1

私が次のテーブルを持っているとしましょう(それを呼びましょうmy_table):

CREATE TABLE `my_table` (
  `table_id` int(10) unsigned NOT NULL auto_increment,
  `my_field` int(10) unsigned NOT NULL default '0'
   PRIMARY KEY  (`table_id`),
   KEY `my_field` (`my_field`,`table_id`)
 ) ENGINE=MyISAM

の主キーmy_tabletable_id(auto_increment)であり、とのキーもmy_fieldありtable_idます。

このクエリをテストすると...

EXPLAIN SELECT * FROM my_table
WHERE my_field = 28
ORDER BY table_id DESC;

...私は得る:

idselect_typeテーブルタイプpossible_keyskeykey_len ref rows Extra
--- ----------- -------- ---- ------------- -------- --- ---- ----- ---- -----
1 SIMPLE my_table ref my_field my_field 8 const 36

正しいキー()を使用していることがわかりますmy_field

しかし、これを試してみると...

EXPLAIN SELECT * FROM my_table
WHERE my_field IN (1, 28, 20)
ORDER BY table_id DESC;

...私は得る:

idselect_typeテーブルタイプpossible_keyskeykey_len ref rows Extra
--- ----------- -------- ---- ------------- ------ ----- -------- ---- ---------------------------
1 SIMPLE my_table ALL my_field(NULL)(NULL)(NULL)406ここでの使用; filesortの使用

キーをまったく使用していないことがわかります。さらに悪いことに、filesortを使用していることがわかります。

" FORCE INDEX (my_field)"を実行しても、ファイルソートは実行されます。

ファイルソートを回避する方法はありますか?

4

4 に答える 4

14

MySQLはこのクエリを並べ替えるためにインデックスを使用できないことを理解しています。

MySQLは、クエリと同じ方法でソートされた場合にのみインデックスを使用できます。あなたの記録(table_id,my_field)

(1,1), (2,28), (3,14), (4,20)

のインデックス(my_field,table_id)は次のように保存されます

(1,1), (14,3), (20,4), (28,2)

INの例からクエリを実行すると(簡単にするために、ORDER BYは昇順であると言います)、MySQLは次のように検出します。

(1,1), (20,4), (28,2)

...この順序で。何があっても、それらをに分類する必要があります(1,1),(28,2),(20,4)。それがファイルソートです。そのため、MySQLは、クエリがあった場合、ORDER BY my_fieldまたはORDER BY my_field, table_idインデックスがすでにこの順序になっているためにのみ、そのインデックスを使用できました。また、 ASCとDESCを混在させた場合、[現在、将来のバージョンでは複合インデックスを混合順序で並べ替えることができるようになる可能性があります]インデックスを使用できないのもそのためです。インデックスはASC、ASCでソートされており、どちらの方法で読んでも、正しい順序にはなりません。

「filesort」には何の問題もないことに注意してください。これは、クエリの通常の実行の一部です。実際にはファイルも使用しないため、非常に高速である必要があります。

何千もの行を並べ替える必要がある場合、特に各行が本当に大きい場合(多くのフィールド、BLOBなど)、小さな派生テーブルを使用すると、より良い結果が得られる可能性があります。

  SELECT t.*
    FROM (
          SELECT table_id FROM my_table WHERE my_field IN (1, 28, 20)
         ) tmp
    JOIN my_table t USING (table_id)
ORDER BY t.table_id DESC

ファイルソートを派生テーブルと交換します。場合によっては、パフォーマンスが大幅に向上することもあれば、わずかに低下することもあります。YMMV

于 2009-09-17T20:29:55.597 に答える
1

まず、SQLではキーが逆方向にあると思います。主キーを使用したくないですtable_idか?

これはおそらくあなたが望むものです:

CREATE TABLE `my_table` (
  `table_id` int(10) unsigned NOT NULL auto_increment,
  `my_field` int(10) unsigned NOT NULL default '0'
   PRIMARY KEY  (`table_id`),
   INDEX `my_index` (`my_field`)
 ) ENGINE=MyISAM
于 2009-09-17T19:32:02.607 に答える
1

クエリに誤った「=」記号があります。次のように削除します。

EXPLAIN SELECT * FROM my_table
WHERE my_field IN (1, 28, 20)
ORDER BY table_id DESC;
于 2009-09-17T19:42:50.137 に答える
1

との両方にmy_field基づくキーであるため、キーは使用されません。単独に基づいてクエリを実行している場合は、排他的にインデックスを作成する必要があります。table_idmy_fieldmy_fieldmy_field

複数の列に単一のキーがあるからといって、いずれかの列で検索した場合にそのキーが使用されるわけではありません。特定のキーは、クエリ内のすべての検索列もキーに含まれている場合にのみ使用されます。

于 2009-09-17T19:43:41.280 に答える