MySQLが合計インデックスの代わりにインデックス交差点を使用するのはなぜですか?
-
13-10-2019 - |
質問
時々、奇妙なmysqlの動作に遭遇します。インデックス(タイプ、REL、作成)、(タイプ)、(REL)があると仮定しましょう。このようなクエリのための最良の選択:
SELECT id FROM tbl
WHERE rel = 3 AND type = 3
ORDER BY created;
インデックスを使用することです (type, rel, created)
。しかし、MySQLはインデックスを交差させることにしました (type)
と (rel)
, 、それがより悪いパフォーマンスにつながります。これが例です:
mysql> EXPLAIN
-> SELECT id FROM tbl
-> WHERE rel = 3 AND type = 3
-> ORDER BY created\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tbl
type: index_merge
possible_keys: idx_type,idx_rel,idx_rel_type_created
key: idx_type,idx_rel
key_len: 1,2
ref: NULL
rows: 4343
Extra: Using intersect(idx_type,idx_rel); Using where; Using filesort
そして同じクエリですが、ヒントが追加されています:
mysql> EXPLAIN
-> SELECT id FROM tbl USE INDEX (idx_type_rel_created)
-> WHERE rel = 3 AND type = 3
-> ORDER BY created\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tbl
type: ref
possible_keys: idx_type_rel_created
key: idx_type_rel_created
key_len: 3
ref: const,const
rows: 8906
Extra: Using where
MySQLは、説明コマンドの「行」列に少ない数字を含む実行計画を取ると思います。その観点からは、4343行のインデックス交差点は、8906行の合計インデックスを使用するよりも本当に良く見えます。それで、おそらく問題はそれらの数字の中にあるのでしょうか?
mysql> SELECT COUNT(*) FROM tbl WHERE type=3 AND rel=3;
+----------+
| COUNT(*) |
+----------+
| 3056 |
+----------+
このことから、MySQLは、合計インデックスの概算数の計算と間違っていると結論付けることができます。
それでは、MySQLに適切な実行計画を立てるためにここで何ができますか?
Optimizerのヒントは使用できません。なぜなら、私が見つけた唯一の解決策は、これらの1フィールドインデックスを削除することであるため、Django Ormに固執する必要があるからです。
MySQLバージョンは5.1.49です。
テーブル構造は次のとおりです。
CREATE TABLE tbl (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` tinyint(1) NOT NULL,
`rel` smallint(2) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_type` (`type`),
KEY `idx_rel` (`rel`),
KEY `idx_type_rel_created` (`type`,`rel`,`created`)
) ENGINE=MyISAM;
解決
その理由を正確に伝えるのは難しいです MySQL
選択します index_merge_intersection
インデックススキャンでは、複合インデックスでは、特定の列までの統計が複合インデックスに保存されていることに注意する必要があります。
の値 information_schema.statistics.cardinality
列用 type
コンポジットインデックスの枢機ingが表示されます (rel, type)
, 、 いいえ type
自体。
間に相関がある場合 rel
と type
, 、次にカーディナリティ (rel, type)
枢機inalの産物よりも少なくなります rel
と type
対応する列のインデックスとは別に取得されます。
そのため、行の数が誤って計算されます(交差点のサイズが組合よりも大きくなることはできません)。
禁止することができます index_merge_intersection
それをオフに設定することによって @@optimizer_switch
:
SET optimizer_switch = 'index_merge_intersection=off'
他のヒント
別のことは言及する価値があります:タイプのみのインデックスを削除しても問題はありません。コンポジットインデックスの一部を複製するため、インデックスは必要ありません。