a = 0およびb = 0および…z = 0 vs a + b + c + d = 0のパフォーマンス


20

これは簡単な質問ですが、答えが見つからないようです。

パフォーマンスの観点から、のWHEREような条項がある場合a=0 and b=0 and ... z=0、その条件をに置き換えてもパフォーマンスは向上しa+b+...+z=0ますか

言い換えれば、次のものを置き換えることによってパフォーマンスが向上しますか

Select * 
From MyTable 
Where A=0 and B=0 and C=0 and D=0...

Select * 
From MyTable 
Where A+B+C+D=0...

私はそれがインデックスに依存することを知っていますが、この目的のために、インデックスが存在しないとだけ言ってみましょう。算術演算子(+)のパフォーマンスは、「OR」または「AND」論理演算子よりも優れていますか?

ANDまたはORを使用した複数の条件よりも、追加の方がパフォーマンスが良いという印象を受けています。

試験結果

420万行のテーブル

A = 0、B = 0、C = 0の行を返す-> 351748行

追加(A + B + C = 0)には5秒かかりましたが、論理条件A = 0およびB = 0およびC = 0には11秒かかりました。

一方

A <> 0 B <> 0またはC <> 0-> 3829750行58秒の行を返す

行を返すF65 + F67 + f64 <> 0-> 3829750行57秒

ORについては、大きな違いはないようです。

私はGBNに同意します:

Aが-1でBが1の場合、A + B = 0ですが、A = 0およびB = 0はfalseです

AMtwoの場合:

ABS(A)+ ABS(B)+ ABS(C)+ ABS(D)...正の値のみを期待している場合でも、列が負の値を受け入れる場合は、それに遭遇する可能性があると仮定する必要があります

私が思ったように、結果は非常に印象的です。追加は論理演算子よりもはるかに速いようです。

A =フロート、B =マネー、C =フロート。使用されるクエリは次のとおりです。私の場合、すべて正の数です。インデックスなし。私の考えでは、論理条件よりも追加の方が速いのは論理的です!


これらはブール値ですか?4(例)または26(タイトル)について、何列について話しますか?違いが生まれます。SQL Serverのバージョン FLOATとMONEYはどこで機能しますか?推定される行数は?この質問には多くの要因があります。
エヴァンキャロル

@Evan Carrollブール値ではなく、インデックスなしの数値(int、float、moneyなど)です。SQLバージョン(SQL2012以降)、行または列の数に関係なく、問題は論理演算子と算術演算子のどちらの演算子の方が優れているかを調べることでした。あなたが見ることができるように、マックス・バーノンは彼の例で理論を完全に実証します。
JohnG

回答:


46

質問では、個別の列を比較するよりも追加オプションが速いことを「証明」する場所で準備したいくつかのテストについて詳しく説明します。@gbnと@srutzkyが示唆しているように、テスト方法にはいくつかの点で欠陥があると思います。

まず、SQL Server Management Studio(または使用しているクライアント)をテストしていないことを確認する必要があります。たとえば、SELECT *300万行のテーブルからを実行している場合、主にSSMSがSQL Serverから行を取得して画面上に表示する機能をテストしています。SELECT COUNT(1)ネットワークを介して数百万行をプルし、画面上にレンダリングする必要をなくすようなものを使用する方がはるかに良いでしょう。

次に、SQL Serverのデータキャッシュに注意する必要があります。通常、ストレージからデータを読み取り、コールドキャッシュからデータを処理する速度をテストします(つまり、SQL Serverのバッファーは空です)。場合によっては、すべてのテストをウォームキャッシュで行うことが理にかなっていますが、それを念頭に置いてテストに明示的に取り組む必要があります。

コールドキャッシュテストでは、あなたが実行する必要があるCHECKPOINTDBCC DROPCLEANBUFFERS、テストの各実行する前に。

質問で質問したテストのために、次のテストベッドを作成しました。

IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
    DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
    TestID INT NOT NULL
        PRIMARY KEY 
        IDENTITY(1,1)
    , A INT NOT NULL
    , B FLOAT NOT NULL
    , C MONEY NOT NULL
    , D BIGINT NOT NULL
);

INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
    , sys.objects o2
    , sys.objects o3
    , sys.objects o4;

SELECT COUNT(1) 
FROM #SomeTest;

これは、私のマシンで260,144,641のカウントを返します。

「追加」メソッドをテストするには、次を実行します。

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;

メッセージタブには以下が表示されます:

テーブル '#SomeTest'。スキャンカウント3、論理読み取り1322661、物理読み取り0、先読み読み取り1313877、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

SQL Serverの実行時間:CPU時間= 49047ミリ秒、経過時間= 173451ミリ秒。

「離散列」テストの場合:

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
    AND st.B = 0
    AND st.C = 0
    AND st.D = 0;
