3

コア2デュオ、8G RAMラップトップで実行されている約400万行の大きなMySQL、MyISAMテーブルがあります。

このテーブルには、varchar、decimal、およびint型を含む30列があります。

varchar(16)にインデックスがあります。この列を「indexed_varchar_column」と呼びましょう。

私の質問は

SELECT 9 columns FROM the_table WHERE indexed_varchar_column = 'something';

クエリを実行する「何か」ごとに、常に約5000行が返されます。

クエリへのEXPLAINはこれを返します:

+----+-------------+-------------+------+----------------------------------------------------+--------------------------------------------+---------+-------+------+-------------+
| id | select_type | table       | type | possible_keys                                      | key                                        | key_len | ref   | rows | Extra       |
+----+-------------+-------------+------+----------------------------------------------------+--------------------------------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | the_table   | ref  | many indexes including indexed_varchar_column      | another_index NOT: indexed_varchar_column! | 19      | const | 5247 | Using where |
+----+-------------+-------------+------+----------------------------------------------------+--------------------------------------------+---------+-------+------+-------------+

まず、another_indexが選択された理由がわかりません。実際には、indexed_varchar_columnと別の2つの列(選択された列の一部を形成する)の複合インデックスであるインデックスを選択します。クエリの2つの列を読み取る必要がないため、処理が少し速くなる可能性があるため、おそらくこれは理にかなっています。本当の質問はのとおりです。

クエリは、一致する「何か」ごとに5秒かかります。2回目に「何か」に対してクエリを実行すると、0.15秒かかります(クエリがキャッシュされているためだと思います)。'something_new'に対して別のクエリを実行すると、再び5秒かかります。だから、それは一貫しています。

問題は次のとおりです。インデックス(indexed_varchar_columnを含む別の複合インデックス)を作成して再度ドロップすると、新しい'something_other'に対する以降のすべてのクエリにかかる時間はわずか0.15秒であることがわかりました。1)インデックスを作成します2)再度ドロップすることに注意してください。したがって、すべてが同じ状態になります。

インデックスの作成と削除に必要なすべての操作により、SQLエンジンが何かをキャッシュして再利用できるようになると思います。この後、クエリでEXPLAINを実行すると、以前とまったく同じになります。

インデックスを操作せずにキャッシュできるように、インデックスの作成と削除の手順で何がキャッシュされているかを理解するにはどうすればよいですか?

アップデート:

mySQLがインデックスを作成するときに内部的にSELECTを実行することを示唆するMarcBからのコメントに続いて、私は次のことを試みました。

SELECT * FROM my_table;

30秒かかり、400万行が返されました。良いことは、それ以降のすべてのクエリが再び非常に高速になることです(システムを再起動するまで)。再起動後、クエリが再び遅くなることに注意してください。これは、mySQLが何らかのOSキャッシングを使用しているためだと思います。

何か案が?推測するテーブルを明示的にキャッシュするにはどうすればよいですか?

更新2: おそらく、このテーブルはひどく断片化されている可能性があることを述べておかなければなりません。400万行ですが、古いフィールドを定期的に削除しています。新しいものも追加します。毎日ID(削除された行)に大きなギャップがあったため、プライマリインデックス(ID)を削除し、連続した番号で再度作成します。その場合、テーブルは非常に断片化される可能性があるため、IOが問題になる可能性があります...どうすればよいかわかりません。

4

3 に答える 3

0

複合インデックスの列の順序は何ですか。

クエリでは、(少なくとも)列の左結合サブセットを使用する必要があります

foo、bar、およびbazにインデックスがある場合、それはテーマ自体によるbarまたはbazに対するインデックスとしては使用できません。(foo)、(foo、bar)、および(foo、bar、baz)のみ。

EXPLAINここにあなたの友達です。クエリで使用されているインデックスがある場合は、それがわかります。

編集これは、比較のための単純な左結合クエリのpostgresの説明です。

Nested Loop Left Join  (cost=0.00..16.97 rows=13 width=103)
    Join Filter: (pagesets.id = pages.pageset_id)
      ->  Index Scan using ix_pages_pageset_id on pages  (cost=0.00..8.51 rows=13 width=80)
              Index Cond: (pageset_id = 515)
      ->  Materialize  (cost=0.00..8.27 rows=1 width=23)
          ->  Index Scan using pagesets_pkey on pagesets  (cost=0.00..8.27 rows=1 width=23)
                Index Cond: (id = 515)
于 2012-09-10T15:07:53.613 に答える
0

indexed_varchar_column を含むインデックスはいくつありますか? indexed_varchar_column だけに単一のインデックスがありますか?

あなたは試しましたか: SELECT 9 columns FROM USE INDEX (name_of_index) the_table WHERE indexed_varchar_column = 'something';

于 2012-09-10T15:22:17.693 に答える
0

助けてくれてありがとう。

最後に、(Marc B のヒントのおかげで) 多くの INSERT と DELETE の後でテーブルがひどく断片化されていることを発見しました。数時間前にこの情報で質問を更新しました。次の 2 つのことが役立ちます。

1)

ALTER TABLE my_table ORDER BY indexed_varchar_column;

2) 実行中:

myisamchk --sort-records=4 my_table.MYI  (where 4 corresponds to my index)

どちらのコマンドも同等だと思います。システムの再起動後でも、クエリは高速です。この ALTER TABLE ORDER BY コマンドを、毎日実行される cron に配置しました。2分かかりますが、それだけの価値があります。

于 2012-09-12T09:21:36.423 に答える