web-dev-qa-db-ja.com

MySQL(InnoDB)テーブルがOPTIMIZE TABLEの後に速くなるのに機能しないのはなぜですか?

私はDjango MySQL InnoDBデータベースにデータを保存するWebアプリケーションを持っています。Django adminで多くアクセスされる特定のページがあり、クエリに時間がかかる(〜20秒)Django internalsであるため、クエリを変更できません。

AB、およびCの3つのテーブルがあります。クエリは次のようになります。

SELECT * 
FROM A 
   INNER JOIN B ON (A.b_id = B.foo) 
   INNER JOIN C ON (B.foo = C.id) 
ORDER BY A.id DESC 
LIMIT 100

単純なjoin-3-tablesを一緒に。

idフィールドは主キーであり、インデックスがあります。 A.b_idB.foo両方に独自のインデックスがあります。

ただし、クエリプランは間違って見え、Bでキーを使用していないと表示されます(ただし、他の結合のキーを使用しています)。 MySQLのパフォーマンスに関する多くのことを読むと、「フォールスルー」する可能性があるさまざまなconst結合であるため、理論的にはインデックスを使用する必要があります。 Bの〜1200行すべてをスキャンする必要があると述べています。

奇妙なことに、私はローカルマシンで1つずつOPTIMIZEedし、クエリを再実行しました(SQL_NO_CACHE)、それは元の20秒に対して0.02秒とはるかに高速でした。同じクエリに対してEXPLAINを実行すると、異なる、はるかに実用的な結果が得られ、それぞれにインデックスを使用できること、および全体をスキャンする必要がないことを示します。同僚は、ほぼ同じデータ(最近、ロードされたダンプファイルから再作成された)を使用して、テストマシン上でそれぞれに対してOPTIMIZEを実行しましたが、速度の向上と理にかなった説明も示しました。

したがって、ライブシステムで実行しましたが、何も変わりませんでした(速度も説明もありません)。 MySQLデータベースを再作成し(DROPed the database and reload from a dump)、今度はOPTIMIZEは何も変更しません(つまり、実行時間〜20秒、クエリプランが正しくありません)。

なぜこれが起こるのですか? MySQLに正しいインデックスを使用させ、0.02秒のクエリ時間を取り戻すにはどうすればよいですか?このブログ投稿( http://www.xaprb.com/blog/2010/02/07/how-often-should-you-use-optimize-table/ )は、OPTIMIZEは主キーのみを最適化します(それだけではありませんb_idfooはプライマリインデックスではありません)。 「セカンダリインデックスを再構築」するにはどうすればよいですか?やってみましたALTER TABLE A ENGINE=InnoDB(BとCも同じ)で、変更はありませんでした。

実際、これを見れば見るほど、MySQLクエリプランが失敗したように見えます。間違ったクエリプランを実行しており、使用できるインデックスを使用していません。 OPTIMIZE TABLEなどを実行した後、正しいインデックスを使用できる場合があります。このような不適切なクエリプランがある場合、ランダムに選択される可能性があるため、マシンによって結果が異なります(私はそう思います)。

3
Rory

OPTIMIZEはテーブルを再構築します。これ(InnoDBの場合)は、断片化と無駄なスペースの一部を排除します。これにより、クエリで顕著な違いが生じることはほとんどありません。

また、OPTIMIZEはANALYZEを実行します。これは統計を変更する可能性があり、それによって別の(より良いまたは悪い)EXPLAINプランにつながります。

ANALYZEはOPTIMIZEよりもはるかに高速(InnoDB上)なので、ANALYZEを実行するだけです。

さまざまな非ANALYZEアクションにより、ANALYZEが実行されます。

ANALYZEはBTreeをランダムにプローブし、統計を収集します。時々、結果の統計は貧弱です。これを防ぐ方法は事実上ありません。長年にわたっていくつかの部分的なハックが作成されました。 5.6.7はANALYZEでこの問題の解消に近づきました。以下がその1つです。 http://dev.mysql.com/doc/refman/5.6/en/innodb-parameters.html#sysvar_innodb_stats_persistent_sample_pages

8
Rick James