今日、mysqlテーブル接続を照会したときに、非常に良いと感じる結合深度分析に関する記事を見つけ、説明があります。ここでそれを共有します。
参加入門
マルチテーブルジョイントクエリには、内部結合、外部結合、右結合、左結合、および自然結合があります。
デカルト製品CROSSJOIN
デカルト積は、Aテーブルの各レコードとBテーブルの各レコードを一緒に強制することです。したがって、テーブルAにn個のレコードがあり、テーブルBにm個のレコードがある場合、デカルト積の結果はn * mレコードを生成します。
内部接続INNER JOIN
INNER JOIN、WHERE(同等の結合)、STRAIGHT_JOIN、JOIN(INNERは省略)の4つの記述方法があります。
内部結合は、最も一般的に使用される結合操作です。数学的な観点からは、2つのテーブルの共通部分を見つけることです。デカルト積の観点からは、デカルト積からONワードのレコードを選択することです。
左接続LEFT JOIN
2つのテーブルの共通部分と、左側のテーブルの残りのデータ。デカルト積の観点から、最初にON句の条件が満たされるレコードをデカルト積から選択し、次に残りのレコードを左側のテーブルに追加します。
正しい接続RIGHT JOIN
2つのテーブルの共通部分と、右側のテーブルの残りのデータ。デカルト積の観点から、最初にON句の条件が満たされるレコードをデカルト積から選択し、次に残りのレコードを右側のテーブルに追加します。
外部結合OUTER JOIN
外部結合は、2つのセットの和集合を見つけることです。デカルト積の観点からは、デカルト積からON句の条件が満たされるレコードを選択し、左側のテーブルに残りのレコードを追加し、最後に右側のテーブルに残りのレコードを追加します。
MYSQLはOUTERJOINをサポートしていませんが、左結合と右結合の結果に対するUNION操作によって実装できます。
USING句
スキーマ設計で結合テーブルの列に同じ命名スタイルを使用する場合、USING構文を使用してON構文を簡略化できます。形式はUSING(column_name)です。
自然に参加する
自然接続は、USING句の簡略化されたバージョンであり、接続する接続条件として2つのテーブルで同じ列を検索します。左の自然なつながり、右の自然なつながり、そして通常の自然なつながりがあります。
参加原則
NLJ(ネストされたループ結合、ネストされたループアルゴリズム)
Table1はテーブルを駆動し、table2はテーブルを駆動します。駆動テーブルは、接続操作のために被駆動テーブルを駆動します。
- ドライバテーブルをロードし、ドライバテーブルから最初のレコードを見つけます。
- 被駆動テーブルをロードし、被駆動テーブルを最初からスキャンし、被駆動テーブルの最初のレコードと1つずつ一致するレコードを見つけてから、それらを接続して結果テーブルにレコードを形成します。
- 被駆動テーブルによって検索された後、被駆動テーブルから2番目のレコードを取得します。次に、ドリブンテーブルを再度ロードし、ドリブンテーブルを最初からスキャンし、ドライブテーブルの2番目のレコードに一致するレコードを1つずつ見つけ、それらを接続して結果テーブルにレコードを形成します。
- ドライブテーブルのすべてのレコードが処理されるまで、上記の操作を繰り返します。これは、ネストされたループ接続アルゴリズムの基本的な考え方です。一度に1つの行だけが内側のループに渡されるため、メモリループは、外側のループ(結果セット)の行数と同じ回数実行する必要があります。
表t1、t2、t3の接続タイプ:
Table Join Type
t1 range
t2 ref
t3 ALL
実際の処理:
for each row in t1 matching range {
for each row in t2 matching reference key {
for each row in t3 {
if row satisfies join conditions, send to client
}
}
}
BNLJ(ネストされたループ結合のブロック、ネストされたループのブロックアルゴリズム)アルゴリズム
NLJの最適化。一般的な考え方は、ドライブテーブルから一度に複数のレコードをフェッチするためのバッファ領域を作成することです。
外側のループの行/結果セットを結合バッファーに格納し、内側のループの各行をバッファー全体のレコードと比較して、内側のループの数を減らします。
実際の処理:
for each row in t1 matching range {
for each row in t2 matching reference key {
store used columns from t1, t2 in join buffer
if buffer is full {
for each row in t3 {
for each t1, t2 combination in join buffer {
if row satisfies join conditions, send to client
}
}
empty join buffer
}
}
}
if buffer is not empty {
for each row in t3 {
for each t1, t2 combination in join buffer {
if row satisfies join conditions, send to client
}
}
}
外側のtable100行の例:
外側のループの結果セットは100行であり、NLJアルゴリズムを使用するには、内部テーブルを100回スキャンする必要があります。
BNLアルゴリズムを使用する場合は、最初に外部ループテーブル(外部テーブル)から読み取られた10行のレコードを(join_buffer_sizeのサイズに応じて)結合バッファーに入れてから、これらの10行のデータを直接照合します。 InnerLoopテーブル(内部テーブル)。メモリループは一度にこれらの10行と比較できるため、10回の比較のみが必要であり、内部テーブルのスキャンが9/10削減されます。
したがって、BNLアルゴリズムは、内部ループテーブルのスキャン数を大幅に減らすことができます。
MySQLがJoinBufferを使用する場合、次の点があります。
- join_buffer_size変数は、バッファーサイズを決定します。
- 結合バッファーは、結合タイプがall、index、およびrangeの場合にのみ使用できます。
- バッファリングできる各結合はバッファを割り当てます。つまり、クエリは最終的に複数の結合バッファを使用する可能性があります。
- 最初のnonconstテーブルは、スキャンタイプがallまたはindexであっても、結合バッファを割り当てません。
- 結合バッファは、結合の前に割り当てられ、クエリの実行後に解放されます。
- データ行全体ではなく、結合に参加している列のみが結合バッファーに格納されます。
使用する
バージョン5.6以降では、オプティマイザー管理パラメーターoptimizer_switchのblock_nested_loopパラメーターは、オプティマイザーでBNLを使用するかどうかを制御します。デフォルトでオンになっています。オフに設定されている場合、オプティマイザは結合方法を選択するときにNLJアルゴリズムを選択します。
オンまたはオフに設定:SET SESSION optimizer_switch ='block_nested_loop=off';
パフォーマンスに影響を与える要因
内部サイクルの数
table1には100レコードがあり、table2には10,000レコードがあると想定します。
命令の実行回数は100 * 10000回です。
Table1はtable2を駆動します:table1は1回ロードされ、table2は100回ロードされます。
Table2はtable1を駆動します。table1は10,000回ロードされ、table2は1回ロードされます。
したがって、table1はtable2をより効率的に駆動します。
大きなテーブルを小さなテーブルで駆動すると、内部ループの数が減り、接続効率が向上します。
クイックマッチ
ドリブンテーブルをスキャンして適切なレコードを探すことは、クエリ操作と見なすことができます。ドリブンテーブルにインデックスを作成すると、クエリの効率を向上させることができます。
ソート
駆動テーブルをソートすると、最初に駆動テーブルがソートされ、次にテーブル結合アルゴリズムが実行されます。ドリブンテーブルの並べ替えは、テーブルの結合を実行した後に結果セットを並べ替えることです。
したがって、ソート用の駆動テーブルの属性を選択することをお勧めします。
JOINは内部ループの数を最適化します
内部ループの数は、ドライブテーブルのレコード数の影響を受けます。ドライブテーブルのレコード数が多いほど、内部ループが多くなり、接続効率が低下するため、小さなテーブルを使用して大きなテーブルを駆動してみてください。
左側の接続では、左側のテーブルがドリブンテーブルであり、右側のテーブルがドリブンテーブルです。
右側の接続では、右側のテーブルがドリブンテーブルであり、左側のテーブルがドリブンテーブルです。
ただし、内部結合は異なります。ネストされたループアルゴリズムの考え方によれば、table1内部接続table2とtable2内部接続table1の結果セットは同じです。
STRAIGHT_JOINは、左側のテーブルを強制的に右側のテーブルに結合します。
MYSQL独自のオプティマイザは内部結合を最適化します。最適化戦略は、前述のように小さなテーブルが大きなテーブルを駆動することです。
JOINの最適化と高速マッチング
2つのテーブルのJOIN操作は、駆動テーブルからレコードを継続的にフェッチし、駆動テーブル内の一致するレコードを見つけて接続することです。このプロセスの本質はクエリ操作です。クエリ操作を最適化するには、インデックス作成が最も一般的な方法です。
左結合
左側の接続では、左側のテーブルがドリブンテーブルであり、右側のテーブルがドリブンテーブルです。ドリブンテーブルで一致するレコードをすばやく見つけたいので、接続パフォーマンスを向上させるために適切なテーブルにインデックスを作成します。
右結合
右側の接続では、右側のテーブルがドリブンテーブルであり、左側のテーブルがドリブンテーブルです。ドリブンテーブルで一致するレコードをすばやく見つけたいので、接続パフォーマンスを向上させるために左側のテーブルにインデックスを作成します。
内部結合
MySQL Optimizerは内部結合を最適化します。誰が接続するか、誰が接続するかに関係なく、小さなテーブルを使用して大きなテーブルを駆動します。したがって、内部結合を最適化する場合は、大きなテーブルにインデックスを作成して接続パフォーマンスを向上させることができます。
また、小さなテーブルにインデックスを作成する場合、MySQL Optimizerは、大きなテーブルを使用して小さなテーブルを駆動する方が高速であると考え、代わりに大きなテーブルを使用して小さなテーブルを駆動することに注意してください。
マルチテーブル結合
上記は2テーブル接続で、マルチテーブル接続も同じです。駆動テーブルと被駆動テーブルを調べ、被駆動テーブルにインデックスを作成して接続性能を向上させます。
つまり、高速マッチングの観点からJOINを最適化するには、最初に駆動テーブルと被駆動テーブルを見つけてから、被駆動テーブルにインデックスを作成します。
JOIN最適化ソート
並べ替えは、接続されている属性の並べ替えと接続されていない属性の並べ替えに分けられます。
接続属性を並べ替える
接続属性をソートするときは、駆動テーブルの属性をソートテーブルの条件として選択する必要があります。
例:table1は大きなテーブル、table2は小さなテーブル、table1とtable2は接続され、接続条件table1.id = table2.id、接続属性IDはソートされます。
Table1は大きなテーブルで、table2は小さなテーブルです。したがって、table2はドリブンテーブルであり、table1はドリブンテーブルです。
方法1:ORDER BY table1.id
がテーブル結合アルゴリズムを実行した後、結果セットがソートされますが、これは非効率的です。
方法2:ORDER BY table2.idは
最初にtable2をソートし、次にテーブル結合アルゴリズムを実行します。効率的。
接続されていない属性を並べ替える
MySQL Optimizerは、「小さなテーブルを駆動する大きなテーブル戦略」に従って最適化するためです。ラージテーブルの結合されていない属性をソートする場合は、STRAIGHT_JOINを使用してラージテーブルがスモールテーブルを駆動するようにすることを検討してください。
例:table1は大きなテーブル、table2は小さなテーブル、table1とtable2は接続され、接続条件table1.id = table2.id、接続されていない属性table1のフィールドタイプがソートされます。
実際の操作結果:MySQLOptimizerはtable2を使用してtable1を駆動します。次に、table1のtype属性を並べ替える必要があります。Table1はドリブンテーブルであるため、必然的に、接続後に結果セットの一時的な並べ替えを使用することになります(filesortの使用よりも深刻です)。したがって、STRAIGHT_JOINを使用して、大きなテーブルtable1が小さなテーブルtable2を駆動するようにします。
この記事の著者は他の記事を非常によく書いているので、学ぶ価値があります。興味がある場合は、彼のブログにアクセスしてください。記事の下部には、mysqlの他の側面に関するチュートリアルがあります。
このブログはhttp://www.apeit.cn/mysql-join-x167qに転載されています。共有していただきありがとうございます。