MySQL結合ステートメントの詳細な実行プロセス

バックグラウンド

今日、結合関連チェック用のステートメントと、結合用に最適化する必要のあるステートメントを最適化したので、彼の実行プロセスの1つを理解する必要があります。ことわざにあるように、自分と敵を知って、すべての戦いに勝利してください!

結合クエリアルゴリズム

1.単純な入れ子ループ結合(単純な入れ子ループ結合)

  • 単純なネストループアルゴリズムのクエリプロセスは、ネストされたクエリです。結合を使用すると、mysqlオプティマイザがインデックス自体を選択するため、この関連するクエリステートメントは、最初はどちらが駆動テーブルであるかを判別できません(これは、DBAが許可しない場合にも当てはまります)結合クエリの理由の1つ)。aおよびbフィールドがインデックス付けされていない場合、このアルゴリズムクエリが表示されます。
  • クエリプロセス:最初にt1テーブルで修飾フィールドaを見つけ、次にt2テーブルをトラバースしてループをトラバースします。(ただし、このアルゴリズムはmysqlでは使用されません)
    ここに画像の説明を挿入
select * from  t1 join t2  on t1.a = t2.b

2.インデックスの入れ子ループ結合(インデックスの入れ子ループ結合)

  • Straight_joinの使用は、t1が駆動テーブルであり、t2が駆動テーブルであることを明確に示していることを意味します。
  • クエリプロセス:t1からデータの一部を取得し、インデックスbを使用してt2から一致させます。bがカバーするインデックスであり、必要なフィールドが含まれている場合、テーブルに戻るクエリを実行する必要はありませんが、これらのフィールドに含まれていない場合すべて、それから再びテーブルに戻るクエリを実行する必要があります。駆動テーブルのフィールドにインデックスが付けられている場合、クエリアルゴリズムは同じですか?実際、駆動テーブルが最初にインデックスをチェックし、次に駆動テーブルをスキャンすることを除いて、同じことが当てはまります。
  • では、上記の2つの状況で駆動テーブルをどのように選択すればよいでしょうか?インデックス付きテーブルではなく、インデックス付きテーブルについてはどうでしょうか?私は個人的には、これは必ずしもそうではないと思います。テーブルがクエリ条件としてのみ使用され、テーブルフィールドではなく、このテーブルに関連フィールドのインデックスがある場合
    ここに画像の説明を挿入
select * from  t1 straight_join t2  on t1.a = t2.b(t2中的表字段有索引)

3.ブロックネストループ結合(キャッシュブロックネストループ結合)

  • MySQlでは、前述の単純な入れ子ループ結合アルゴリズムは使用されません。2つのテーブルの関連フィールドにインデックスが作成されていない場合、mysqlはどのように処理しますか?つまり、ブロックネストループ結合アルゴリズムを使用します。

  • クエリプロセス:テーブルt1のデータをスレッドメモリのjoin_bufferに読み込みます。このステートメントではselect *を書き込んでいるため、テーブルt1全体をメモリに入れ、テーブルt2をスキャンして、テーブルt2の各行を取り出します。 、join_bufferのデータと比較し、結果セットの一部として結合条件を満たすものを返します。
    ここに画像の説明を挿入

  • ただし、このジョインバッファのサイズには制限があります。ジョインバッファがいっぱいで、クエリを一度に完了できない場合、戦略は複数のクエリを実行することです

    1. テーブルt1をスキャンし、データ行を順番に読み取ってjoin_bufferに入れます。join_bufferを行88に置いた後、手順2に進みます。
    2. テーブルt2をスキャンし、t2の各行を取り出して、それをjoin_bufferのデータと比較します。結合条件が満たされると、結果セットの一部として返され、join_bufferがクリアされます。
    3. テーブルt1のスキャンを続行し、最後の12行のデータをjoin_bufferに順次読み取り、ステップ2に進みます。
    4. このようにして、ループは最後の結果セットを取得して返します。

4.バッチキーアクセス

  • NLJアルゴリズムは、最初にデータの行をドリブンテーブルから読み取り、次にドリブンテーブルに移動してデータを照合します。ただし、2つのテーブルのデータ量が多すぎると、パフォーマンスの問題が発生します。データベースのアルゴリズム最適化にはMRR最適化があります。基本的な考え方は、順次読み取りを実行することです。この順次読み取りの理由は、mysqlインデックスの格納方法がデータページの形式であるためです。各データページのサイズは16kbであり、計算できます保存できるデータの量。シーケンシャルに読み取ると、データページ間の切り替えが少なくなります。つまり、IO操作の削減です。ディスクに複数回アクセスする必要がないため、効率が大幅に向上します。それにより、NLJがシーケンシャルに読み取り、バッチマッチングを実行できるようになります。これはすぐに離陸しませんか?
  • このとき、BKAアルゴリズムが登場しました。このアルゴリズムは、5.7以降のデータベースバージョンに登場しました。これは、BNLアルゴリズムの最適化バージョンです。クエリプロセスでは、ドライブテーブルのデータをバッチで読み取り、それをバッファーに格納してから、バッチマッチングを実行します(これは関連付けられたIDがソートされます)、次にバッチマッチングクエリを実行します。

4.ドライブテーブルの選択

  • 上記の3つの結合アルゴリズムを効率的に使用するには、駆動テーブルの選択が必要です。
  • Index Nested-Loop Joinアルゴリズムの場合は、小さなテーブルを駆動テーブルとして選択する必要があります。BlockNested-Loop Joinアルゴリズムの場合:join_buffer_sizeが十分に大きい場合も同じです; join_buffer_sizeが十分に大きくない場合(この状況はより一般的です) 、小さなテーブルを駆動テーブルとして選択する必要があります。
  • したがって、従うべき一般的なルールは、駆動テーブルとして小さなテーブルを選択することです。ここでの小さなテーブルは、データボリュームが小さいテーブルではなく、where条件が実行された後の結合バッファー内のデータボリュームが小さいテーブルを指します。

5.毎日の使用

  • 実際、通常の関連クエリでは、通常、主キーインデックスを使用して別のテーブルの一意のインデックスを関連付けます。そのため、使用される関連クエリにはインデックスが付けられるため、それらのほとんどはIndex Nested-Loopを使用します参加(バージョン5.6より前)またはBKA。したがって、通常の最適化では、主にwhere条件に基づいています。テーブルの関連付けでパフォーマンスが浪費されるわけではありません。駆動テーブルにクエリを実行する場合、大きな部分を直接除外し、主キーIDに基づいて直接チェックします。結合のパフォーマンスが低下することはありますか?したがって、通常の最適化は主にテーブルの選択を促進し、テーブルのクエリパフォーマンスを向上させることです。ドライブテーブルには小さなテーブルを選択し、ドライブテーブルのインデックスは可能な限り適切です。

総括する

  1. 4つのアルゴリズムのおおよそのクエリプロセスについて話しました
  2. mysql 3クエリアルゴリズム、インデックスBKA(結合バッファー)NLJ、インデックスBLN(結合バッファー)なし
  3. 駆動テーブルの選択、小さな駆動テーブルの選択(少量のデータでジョインバッファーに参加)
  4. 結合SQLの毎日の最適化は、主にテーブルの選択とテーブルインデックスの最適化を推進することです

おすすめ

転載: blog.csdn.net/weixin_40413961/article/details/108719849