我有一個大型的表(250M行),其中列group_id大致將表分成組(group_id)。它具有以下指標:錯誤的mysql索引選擇
mysql> show indexes from table\G;
*************************** 13. row ***************************
Table: table
Non_unique: 1
Key_name: myindex
Seq_in_index: 1
Column_name: group_id
Collation: A
Cardinality: 181819
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
*************************** 14. row ***************************
Table: table
Non_unique: 1
Key_name: myindex
Seq_in_index: 2
Column_name: id
Collation: A
Cardinality: 213456239
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
我想執行以下查詢:
mysql> explain select * from `table` WHERE (`table`.`type_id` IN (11, 17, 12, 19) AND `table`.`group_id` = 310248) ORDER BY `table`.`id` ASC LIMIT 201\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: table
type: index
possible_keys: [SOME INDEX NAMES]
key: PRIMARY
key_len: 4
ref: NULL
rows: 257386914
Extra: Using where
1 row in set (0.00 sec)
據我所知,這將需要掃描因爲與索引的問題,對於那些......在某些行()。然而,令人驚訝的是,它選擇通過使用主鍵索引掃描儘可能多的行。
下面似乎明確(顯然)優於:
mysql> explain select * from `table` USE INDEX (myindex) WHERE (`table`.`type_id` IN (11, 17, 12, 19) AND `table`.`group_id` = 310248) ORDER BY `table`.`id` ASC LIMIT 201\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: table
type: ref
possible_keys: myindex
key: myindex
key_len: 5
ref: const
rows: 1883760
Extra: Using where
1 row in set (0.00 sec)
使用對LIMIT(2000)大的值,使用GROUP_ID的不同的值,通過除去ORDER併除去TYPE_ID濾波器這一切導致使用索引。我已經運行ANALYZE TABLE。
其值得注意的是,該行的估計是相當高:
mysql> select count(*) from table where group_id=310248 and type_id in (11, 17, 12, 19) ;
+----------+
| count(*) |
+----------+
| 583868 |
+----------+
1 row in set (0.61 sec)
MySQL版本:
版57年1月5日 - rel12.8日誌用於在x86_64 Debian的Linux-GNU((Percona的服務器(GPL),12.8,修訂版233))
爲什麼mysql會選擇一個它認爲會掃描257386914行而不是1883760的計劃?我知道它可能會重複順序讀取,但爲什麼它會選擇2000行的索引,而不是200行?爲什麼要用不同的組ID進行過濾?
編輯:我也嘗試創建索引(group_id,id,type_id),以便所有的排序只能使用索引掃描來完成,但我無法讓它選擇那個索引。
對不起,你說得對,我添加了一個我有問題的樣本。正如我在編輯中注意到的,我曾嘗試在索引中添加type_id。有了hist,我可以在取消前大約10分鐘,並且提示時間<2秒。 – jaklaassen