2016-04-11 20 views
3

テーブルA、B、C、Dをの4つのテーブルがあり、不特定のリレーショナルSQLデータベースとします。 A参照B、CおよびDも同様である。参照は、Aが列A.refX_id = X.idを有し、XがA、BおよびC(共通外部キー1:N)であることを意味する。SELECT ... WHERE IN IN JOIN

私が欲しいのは、すべての子テーブルB、C、Dの列に基づいた条件でテーブルAを照会することです。私の質問はです。 (ユーザビリティ、効率、スピードの面で)

バリアント1:私は、データベースの観点からより好きですが、プログラムには少し難しくなります

SELECT DISTINCT A.* FROM A 
    JOIN B ON A.refB_id = B.id 
    JOIN C ON A.refC_id = C.id 
    JOIN D ON A.refD_id = D.id 
    WHERE <condition on B> AND <condition on C> AND <condition on D>; 

バリアント2:

SELECT id FROM B WHERE <condition on B>; # result store to array "BIds" on program side 
SELECT id FROM C WHERE <condition on C>; # result store to array "CIds" on program side 
SELECT id FROM D WHERE <condition on D>; # result store to array "DIds" on program side 

SELECT A.* FROM A 
    WHERE refB_id IN (<B_ids>) AND refC_id IN (<C_ids>) AND refD_id IN (<D_ids>); 

# <B_ids> menas expand whole array of ids, which can result in a very long query string 

Iは、バリアント2はcompletellyスマットと潜在的に大きなデータと使用不可であると考えました。しかし、私は聞いたことがありますが、それは相対的に簡単なので、多くのフレームワークが通常それを使用しています。 "IN"句の内容が別のクエリの結果から取得されたことがわかっている場合、一般的にはこのようにデータを照会するのは合法ですか?

+0

ちょうどこの非常に疑問を探していたと、この応答が見つかりました:http://stackoverflow.com/questions/121631/inner-join-vs-where?rq = 1 – CodeJockey

答えて

3

ようJOIN ON条件にWHERE条件を移動させることができるではないと仮定してINNER JOINLEFT JOINに変更しますINまたはEXISTS

SELECT A.* 
FROM A 
WHERE EXISTS (SELECT 1 FROM B WHERE A.refB_id = B.id AND <condition on B>) AND 
     EXISTS (SELECT 1 FROM C WHERE A.refC_id = C.id AND <condition on C>) AND 
     EXISTS (SELECT 1 FROM D WHERE A.refD_id = D.id AND <condition on D>); 

このアプローチの利点:

  • 大きな中間デカルト積が得られる危険はありません。
  • SELECT DISTINCTの重複を排除する費用はありません。
  • ほとんどのデータベースはEXISTSをうまく処理します。
  • インデックスを使用して各サブクエリを最適化できます。

EDIT:

あなたはINとサブクエリでこれを書くことができます。

SELECT A.* 
FROM A 
WHERE A.refB_id IN (SELECT B.id FROM B WHERE <condition on B>) AND 
     A.refC_id IN (SELECT C.id FROM C WHERE <condition on C>) AND 
     A.refD_id IN (SELECT D.id FROM D WHERE <condition on D>); 
+0

ありがとうございました! SELECT 1は見たことがありません... INではどのように見えますか?あなたはVariant1を意味しましたか? – David

+0

はい、これは読みやすくなります。ありがとう、それはまさに私が望んでいたものです。 – David

+0

@David私は読みやすさについては同意しませんが、あなたが見慣れたものによって異なります。 – CodeJockey

3

どのフレームワークが第2のアプローチを使用しているかはわかりませんが、第1のアプローチは、私が求めていることです。すべての表の結合列に適切な索引が作成されている場合、第1の方法では複数のIN句を持つ2番目の方法よりもはるかに良い計画が作成され、何百万もの要素がすべてINであればどうなりますか?

また、私はすべてのIDのが一致して、私が使用することをお勧めします

SELECT DISTINCT A.* FROM A 
    LEFT JOIN B ON A.refB_id = B.id AND <condition on B> 
    LEFT JOIN C ON A.refC_id = C.id AND <condition on C> 
    LEFT JOIN D ON A.refD_id = D.id AND <condition on D>;