これは、最近仕事で出てきたシナリオです。
A、B、Cの3つのテーブルについて考えてみます。
Aには3,000行あります。Bには300,000,000行あります。Cには2,000行あります。
外部キーが定義されています:B(a_id)、B(c_id)。
次のようなクエリがあるとします。
select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id
私の経験では、この場合、MySQLはC-> B-> Aを選択する可能性があります。CはAよりも小さく、Bは巨大で、すべて等結合です。
問題は、MySQLが(C.idとB.c_id)と(A.idとB.a_id)の共通部分のサイズを必ずしも考慮していないことです。BとCの間の結合がBと同じ数の行を返す場合、それは非常に不適切な選択です。Aから始めて、BをAと同じ数の行にフィルター処理する場合は、はるかに適切な選択でした。straight_join
このようにこの順序を強制するために使用できます:
select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id
のa
前に参加する必要がありますb
。
通常、結果のセットの行数が最小になる順序で結合を実行する必要があります。したがって、小さなテーブルから始めて、結果の結合も小さくなるように結合するのが理想的です。小さなテーブルから始めて、それを大きなテーブルに結合すると、大きなテーブルと同じ大きさになると、物事は洋ナシ型になります。
ただし、統計に依存します。データの分布が変わると、計算が変わる可能性があります。また、結合メカニズムの実装の詳細にも依存します。
MySQLで見た最悪のケースは、必須straight_join
または積極的なインデックスヒントを除いて、ライトフィルタリングを使用して厳密な並べ替え順序で大量のデータをページ分割するクエリです。MySQLは、ソートよりもフィルターと結合にインデックスを使用することを強く好みます。ほとんどの人はデータベース全体を並べ替えようとしているのではなく、クエリに応答する行のサブセットが限られているため、これは理にかなっています。限られたサブセットの並べ替えは、並べ替えられているかどうかに関係なく、テーブル全体をフィルタリングするよりもはるかに高速です。そうではありません。この場合、インデックス付きの列があるテーブルの直後に直接結合を配置して、固定されたもので並べ替えたいと思いました。
straight_join
。