今天做了一個MySQL數據庫中的SQL優化。
結論是關聯字段字符集不同,導致索引不可用。
查詢的SQL如下:
select `Alias`.`Grade`, `Alias`.`id`, `Alias`.`Cust_Name`, `Alias`.`Agent_Code1` from `database_name1`.`TAB1` as `Alias` where ( `Alias`.`Agent_Code1` = '1090300496329' and `Alias`.`id` in ( select `database_name1`.`TAB2`.`B` from `database_name1`.`TAB2` join `database_name1`.`TAB3` as `T1` on `T1`.`id` = `database_name1`.`TAB2`.`A` where ( `T1`.`Cust_Type` in ( '1200001', '1200002' ) and `T1`.`id` in ( select `database_name1`.`TAB4`.`B` from `database_name1`.`TAB4` join `database_name1`.`TAB5` as `T2` on `T2`.`id` = `database_name1`.`TAB4`.`A` where `T2`.`Cont_Meth_Tp_Cd` = '1220001' ) ) ) ) order by `Alias`.`Cust_Name` asc, `Alias`.`id` asc limit 11 offset 0
SQL的執行計划如下 :
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: Alias partitions: NULL type: ref possible_keys: PRIMARY key_len: 203 ref: const rows: 894 filtered: 100.00 Extra: Using index condition *************************** 2. row *************************** id: 1 select_type: SIMPLE table: TAB2 partitions: NULL type: ref possible_keys: TAB2_IDX key: TAB2_IDX key_len: 103 ref: database_name1.Alias.id rows: 1 filtered: 100.00 Extra: Using where; Using index *************************** 3. row *************************** id: 1 select_type: SIMPLE table: HDL_ADD_CUSTOMER_Alias partitions: NULL type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 77 ref: func rows: 1 filtered: 55.42 Extra: Using where *************************** 4. row *************************** id: 1 select_type: SIMPLE table: TAB4 partitions: NULL type: index possible_keys: NULL key: TAB4_IDX key_len: 206 ref: NULL rows: 5852807 filtered: 100.00 Extra: Using where; Using index *************************** 5. row *************************** id: 1 select_type: SIMPLE table: T2 partitions: NULL type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 142 ref: database_name1.TAB5.A rows: 1 filtered: 50.00 Extra: Using where; FirstMatch(Alias) 5 rows in set, 1 warning (0.01 sec)
由於對MySQL執行計划不熟,看了半天也沒看出有啥問題。
但是第4行有一個地方引起我的注意了,possible_keys = NULL ,key = TAB4_IDX
字面理解:可能走的索引沒有,實際上走了索引。
實際上是沒有走索引范圍掃描。后來從MySQL Wordbench 的執行計划里找到了端倪。
在TAB4表上的關聯字段ID發生了隱式轉換,這個字段的字符集是 gbk的, 而t2.id 字符集是utf8 的;
結果導致轉換后,tab4上的索引沒法使用。發生了 block nested loops;
從索引中讀所有數據到內存。 index full scan ;
確認這段時間可以更新,把ID字段字符集都改成一致即可。
ALTER TABLE `database_name1`.`tab3` CHANGE COLUMN `id` `id` VARCHAR(25) CHARACTER SET 'gb18030' NOT NULL ;