質問では、個別の列を比較するよりも追加オプションが速いことを「証明」する場所で準備したいくつかのテストについて詳しく説明します。@gbnと@srutzkyが示唆しているように、テスト方法にはいくつかの点で欠陥があると思います。
まず、SQL Server Management Studio(または使用しているクライアント)をテストしていないことを確認する必要があります。たとえば、SELECT *
300万行のテーブルからを実行している場合、主にSSMSがSQL Serverから行を取得して画面上に表示する機能をテストしています。SELECT COUNT(1)
ネットワークを介して数百万行をプルし、画面上にレンダリングする必要をなくすようなものを使用する方がはるかに良いでしょう。
次に、SQL Serverのデータキャッシュに注意する必要があります。通常、ストレージからデータを読み取り、コールドキャッシュからデータを処理する速度をテストします(つまり、SQL Serverのバッファーは空です)。場合によっては、すべてのテストをウォームキャッシュで行うことが理にかなっていますが、それを念頭に置いてテストに明示的に取り組む必要があります。
コールドキャッシュテストでは、あなたが実行する必要があるCHECKPOINT
とDBCC 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
がゼロであるインデックスの最初の行をシークできます: