sql-server – a = 0和b = 0的性能和… z = 0 vs b c d = 0

这是一个简单的问题,我似乎找不到答案.

性能方面,如果我有一个WHERE子句,如a = 0和b = 0,并且… z = 0,如果我用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< 0> 0或C< 0>> 3829750行58秒

返回行F65 F67 f64<> 0 – > 3829750行57秒

对于OR,似乎没有显着差异.

我同意gbn:

If A is -1 and B is 1,A+B=0 but A=0 and B= 0 is false

和AMtwo:

ABS(A)+ABS(B)+ABS(C)+ABS(D)… Even if you expect only positive values,if the column accepts negative values,you should assume that you might encounter one

结果非常令人印象深刻,正如我想的那样,似乎加法比逻辑运算符快得多.

A = Float,B = Money和C = Float.使用的查询如图所示.就我而言,所有都是正数.没有索引.在我看来,合乎逻辑的是,添加会比逻辑条件更快!

解决方法

在您的问题中,您详细说明了您准备的一些测试,其中“证明”添加选项比比较离散列更快.我怀疑你的测试方法可能在几个方面存在缺陷,正如@gbn和@srutzky所暗示的那样.

首先,您需要确保不测试sql Server Management Studio(或您正在使用的任何客户端).例如,如果从具有300万行的表中运行SELECT *,则主要测试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;

消息选项卡显示

Table ‘#SomeTest’. Scan count 3,logical reads 1322661,physical reads 0,read-ahead reads 1313877,lob logical reads 0,lob physical reads 0,lob read-ahead reads 0.

sql Server Execution Times:
cpu time = 49047 ms,elapsed time = 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;

再次,从消息选项卡:

Table ‘#SomeTest’. Scan count 3,read-ahead reads 1322661,lob read-ahead reads 0.

sql Server Execution Times:
cpu time = 8938 ms,elapsed time = 162581 ms.

从上面的统计数据可以看到第二个变量,离散列与0相比,经过的时间缩短了大约10秒,cpu时间减少了大约6倍.我上面的测试中的长持续时间主要是从磁盘读取大量行的结果.如果将行数减少到300万,您会看到比率保持大致相同但经过的时间明显减少,因为磁盘I / O的影响要小得多.

使用“加法”方法

Table ‘#SomeTest’. Scan count 3,logical reads 15255,read-ahead reads 0,lob read-ahead reads 0.

sql Server Execution Times:
cpu time = 499 ms,elapsed time = 256 ms.

使用“离散列”方法

Table ‘#SomeTest’. Scan count 3,lob read-ahead reads 0.

sql Server Execution Times:
cpu time = 94 ms,elapsed time = 53 ms.

什么会对这个测试产生非常大的影响?适当的索引,例如:

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

添加方法

Table ‘#SomeTest’. Scan count 3,logical reads 14235,lob read-ahead reads 0.

sql Server Execution Times:
cpu time = 546 ms,elapsed time = 314 ms.

“离散列”方法

Table ‘#SomeTest’. Scan count 1,logical reads 3,lob read-ahead reads 0.

sql Server Execution Times:
cpu time = 0 ms,elapsed time = 0 ms.

每个查询的执行计划(使用上述索引就位)非常有说服力.

添加方法,必须执行整个索引的扫描:

和“离散列”方法,它可以寻找前导索引列A为零的索引的第一行:

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...