MySQLが合計インデックスの代わりにインデックス交差点を使用するのはなぜですか?

StackOverflow https://stackoverflow.com/questions/4526686

質問

時々、奇妙な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 自体。

間に相関がある場合 reltype, 、次にカーディナリティ (rel, type) 枢機inalの産物よりも少なくなります reltype 対応する列のインデックスとは別に取得されます。

そのため、行の数が誤って計算されます(交差点のサイズが組合よりも大きくなることはできません)。

禁止することができます index_merge_intersection それをオフに設定することによって @@optimizer_switch:

SET optimizer_switch = 'index_merge_intersection=off'

他のヒント

別のことは言及する価値があります:タイプのみのインデックスを削除しても問題はありません。コンポジットインデックスの一部を複製するため、インデックスは必要ありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top