a = 0和b = 0以及…z = 0与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...

我知道它可以依赖于索引,但是为此,我们只说不存在索引。算术运算符(+)的性能是否优于“或”或“与”逻辑运算符?

我的印象是,加法的效果要好于使用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为假

和AMtwo:

ABS(A)+ ABS(B)+ ABS(C)+ ABS(D)...即使您只期望正值,但如果该列接受负值,您也应该假设您可能会遇到一个

正如我所想,结果非常令人印象深刻,看来加法比逻辑运算符要快得多。

A =浮动,B =货币,C =浮动。使用的查询如下所示。就我而言,都是正数。没有索引。在我看来,合乎逻辑的条件比逻辑条件要快!


这些是布尔值吗?您在谈论4列(在示例中)或26列(在标题中)?这有所作为。什么版本的SQL Server?FLOAT和MONEY在哪里发挥作用?我们假设有多少行?这个问题有很多因素。
埃文·卡罗尔

@Evan Carroll他们不是布尔值,他们是没有索引的数字(整数,浮点数,货币等)。无论使用哪种SQL版本(SQL2012及更高版本),行数或列数都是多少,问题是要找出哪个运算符的性能更好-逻辑运算符还是算术运算符。如您所见,马克斯·弗农(Max Vernon)用他的例子完美地说明了这一理论。
JohnG '17

Answers:


46

在您的问题中,您详细介绍了一些准备的测试,这些测试可以“证明”加法选项比比较离散列更快。我怀疑您的测试方法可能在某些方面存在缺陷,就像@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零:

在此处输入图片说明


24

假设您在A,B,C和D上都有一个索引。也可以进行过滤。

这更可能使用索引然后加上。

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

在其他新闻中,如果A为-1而B为1,A+B=0则为true,但A=0 and B=0为false。


7

(请注意,此答案是在“问题”中提到任何测试之前提交的:“问题”的文本恰好在“ 测试结果”部分的上方。)

我猜想AND最好使用单独的条件,因为如果其中一个条件等于0,则优化器更可能使操作短路,而无需先进行计算。

不过,由于这是性能的问题,你应该先建立一个测试,以确定在回答你的硬件。报告这些结果,显示您的测试代码,并要求其他人仔细检查以确保它是一个很好的测试。您可能没有想到其他值得考虑的因素。


3

一些一般的推论,如果手头没有任何索引,我认为选择这两种解决方案中的哪一种都不会有多大关系,两者都会表现不佳。另一方面,如果您在谓词中的一个或多个列上都有索引,则第一个可能会比第二个更好,因为第二个可能无法利用索引。

总的来说,析取(OR)的性能要比合取(AND)差,但是即使您有析取的查询,我也会把钱花在第一个上。


2

这是一个简单的问题

不它不是。这个(种类)问题是每天困扰着许多DBA和软件开发人员的问题,这几乎是微不足道的。

我似乎找不到答案。

是的,您不会。至少不是一个普遍的答案。首先,这将在很大程度上取决于您所使用的RDBMS(好的,您正在使用,但是仍然)。当您从一个版本的RDBMS转到另一个版本时,它甚至可能会更改。

然后,它可能取决于任何其他小细节,例如,数据库如何存储数据,如果子选择/联接使计划优化程序产生问题,等等。优化程序可能会为您提供不同的执行计划,具体取决于你有多少行...

进行实际测试通常是解决此类问题的唯一有用方法。同样,通过这样的“ arcane”优化所获得的任何收益通常都被精明的索引选择所吞噬了十倍,因此,在真正排除使用索引之前,我不会花太多时间在上面。


0

这可能是显而易见的,但如果列INT,则a+b+c可能等于零,即使没有它们实际上是零。您正在测试两种不同的东西!


刚意识到@gbn在他的回答中提到了这一点。
Ross Presser
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.