引言
2021年春節後的某個忙(mo)碌(yu)的下午,旁邊的劉哥(老江湖,從業5年+)突然發出了一聲嘆息:“哎,mysql 出bug了,有索引不走”。
作爲一個熱心的人,我立即說到:“是不是,對索引字段做了函數操作”。
劉哥沉思了2秒,略有玩味的小眼神看了看我,慢慢說道:“溫兄,常規的情況,對索引字段做函數操作,或者 字符串與數字比較造成的隱式轉換,這次的SQL都不涉及”。
我一聽頓時來了興趣,略帶興奮的跟劉哥說:“劉哥,您發SQL,我也研究下”。
劉哥略有無奈的看了看我後,依舊把SQL發給了我:
SELECT * FROM oc_order oo join orders_detail od ON oo.order_id =od.order_id
不過須臾(近20分鐘),我便查明瞭原因,裝作大師的模樣,一字一句的說到:”這是,字符集隱式轉換問題”
劉哥聽後,百度了下,直拍大腿,“對對,怎麼把這個給忘了”。
定位問題
1.首先執行explain,查看執行計劃
explain
SELECT * FROM oc_order oo join orders_detail od ON oo.order_id =od.order_id
確實被驅動表orders_detail 沒走索引
第一個表就是驅動表,後邊的都是被驅動表,會從驅動板取出數據作爲參數,到被驅動表查詢匹配的記錄。
--- 非專業術語,溫安適 20210223
2. 查看被驅動表的索引
SHOW INDEX FROM test.orders_detail;
3.查看字段字符集
SELECT COLUMN_NAME,character_set_name,collation_name FROM INformation_schema.`COLUMNS` WHERE TABLE_NAME='oc_order' AND COLUMN_NAME='order_id';
SELECT COLUMN_NAME,character_set_name,collation_name FROM INformation_schema.`COLUMNS` WHERE TABLE_NAME='orders_detail'AND COLUMN_NAME='order_id';
Mysql字符集說明
utf8m4是utf8超集,utf8,與utf8mb4會比較,utf8會轉換爲utf8mb4.
驗證
調整SQL語句,將oc_orders的order_id強制轉換爲utf8。
explain
SELECT * FROM oc_order oo join orders_detail od ON convert(oo.order_id USING UTF8) =od.order_id
查看執行計劃,確實走了索引
解決方式
調整SQL語句
SELECT * FROM oc_order oo join orders_detail od ON convert(oo.order_id USING UTF8) =od.order_id
調整字符集一致,建議
總結
可能不走索引的3種情況
- 對索引字段做函數操作
- 隱式類型轉換,字符串與數字比較,字符串會轉換爲數字
- 隱式字符集轉換,utf8m4是utf8超集,utf8,與utf8mb4會比較,utf8會轉換爲utf8mb4.