8

少なくとも 1 つのレコードが存在するかどうかを確認する必要がある場合があります。通常は次を使用します。

IF EXISTS (SELECT TOP 1 1 FROM [SomeTable] WHERE [Fields] = [Values]) BEGIN
-- action
END

複数のレコードが存在するかどうかを確認する簡単な方法はありますか? 私は次のようなことができます:

IF EXISTS (SELECT 1 FROM [SomeTable] 
                        WHERE [Fields] = [Values] 
                                HAVING Count(*) > 1) 
BEGIN
    -- action
END

ただし、セット内のすべてのレコードをテストするため、これが最速の方法であるかどうかはわかりません。もっと速い方法はありますか?

「where」部分は非常に複雑で、複数の AND と OR で構成されている場合があります。

4

5 に答える 5

8

SQL Serverは通常、集約クエリを短絡しません。(ここのコメントで説明されているHAVING COUNT(*) > 0)と同じプランを使用するようにクエリを変換できる場合もありますが、それはそれだけです。EXISTS

理論的には行番号2のHAVING COUNT(*) > 1 後でカウントを停止する可能性がありますが、クエリは常にすべての行をカウントします。

それを念頭に置いて、私は使用します

IF EXISTS(
  SELECT * FROM (
                 SELECT TOP 2 *
                 FROM [SomeTable] 
                 WHERE [Fields] = [Values] 
) T
HAVING COUNT(*)=2) 

イテレータは、2番目の行が返された後、行の要求を停止します。TOP 2したがって、すべての行を返し、それらをカウントするのではなく、内部クエリを早期に短絡させることができます。

両方のバージョンの計画例を以下に示します

予定

についてのコメントの質問について

「どれが最適かをどうやって見分けることができますか?それはクエリコストですか?」

TOP上記の計画に示されている特定のケースでは、推定および実際の行数が非常に正確であり、イテレーターの追加を除いて2つの計画は非常に類似しているため、コストは妥当な指標になります。したがって、計画に示されている追加コストは、追加の行数をスキャン(および場合によってはディスクから読み込む)してカウントする必要があるという事実を完全に表しています。

この場合、これが単なる追加作業を表していることは非常に明確です。他の計画ではそうではないかもしれません。を追加すると、TOP 2その下のクエリツリーが大幅に変更される可能性があります(たとえば、イテレータをブロックすることで計画を嫌う)

その場合、実行計画に示されているコストは信頼できるメトリックではない可能性があります。実際の実行プランでも、表示されるコストは見積もりに基づいているため、それらと同じくらい良好であり、推定行数が良好であっても、表示されるコストは特定のモデリングの仮定に基づいています。

SQL Kiwiは、DBAサイトのこの最近の回答にそれをうまく入れています

オプティマイザのコスト見積もりは、主に内部サーバーの目的でのみ役立ちます。これらは、「高レベル」であっても、潜在的なパフォーマンスを評価するために使用されることを意図したものではありません。モデルは、それが設計された内部目的のためにたまたまうまく機能する抽象化です。推定コストがハードウェアと構成の実際の実行コストにかなり類似している可能性は、実際には非常に小さいです。

あなたにとって重要な実際の問題に基づいて、パフォーマンスを比較するために他のメトリックを選択します。

論理読み取り(の場合に表示SET STATISTICS IO ON;)は、確認できるそのようなメトリックの1つですが、これにのみ焦点を当てると、誤解を招く可能性があります。クエリ期間のテストはおそらく唯一の信頼できる方法ですが、パフォーマンスはサーバーでの同時アクティビティに応じて変化する可能性があるため、正確な科学ではありません(メモリの付与、利用可能なDOP、キャッシュ内の関連ページの数を待機します)。

結局のところ、サーバー上のリソースを効率的に使用しているように見えるクエリプランを取得することになります。

于 2012-12-18T12:46:35.103 に答える
2

このチェックをより高速に実行できるようにするトリックがあると確信しています。ただし、スキーマ(特にインデックス)に大きく依存し、特定のチェックはある状況では機能し、別の状況では機能しない場合があります。

以下のようなものがあなたのために働くかもしれません。

IF EXISTS (SELECT * FROM [SomeTable] T1
           INNER JOIN [SomeTable] T2
           ON T1.UniqueID <> T2.UniqueID
           WHERE T1.[Fields] = T1.[Values]
           AND T2.[Fields] = T2.[Values]) 
BEGIN
    -- action
END
于 2012-12-18T12:43:30.907 に答える
1

1,900 万レコードのテーブルでこのソリューションを使用すると、優れたパフォーマンスが得られました。

IF EXISTS (
        SELECT '1' FROM (
            SELECT TOP(2) '1' AS 'N'
            FROM TBL_KV3) AS Z
            HAVING COUNT(*) > 1     
            ) 
    SELECT '1'
ELSE
    SELECT '0'

ここに画像の説明を入力

于 2014-08-29T08:17:06.523 に答える
1

topまたはを気にしないでくださいselect 1

if exists (select * ...)

と同じくらい速いです。

于 2012-12-18T12:28:26.897 に答える
0

パフォーマンスについてはわかりませんが、CTEandを使用できCOUNT(*)OVERます。

WITH Match AS
(
    SELECT t1.*, COUNT(*)OVER(PARTITION BY t1.Fields)AS CountFields
    FROM SomeTable t1
    WHERE t1.Fields=@Values
)
SELECT m1.* 
FROM Match m1
WHERE CountFields >= 2

デモ

于 2012-12-18T12:36:52.663 に答える