4

A、B、C という3innodbつのテーブルがあります。これら 3 つのテーブルを結合して結果を生成するクエリがあります。

SELECT A.a, B.b, C.c
from A 
join B on A.id = B.a_id 
join C on C.id = B.c_id
where A.a = 'example' and B.b < 10;

最初に「EXPLAIN」コマンドを使用してクエリをテストしていたとき、次の順序が得られました。

B -- C -- A

ただし、これは最適ではありません。したがって、すべてのテーブルに対して「ANALYZE TABLE」を実行すると、次のようになります。

A -- B -- C

、これは正しい順序だと思います。

次に、SQL を本番環境にデプロイしましたが、理由もなく、1 か月後、実行計画は B--C--A という不適切なオプションに戻りました。その後、何度かANALYZE TABLE実行を試みましたが、今回は結果がわかりにくいです。B--C--A が表示されることもあれば、A--B--C が表示されることもあれば、他の実行計画が表示されることもあります。

だから私の質問は:

  1. 展開後に実行計画が変更されるのはなぜですか?
  2. 実行計画を固定する以外に (データが更新されて急速に変化するため、最適な計画は将来変更される可能性があります)、最適な計画が常に保証されることを保証する方法はありますか?
4

1 に答える 1

6

オプティマイザは、テーブルのサイズ、カーディナリティ、値の分布、インデックスなどに関するインメモリ統計に基づいて、テーブルの並べ替えとインデックスの使用について選択を行います。これらの統計は推定値であり、常に完全に正確というわけではありません。

InnoDB はその統計を時々更新します。これは、ANALZYE TABLE を実行したときに発生させることができるものです。

それでも、メモリ内の統計情報がオプティマイザーに別の選択をさせる直前にある場合があるため、このフリップフロップ動作が見られます。

クエリでインデックス ヒントを指定することにより、インデックスを選択するためのオプティマイザーの既定のアルゴリズムをオーバーライドできます。

を指定すると、オプティマイザのデフォルトのテーブルの並べ替えアルゴリズムをオーバーライドできますSTRAIGHT_JOIN。これは、FROM 句で指定した順序でテーブルを読み取り、並べ替えないことを意味します。

STRAIGHT_JOIN をクエリ修飾子として使用できます (DISTINCT など)。SELECT の直後に置きます。

SELECT STRAIGHT_JOIN A.a, B.b, C.c
from A 
join B on A.id = B.a_id 
join C on C.id = B.c_id
where A.a = 'example' and B.b < 10;

ただし、インデックス ヒントや結合ヒントを過度に使用しないように注意してください。オプティマイザーは、データのサイズと分布がほんの少し変化した後、来週、フリップフロップ動作を回避する可能性があります。コードにオーバーライドが多すぎると、オプティマイザが適切に機能しなくなる可能性があります。

于 2013-01-30T23:51:41.883 に答える