web-dev-qa-db-ja.com

SQLはSQLサブクエリ(パフォーマンス)と結合しますか?

joinこのようなクエリがあるかどうかを知りたい-

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

そしてsubqueryこのようなもの-

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

パフォーマンスを検討すると、2つのクエリのどちらがより高速になり、why

また、一方を他方よりも優先すべき時がありますか?

これがあまりにも些細で前に尋ねられたら申し訳ありませんが、私はそれについて混乱しています。また、皆さんが私に提案することができれば素晴らしいと思いますtools 2つのクエリのパフォーマンスを測定するために使用する必要があります。どうもありがとう!

95
Vishal

主に同等性と明示的なJOINがあるため、最初のクエリがより高速になると期待しています。私の経験では、INは非常に遅い演算子です。SQLは通常、「OR」(WHERE x=Y OR x=Z OR...)で区切られた一連のWHERE句として評価するためです。

ALL THINGS SQLと同様に、走行距離は異なる場合があります。速度はインデックスに大きく依存します(両方のID列にインデックスがありますか?それは非常に役立ちます...)。

100%の確実性でより速く判断する唯一の実際の方法は、パフォーマンストラッキングを有効にし(IO統計が特に便利です)、両方を実行することです。実行するたびにキャッシュをクリアしてください!

43
JNK

まあ、私はそれが「古いが金」の質問だと思います。答えは「依存します!」です。パフォーマンスは非常にデリケートな主題であるため、「サブクエリを使用せず、常に参加する」と言うのは馬鹿げすぎます。次のリンクには、非常に役立つことがわかった基本的なベストプラクティスがいくつかあります。 ここ1ここ2ここ

50000の要素を持つテーブルがあり、探していた結果は739の要素でした。

私の最初の質問はこれでした:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

実行に7.9秒かかりました。

最後に私のクエリはこれです:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

0.0256sかかりました

良いSQL、良い。

30
linuxatico

SQlサーバーがそれらを解釈する方法の違いを確認するために、実行計画を調べ始めます。プロファイラーを使用して、実際にクエリを複数回実行し、差異を取得することもできます。

これらがそれほどひどく異なるとは思いません。相関サブクエリを使用すると、サブクエリの代わりに結合を使用することで実際に大きなパフォーマンスを得ることができます。

EXISTSは多くの場合、これら2つのいずれよりも優れており、左結合テーブルにないすべてのレコードを必要とする左結合について話している場合、多くの場合、NOT EXISTSの方がはるかに優れた選択肢です。

10
HLGEM

パフォーマンスは、実行しているデータの量に基づいています...

20kあたりのデータが少ない場合。 JOINの方が効果的です。

データが100k +に近い場合、INはより適切に機能します。

他のテーブルのデータが必要ない場合、INは良いですが、EXISTSを使用することをお勧めします。

私がテストしたこれらすべての基準とテーブルには適切なインデックスがあります。

8
JP Emvia

2つのクエリは意味的に同等ではない場合があります。従業員が複数の部門で働いている場合(私が働いている企業で可能です;確かに、これはテーブルが完全に正規化されていないことを意味します)、最初のクエリは重複行を返しますが、2番目のクエリはそうではありません。この場合にクエリを同等にするには、DISTINCTキーワードをSELECT句に追加する必要があり、これはパフォーマンスに影響を与える可能性があります。

テーブルはエンティティ/クラスまたはエンティティ/クラス間の関係をモデル化する必要がありますが、両方をモデル化するべきではないという設計経験則があります。したがって、OrgChartなどの3番目のテーブルを作成して、従業員と部署の関係をモデル化することをお勧めします。

4
onedaywhen

これは古い投稿であることは知っていますが、これは非常に重要なトピックだと思います。特に、最近では1,000万件以上のレコードがあり、テラバイトのデータについて語っています。

また、次の観察結果にも重みを付けます。テーブル([データ])に約4,500万レコード、[cats]テーブルに約300レコードがあります。これから説明するすべてのクエリに対して広範なインデックスを作成します。

例1を検討してください。

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

対例2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

例1の実行には約23分かかりました。例2は約5分かかりました。

したがって、この場合のサブクエリははるかに高速であると結論付けます。もちろん、I/O @ 1GB /秒(バイトではなくバイト)が可能なM.2 SSDドライブを使用しているため、インデックスも非常に高速です。したがって、これはあなたの状況でも速度に影響を与える可能性があります

1回限りのデータクレンジングの場合は、実行して終了することをお勧めします。 TOP(10000)を使用して、どのくらい時間がかかるかを確認し、大きなクエリをヒットする前にレコード数を掛けます。

実稼働データベースを最適化する場合は、データの前処理、つまりトリガーまたはジョブブローカーを使用して更新レコードを非同期化し、リアルタイムアクセスで静的データを取得することを強くお勧めします。

3
Arvin Amir

パフォーマンスは同じでなければなりません。テーブルに正しいインデックスとクラスタリングを適用することの方がはるかに重要です(そのトピックには (良いリソース) が存在します)。

(更新された質問を反映するように編集)

3
Lucero

Explain Planを使用して、客観的な答えを得ることができます。

あなたの問題については、 Exists filter がおそらく最も高速に実行されるでしょう。

0
Snekse