前言
本文介紹三種因為函式轉換導致不使用索引的問題,注意,不使用索引指的是不使用樹搜索,而是全表掃描索引樹,
顯式使用函式
比如 select count(*) from tradelog where month(t_modified)=7;,在 t_modified 欄位上建立了普通索引,
索引對于 t_modified 是有序的,但是對于 month(t_modified) 不是有序的,所以優化器規定,當遇到使用函式對欄位進行操作后,不會使用樹搜索,而是全表掃描,這里因為只查詢符合條件的行數,并且 t_modified 索引樹比主鍵索引樹小,所以使用了索引覆寫,
型別轉換
比如 select * from tradelog where tradeid=110717;,其中,tradeid 欄位是 varchar 型別,
因為 tradeid 和 110717 兩個型別不一致,所以需要型別轉換,那是轉換成字串呢還是數字呢?
一個簡單的判斷方法是,執行 select 9 < '10';,如果回傳 1,說明轉換成數字,否則轉換成字串,
于是,這條陳述句等價于 select * from tradelog where CASE(tradeid AS signed int)=110717;,也不能使用樹搜索,盡管 tradeid 欄位有索引,
不過,對于 select * from t where id = '1'; ,會使用主鍵索引,因為等價于 select * from t where id = CAST('1' AS signed int);
編碼轉換
比如 select * from trade_detail where tradeid=$L2.tradeid.value;,其中 tradeid 是 utf8 編碼,而 $L2.tradeid.value 是 utf8mb64 編碼,
因為 utf8mb64 是 utf8 的超集,所以查詢時需要將 tradeid 欄位編碼轉換成 utf8mb64,
如果要優化這個場景,在線上資料量不大且可以做這個 DDL 時,可以將 trade_detail 表的 tradeid 欄位設為 utf8mb64 編碼,如果不能做這個 DDL 操作,可以采用 select * from trade_detail where CONVERT(tradeid USING utf8)=$L2.tradeid.value;
總結
在遇到顯式或者隱式使用函式應用欄位時,優化器將不會選擇索引,而是采用全表掃描的方式,并且,對于像 where id+1=1000 的運算式同樣不會采用索引,寫成 where id = 1000-1 就可以,這里感覺優化器偷懶了,
參考
- [1] 為什么這些SQL陳述句邏輯相同,性能卻差異巨大
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/301418.html
標籤:其他
下一篇:MySQL45講之查詢慢或者阻塞
