為什麼這個查詢慢,看起來很簡單
我的應用程序有一個非常典型的使用者資訊表,其中包含一組平均列(ints、varchars 等)。
此表中有兩個 varchar(100) 欄位:emailAddress 和 emailAddress2。
我非常困惑為什麼我的一個查詢如此緩慢(5 秒以上),而在測試一些替代項時它們如此之快(<= 0.02 秒)。
這個查詢很快(匹配 emailAddress 欄位):
SELECT u.userId FROM user AS u WHERE u.isActive=1 AND u.emailAddress = 'user@domain.com'
這個查詢也很快(匹配 emailAddress2 欄位):
SELECT u.userId FROM user AS u WHERE u.isActive=1 AND u.emailAddress2 = 'user@domain.com'
此查詢速度不快(匹配 emailAddress 或 emailAddress2 欄位):
SELECT u.userId FROM user AS u WHERE u.isActive=1 AND (u.emailAddress = 'user@domain.com' OR u.emailAddress2 = 'user@domain.com')
我有 2 個索引,每個索引位於 emailAddress 和 emailAddress2 欄位上。
(編輯)這是解釋輸出:
id 1 select_type SIMPLE table u type ref possible_keys active,emailAddress,emailAddress2 key active key_len 1 ref const rows 166808 Extra Using where
知道為什麼上面的第三個查詢這麼慢嗎?建議以另一種方式進行?我需要在少數幾個欄位上進行匹配,然後獲取所有使用者,除了他們的電子郵件地址在 emailAddress 或 emailAddress2 中的使用者(上面的查詢已針對我的文章進行了簡化)。
這真讓我抓狂!(並對我的應用程序的性能產生負面影響)。
謝謝
查詢很慢,因為首先,這個查詢有一個
OR
不能用單個索引優化的條件(而只有AND
can 的條件),其次,因為除了電子郵件之外,它還必須檢查isActive=1
條件。所以它更喜歡做一個表掃描。另一種可能的路徑是將兩個電子郵件索引與索引合併聯合訪問算法一起使用,但由於某種原因優化器沒有選擇此計劃。一種解決方案是更改您擁有的兩個索引,
isActive
在末尾附加列:ALTER TABLE user DROP INDEX the_name_of_the existing_index, DROP INDEX the_name_of_the_other_index, ADD INDEX emailAddress_isActive_IX (emailAddress, isActive), ADD INDEX emailAddress2_isActive_IX (emailAddress2, isActive) ;
如果它仍然很慢(和/或不進行索引合併但更喜歡表掃描),您可以嘗試使用以下命令重寫查詢
UNION
:SELECT u.userId FROM user AS u WHERE u.isActive=1 AND u.emailAddress = 'user@domain.com' UNION SELECT u.userId FROM user AS u WHERE u.isActive=1 AND u.emailAddress2 = 'user@domain.com' ;
另一種選擇 - 不必添加/更改索引 - 是將查詢嵌套到 2 層中,僅將電子郵件條件保留在內部層中,實質上迫使 MySQL 考慮將索引合併與兩個可用索引一起使用:
SELECT userId FROM ( SELECT userId, isActive FROM user AS u WHERE emailAddress = 'user@domain.com' OR emailAddress2 = 'user@domain.com' ) x WHERE isActive=1 ;