在您的问题中,您详细介绍了一些准备的测试,这些测试可以“证明”加法选项比比较离散列更快。我怀疑您的测试方法可能在某些方面存在缺陷,就像@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 ms,经过的时间= 173451 ms。
对于“离散列”测试:
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倍。我在上面的测试中持续时间长,主要是因为从磁盘读取了很多行。如果将行数减少到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
零: