詳解MySQL數據庫常見的索引問題:無索引,隱式轉換,附實例說明
概述
在這些年的工作之中,由于SQL問題導致的數據庫故障層出不窮,而索引問題是SQL問題中出現頻率最高的,常見的索引問題包括:無索引,隱式轉換。
索引問題
1、無索引
當數據庫中出現訪問表的SQL無索引導致全表掃描,如果表的數據量很大,掃描大量的數據,應用請求變慢占用數據庫連接,連接堆積很快達到數據庫的最大連接數設置,新的應用請求將會被拒絕導致故障發生。
2、隱式轉換
隱式轉換是指SQL查詢條件中的傳入值與對應字段的數據定義不一致導致索引無法使用。常見隱士轉換如字段的表結構定義為字符類型,但SQL傳入值為數字;或者是字段定義collation為區分大小寫,在多表關聯的場景下,其表的關聯字段大小寫敏感定義各不相同。隱式轉換會導致索引無法使用,進而出現上述慢SQL堆積數據庫連接數跑滿的情況。
無索引實例
表結構:

執行計劃:

從上面的SQL看到執行計劃中ALL,代表了這條SQL執行計劃是全表掃描,每次執行需要掃描707250行數據,這是非常消耗性能的,該如何進行優化?添加索引。
驗證mo字段的過濾性:

可以看到mo字段的過濾性是非常高的,進一步驗證可以通過select count(*) as all_count,count(distinct mo) as distinct_cnt from user,通對比 all_count和distinct_cnt這兩個值進行對比,如果all_cnt和distinct_cnt相差甚多,則在mo字段上添加索引是非常有效的。
添加索引
- mysql> alter table user add index ind_mo(mo);
- mysql>SELECT uid FROM `user` WHERE mo=13772556391 LIMIT 0,1;
執行計劃:

隱式轉換
表結構:

執行計劃:
- mysql> explain extended select uid from`user` where mo=13772556391 limit 0,1;
- mysql> show warnings;
- Warning1:Cannot use index 'ind_mo' due to type or collation conversion on field 'mo'
- Note:select `user`.`uid` AS `uid` from `user` where (`user`.`mo` = 13772556391) limit 0,1
如何解決:

上述案例中由于表結構定義mo字段后字符串數據類型,而應用傳入的則是數字,進而導致了隱式轉換,索引無法使用,所以有兩種方案:
第一,將表結構mo修改為數字數據類型。
第二,修改應用將應用中傳入的字符類型改為數據類型。
總結
在使用索引時,我們可以通過explain+extended查看SQL的執行計劃,判斷是否使用了索引以及發生了隱式轉換。
由于常見的隱式轉換是由字段數據類型以及collation定義不當導致,因此我們在設計開發階段,要避免數據庫字段定義,避免出現隱式轉換。