7

ときどき、MySQL の奇妙な動作に遭遇します。インデックス (type、rel、created)、(type)、(rel) があるとします。このようなクエリの最良の選択:

SELECT id FROM tbl
WHERE rel = 3 AND type = 3
ORDER BY created;

index を使用することになります(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 は、EXPLAIN コマンドの「行」列の数が少ない実行計画を採用していると思います。その観点からすると、4343 行のインデックスの交差は、8906 行の結合インデックスを使用するよりも優れているように見えます。では、問題はその数値内にあるのではないでしょうか?

mysql> SELECT COUNT(*) FROM tbl WHERE type=3 AND rel=3;
+----------+
| COUNT(*) |
+----------+
|     3056 |
+----------+

このことから、MySQL は結合インデックスのおおよその行数を計算する際に間違っていると結論付けることができます。

では、MySQL が正しい実行計画を実行できるようにするには、どうすればよいでしょうか?

Django ORM に固執する必要があるため、オプティマイザーのヒントを使用できません。私が見つけた唯一の解決策は、これらの 1 フィールド インデックスを削除することです。

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;
4

2 に答える 2

15

MySQLがインデックス スキャンを選択する理由を正確に説明するのは困難index_merge_intersectionですが、複合インデックスでは、特定の列までの統計が複合インデックス用に格納されることに注意してください。

information_schema.statistics.cardinality複合インデックスの列のの値は、それ自体ではなくtypeのカーディナリティを示します。(rel, type)type

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

行数が正しく計算されないのはそのためです (交差のサイズは和集合よりも大きくすることはできません)。

index_merge_intersectionでオフに設定することで禁止できます@@optimizer_switch

SET optimizer_switch = 'index_merge_intersection=off'
于 2010-12-24T14:02:38.810 に答える
4

言及する価値のあるもう 1 つのこと: タイプのみのインデックスを削除した場合、問題は発生しません。複合インデックスの一部を複製するため、インデックスは必要ありません。

于 2010-12-24T19:38:12.580 に答える