什么更快:SUM 超过 NULL 还是超过 0?

Posted

技术标签:

【中文标题】什么更快:SUM 超过 NULL 还是超过 0?【英文标题】:What is faster: SUM over NULL or over 0? 【发布时间】:2015-11-25 12:04:55 【问题描述】:

我有一个这样的查询:

select sum(case when col1=@arg1 then value else null end) from t

在性能方面,使用 0 而不是 NULL 有区别吗?像这样:

select sum(case when col1=@arg1 then value else 0 end) from t

【问题讨论】:

【参考方案1】:
DECLARE @type CHAR(2) = 'U'

-- [Expr1042] = Scalar Operator(CASE WHEN [Expr1048]=(0) THEN NULL ELSE [Expr1049] END)

SELECT SUM(CASE WHEN [type] = @type THEN 1 END)
FROM sys.objects

-- [Expr1042] = Scalar Operator(CASE WHEN [Expr1048]=(0) THEN NULL ELSE [Expr1049] END)

SELECT SUM(CASE WHEN [type] = @type THEN 1 ELSE NULL END)
FROM sys.objects

-- [Expr1042] = Scalar Operator(CASE WHEN [Expr1048]=(0) THEN NULL ELSE [Expr1049] END)

SELECT SUM(CASE WHEN [type] = @type THEN 1 ELSE 0 END)
FROM sys.objects

结果:

Table 'sysschobjs'. Scan count 1, logical reads 1556, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 7 ms.

Table 'sysschobjs'. Scan count 1, logical reads 1556, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 6 ms.

Table 'sysschobjs'. Scan count 1, logical reads 1556, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 7 ms.

所以...答案 - 类似(如果我们只谈论性能)

【讨论】:

【参考方案2】:

在下面的测试中,我始终发现NULL 稍快。

   SET STATISTICS TIME ON;
   DECLARE @i int = null; /*Or set to zero*/

   WITH 
    E1(N) AS 
    (
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
    )                                       -- 1*10^1 or 10 rows
    , E2(N) AS (SELECT 1 FROM E1 a, E1 b)   -- 1*10^2 or 100 rows
    , E4(N) AS (SELECT 1 FROM E2 a, E2 b)   -- 1*10^4 or 10,000 rows
    , E8(N) AS (SELECT 1 FROM E4 a, E4 b)   -- 1*10^8 or 100,000,000 rows

    SELECT SUM(@i) FROM E8 
    OPTION (MAXDOP 1)

聚合 100,000,000 个值平均需要 608 毫秒。 (即每次聚合 6 纳秒)。

NULL 会花更多时间在

sqllang.dll!CESRunTimeErrorSink::SetAggFnSkippedNull

大概设置了导致消息的标志

警告:空值被聚合或其他 SET 消除 操作。

但总体上似乎更快(以下以毫秒为单位的经过时间)。

+---------+--------+------++-------+
|         |  NULL  |  0   || Diff  |
+---------+--------+------++-------+
| Trial 1 | 7027   | 7592 || 565   |
| Trial 2 | 6981   | 7743 || 762   |
| Trial 3 | 7451   | 8015 || 564   |
| Trial 4 | 6997   | 7591 || 594   |
| Trial 5 | 7018   | 7574 || 556   |
+---------+--------+------++-------+
| Avg     | 7094.8 | 7703 || 608.2 |
+---------+--------+------++-------+

当然,在这种情况下(所有输入都是NULL),它们会返回不同的结果,如果您想将两者互换使用,则需要ISNULL(SUM(@i),0)

【讨论】:

你能提供你的 sql server 实例的版本吗?提前致谢。 @Devart RTM 版本的 SqlServer 2014。 在 2012 sp3 上得到了类似的结果。感谢您的提示 谢谢,很棒的脚本!在我们的服务器 (2008r2) 上进行了尝试,每次通过 5 次,这里我们平均有 11753 毫秒和 12699 毫秒,所以慢了 8.04% 或快了 7.44%。你的平均结果慢了 8.58% 或快了 7.91%,所以这很相似!

以上是关于什么更快:SUM 超过 NULL 还是超过 0?的主要内容,如果未能解决你的问题,请参考以下文章

363 Max Sum of Rectangle No Larger Than K 最大矩阵和不超过K

[LeetCode] Max Sum of Rectangle No Larger Than K 最大矩阵和不超过K

MySQL:唯一,但默认为 NULL - 通过创建表允许。允许插入超过 1 个 NULL。为啥?

如何让SQL语句中的聚集函数sum不忽略NULL值

使用 VBA for Excel 从大量单元格中删除“额外”空格(超过 1 个)的更快方法

MBR格式支持多硬盘超过2TB吗?