1

どちらの select ステートメントが優れていますか?

SELECT *
FROM  aTable
WHERE aField in (
    SELECT xField 
    FROM   bTable
    WHERE  yField > 5
);

また

SELECT *
FROM  aTable
WHERE (
    SELECT yField
    FROM   bTable
    WHERE  aTable.aField = bTable.xField
) > 5;
4

3 に答える 3

3

それらは非常によく似た実行プランを生成します(私のテストテーブルでは小さいです。YMMVは常に実際のデータをプロファイルします)。代わりに検討したい3番目の選択肢があります。

最初:

EXPLAIN SELECT * FROM aTable WHERE aField in (SELECT xField FROM bTable WHERE yField > 5);
+ ---- + -------------------- + -------- + ------- + ------ --------- + --------------- + --------- + ------ + ------ + ------------- +
| id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ|
+ ---- + -------------------- + -------- + ------- + ------ --------- + --------------- + --------- + ------ + ------ + ------------- +
| 1 | プライマリー| aTable | すべて| NULL | NULL | NULL | NULL | 4 | whereを使用する|
| 2 | 依存サブクエリ| bTable | 範囲| bTable_yField | bTable_yField | 5 | NULL | 2 | whereを使用する|
+ ---- + -------------------- + -------- + ------- + ------ --------- + --------------- + --------- + ------ + ------ + ------------- +

二番目:

EXPLAIN SELECT * FROM aTable WHERE (SELECT yField FROM bTable WHERE aTable.aField = bTable.xField) > 5;
+ ---- + -------------------- + -------- + ------ + ------- -------- + ------ + --------- + ------ + ------ + ---------- --- +
| id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ|
+ ---- + -------------------- + -------- + ------ + ------- -------- + ------ + --------- + ------ + ------ + ---------- --- +
| 1 | プライマリー| aTable | すべて| NULL | NULL | NULL | NULL | 4 | whereを使用する|
| 2 | 依存サブクエリ| bTable | すべて| NULL | NULL | NULL | NULL | 4 | whereを使用する|
+ ---- + -------------------- + -------- + ------ + ------- -------- + ------ + --------- + ------ + ------ + ---------- --- +

どちらも依存サブクエリになります。私のサンプルテーブルでは、最初のテーブルはインデックスの恩恵を受けていますが(私bTable.yFieldはインデックスが付けられていると思います)、2番目のテーブルはそうではありません。

JOIN依存サブクエリを回避し、 :を使用して事前フィルタリングを改善できます。

3番目の選択肢:

EXPLAIN SELECT * FROM aTable INNER JOIN bTable On aTable.aField = bTable.xField WHERE bTable.yField > 5;
+ ---- + ------------- + -------- + ------- + ------------- -+ --------------- + --------- + ------ + ------ + ------- ------------------------- +
| id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ|
+ ---- + ------------- + -------- + ------- + ------------- -+ --------------- + --------- + ------ + ------ + ------- ------------------------- +
| 1 | シンプル| bTable | 範囲| bTable_yField | bTable_yField | 5 | NULL | 2 | whereを使用する|
| 1 | シンプル| aTable | すべて| NULL | NULL | NULL | NULL | 4 | whereを使用する; 結合バッファの使用|
+ ---- + ------------- + -------- + ------- + ------------- -+ --------------- + --------- + ------ + ------ + ------- ------------------------- +

ただし、オプティマイザがさまざまな決定を行う可能性があるため、スキーマと代表的な実世界のデータを使用してプロファイリングする必要があります。

quassnoiによるこの優れた記事で、これらの種類の手法をさらに比較します。


参考までに、クエリを作成aTableし、bTable(定義を提供しなかったため)テストした方法は次のとおりです。

mysql> CREATE TABLE aTable(aField INT、aMore VARCHAR(200));
クエリOK、影響を受けた0行(0.01秒)

mysql> CREATE TABLE bTable(xField INT、yField INT);
クエリOK、影響を受ける行は0(0.02秒)

mysql> INSERT INTO aTable(aField、aMore)VALUES(1、'One')、(2、'Two')、(3、'Three')、(4、'Four');
クエリOK、影響を受ける4行(0.00秒)
レコード:4重複:0警告:0

mysql> INSERT INTO bTable(xField、yField)VALUES(1、10)、(2、2)、(3、20)、(4、4);
クエリOK、影響を受ける4行(0.02秒)
レコード:4重複:0警告:0

mysql> CREATE INDEX bTable_yField ON bTable(yField);
クエリOK、影響を受けた0行(0.05秒)
レコード:0重複:0警告:0

mysql> SELECT * FROM aTable WHERE aField in(SELECT xField FROM bTable WHERE yField> 5);
+ -------- + ------- +
| aField | aMore |
+ -------- + ------- +
| 1 | 1つ|
| 3 | 3つ|
+ -------- + ------- +
セットの2行(0.00秒)

mysql> SELECT * FROM aTable WHERE(SELECT yField FROM bTable WHERE aTable.aField = bTable.xField)> 5;
+ -------- + ------- +
| aField | aMore |
+ -------- + ------- +
| 1 | 1つ|
| 3 | 3つ|
+ -------- + ------- +
セットの2行(0.00秒)
于 2012-10-24T14:50:20.587 に答える
1

2 番目のものは相関サブクエリのセマンティクスに変換されるため、最初のものと比較してコストがかかると思います。最善の方法は、次のように 2 つのテーブルを結合することです。

SELECT 
    a.* 
FROM 
    aTable a
    JOIN bTable b
    ON aTable.aField = bTable.xField
WHERE 
    b.xField > 5

これにより、最初のクエリの場合に、クエリの実行が遅くなり、場合によってはオーバーフロー エラーが発生する IN 句の多数の結果を回避できます (SQL Server では、IN で 32767 の値に制限がありました。このオーバーフロー エラーをスローするために使用される句)。

于 2012-10-24T13:36:47.750 に答える
0

多くは、テーブルのインデックス付けと、インデックス付けされた列が結合条件内で使用されているかどうかによって異なります。これらを組み合わせることで、SQL エンジンがクエリを内部的に構築する方法を「決定」し、最終的にクエリのパフォーマンスに影響を与えることができます。MySQL についてはよくわかりませんが、SQL Server では潜在的なボトルネックを示す実行計画を作成できることは確かです。

于 2012-10-24T13:47:35.670 に答える