Mysql

對兩個索引列使用“OR”不使用索引

  • October 24, 2016

在下面的查詢中,fromtidreplies表的索引。

SELECT * FROM `replies`
WHERE `from`="<userId>"
OR `tid` IN (SELECT `tid` FROM `posts` WHERE `from`="<userId>")

通過使用“OR”,它似乎進行了全表掃描(約 300 萬行)。EXPLAIN說可能的密鑰是,from但它不使用任何密鑰。

但是,在下面的查詢中,frid_lt並被frid_gt索引。這兩列在一個複雜的索引中(frid_lt,frid_gt),但frid_gt也有自己的索引。

SELECT `mid` FROM `messages`
WHERE `frid_lt`="<userId>" OR `frid_gt`="<userId>"

這個查詢確實使用了兩個索引。上面寫著“ EXPLAINindex_merge”和“使用 sort_union(frid_lt,frid_gt); 使用 where”。

**為什麼第一個查詢不使用索引合併?

我可以做任何改進以使引擎也使用索引合併嗎?**

OR沒有優化好。一個常見的解決方法是使用UNION

( SELECT * FROM replies WHERE `from` = "..." )
UNION ALL   -- or UNION DISTINCT if you know there are no dups
( SELECT r.* FROM replies AS r
   JOIN posts AS p  ON p.tid = r.tid
   WHERE p.from = "..." )

請注意,我還避免了通常效率低下的IN ( SELECT ... )

為了進一步提高性能,請使用以下索引:

replies:  INDEX(`from`)
posts:    INDEX(`from`, tid)  -- in this order
replies:  INDEX(tid)

(請注意,這PRIMARY KEY 一個索引,所以不要添加冗餘索引。)

在您的第二個範例中,您遇到的“索引合併”可能會也可能不會比UNION.

哦,這是一個更新

要優化UPDATE,請做兩個單獨的UPDATEs(不UNION,不OR)。一本正經地檢查from。另一個是類似於上面第二個選擇的“多表更新”(參見手冊)。

引用自:https://dba.stackexchange.com/questions/153117