GO

SET STATISTICS IO, TIME OFF;

再び、[メッセージ]タブから:

テーブル '#SomeTest'。スキャンカウント3、論理読み取り1322661、物理読み取り0、先読み読み取り1322661、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

SQL Serverの実行時間:CPU時間= 8938ミリ秒、経過時間= 162581ミリ秒。

上記の統計から、離散列が0と比較され、経過時間が約10秒短く、CPU時間が約6倍短い、2番目のバリアントを見ることができます。上記のテストでの長い期間は、主にディスクから多くの行を読み込んだ結果です。行数を300万に落とすと、比率はほぼ同じままですが、ディスクI / Oの影響ははるかに少ないため、経過時間は著しく低下します。

「追加」メソッドの場合:

テーブル '#SomeTest'。スキャンカウント3、論理読み取り15255、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

SQL Serverの実行時間:CPU時間= 499ミリ秒、経過時間= 256ミリ秒。

「離散列」メソッドの場合:

テーブル '#SomeTest'。スキャンカウント3、論理読み取り15255、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

SQL Serverの実行時間:CPU時間= 94ミリ秒、経過時間= 53ミリ秒。

このテストで本当に大きな違いをもたらすのは何ですか?次のような適切なインデックス:

CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);

「追加」メソッド:

テーブル '#SomeTest'。スキャンカウント3、論理読み取り14235、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

SQL Serverの実行時間:CPU時間= 546ミリ秒、経過時間= 314ミリ秒。

「離散列」メソッド:

テーブル '#SomeTest'。スキャンカウント1、論理読み取り3、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0

SQL Serverの実行時間:CPU時間= 0ミリ秒、経過時間= 0ミリ秒。

(上記のインデックスをインプレースで)各クエリの実行計画は非常にわかりやすいです。

「追加」メソッド。インデックス全体のスキャンを実行する必要があります。

ここに画像の説明を入力してください

そして、「離散列」メソッドは、先頭のインデックス列Aがゼロであるインデックスの最初の行をシークできます:

ここに画像の説明を入力してください


24

A、B、C、Dにインデックスがあるとしましょう。フィルターもかけられます。

これは、インデックスよりもインデックスを使用する可能性が高くなります。

Where A=0 and B=0 and C=0 and D=0

他のニュースでは、Aが-1でBが1の場合、A+B=0真ですがA=0 and B=0偽です。


7

(この回答は、質問に記載されているテストの前に提出されたことに注意してください。質問のテキストは、テスト結果セクションのすぐ上で終了しました。)

ANDオプティマイザーは最初に計算を行う必要なく、それらの1つが0に等しくない場合、操作を短絡する可能性が高いため、個別の条件が優先されると思います。

それでも、これはパフォーマンスの問題であるため、最初にテストをセットアップしてハードウェア上の答えを決定する必要があります。それらの結果を報告し、テストコードを表示し、他の人に見てもらい、それが良いテストであることを確認します。あなたが考えなかった考慮に値する他の要因があるかもしれません。


3

一般的な推論として、インデックスが手元にない場合、2つのソリューションのどちらを選択しても、どちらもパフォーマンスが悪いとは思わないでしょう。一方、述部の1つ以上の列にインデックスがある場合、最初の列はおそらく2番目の列よりもパフォーマンスが高くなります。2番目の列はおそらくインデックスを利用できないためです。

一般に、選言(OR)は接続詞(AND)よりもパフォーマンスが劣りますが、選言を含むクエリがある場合でも、最初の選考にお金をかけます。


2

これは簡単な質問です

いいえそうではありません。この(種類の)質問は、毎日多くのDBAとソフトウェア開発者を悩ませているものであり、些細なことです。

答えが見つからないようです。

はい、できません。少なくとも一般的な答えではありません。まず、使用しているRDBMSに大きく依存します(OK、を使用していが、それでも使用)。RDBMSのあるバージョンから次のバージョンに移行するときにも変更される場合があります。

次に、プランオプティマイザーなどの問題を混乱させる副選択/結合がある場合、DBがどのようにデータを保存するかなど、他の細かい詳細の量に依存する可能性があります。オプティマイザーは、行の数について...

このような質問を解決するには、通常、実世界のテストを行うことが唯一の有用な方法です。また、このような「難解な」最適化によって得られる利益は、通常、インデックスのスマートな選択によって10倍に飲み込まれます。そのため、インデックスの使用が実際に除外されるまで、あまり時間をかけません。


0

これは明らかかもしれないが、カラムがある場合はINT、そのa+b+c場合でも、ゼロに等しくなる可能性がどれもそれらのは実際にはゼロではありません。2つの異なることをテストしています!


@gbnが彼の答えでこれに言及していることに気付いた。
ロスプレッサー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.