sql-server – 对于绝对性能,SUM更快还是COUNT?

前端之家收集整理的这篇文章主要介绍了sql-server – 对于绝对性能,SUM更快还是COUNT?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这涉及计算与特定条件匹配的记录的数量,例如,发票金额> $100

我倾向于喜欢

COUNT(CASE WHEN invoice_amount > 100 THEN 1 END)

但是,这同样有效

SUM(CASE WHEN invoice_amount > 100 THEN 1 ELSE 0 END)

我原以为COUNT是有利的,原因有两个:

>传达意图,即COUNT
> COUNT可能涉及
一个简单的i = 1操作,而SUM不能指望
它的表达式是一个简单的整数值.

有没有人有关于特定RDBMS差异的具体事实?

解决方法

你自己已经回答了这个问题.我有一些要补充的内容

在Postgresql(和其他支持布尔类型的RDBMS)中,您可以直接使用测试的布尔结果.将它转换为整数和SUM():

SUM((amount > 100)::int))

或者在NULLIF()表达式和COUNT()中使用它:

COUNT(NULLIF(amount > 100,FALSE))

或者使用简单的OR NULL:

COUNT(amount > 100 OR NULL)

或其他各种表达方式.性能几乎完全相同. COUNT()通常比SUM()快一点.与SUM()和Paul already commented不同,COUNT()永远不会返回NULL,这可能很方便.有关:

> Query optimization or missing indexes?

从Postgres 9.4开始,还有FILTER子句.细节:

> Return counts for multiple ranges in a single SELECT statement

它比上述所有速度快5到10%:

COUNT(*) FILTER (WHERE amount > 100)

如果查询与测试用例一样简单,只有一个计数而没有其他任何内容,则可以重写:

SELECT count(*) FROM tbl WHERE amount > 100;

即使没有索引,哪个是真正的表演之王.
使用适用的索引,它可以更快的数量级,特别是对于仅索引扫描.

基准

Postgres 10

我为Postgres 10运行了一系列新的测试,包括聚合的FILTER子句,并展示了一个小指数和大指数的作用.

设置简单:

CREATE TABLE tbl (
   tbl_id int,amount int NOT NULL
);

INSERT INTO tbl
SELECT g,(random() * 150)::int
FROM   generate_series (1,1000000) g;

-- only relevant for the last test
CREATE INDEX ON tbl (amount);

由于背景噪音和试验台的具体情况,实际时间变化很大.从更大的测试集中显示典型的最佳时间.这两个案例应该抓住本质:

测试1计算所有行的~1%

SELECT COUNT(NULLIF(amount > 148,FALSE))            FROM tbl; -- 140 ms
SELECT SUM((amount > 148)::int)                      FROM tbl; -- 136 ms
SELECT SUM(CASE WHEN amount > 148 THEN 1 ELSE 0 END) FROM tbl; -- 133 ms
SELECT COUNT(CASE WHEN amount > 148 THEN 1 END)      FROM tbl; -- 130 ms
SELECT COUNT((amount > 148) OR NULL)                 FROM tbl; -- 130 ms
SELECT COUNT(*) FILTER (WHERE amount > 148)          FROM tbl; -- 118 ms -- !

SELECT count(*) FROM tbl WHERE amount > 148; -- without index  --  75 ms -- !!
SELECT count(*) FROM tbl WHERE amount > 148; -- with index     --   1.4 ms -- !!!

db<>小提琴here

测试2计算所有行的~33%

SELECT COUNT(NULLIF(amount > 100,FALSE))            FROM tbl; -- 140 ms
SELECT SUM((amount > 100)::int)                      FROM tbl; -- 138 ms
SELECT SUM(CASE WHEN amount > 100 THEN 1 ELSE 0 END) FROM tbl; -- 139 ms
SELECT COUNT(CASE WHEN amount > 100 THEN 1 END)      FROM tbl; -- 138 ms
SELECT COUNT(amount > 100 OR NULL)                   FROM tbl; -- 137 ms
SELECT COUNT(*) FILTER (WHERE amount > 100)          FROM tbl; -- 132 ms -- !

SELECT count(*) FROM tbl WHERE amount > 100; -- without index  -- 102 ms -- !!
SELECT count(*) FROM tbl WHERE amount > 100; -- with index     --  55 ms -- !!!

db<>小提琴here

每组中的最后一个测试使用仅索引扫描,这就是为什么它有助于计算所有行的三分之一.当涉及所有行的大约5%或更多时,普通索引或位图索引扫描不能与顺序扫描竞争.

Postgres的旧测试9.1

为了验证我在Postgresql 9.1.6中的真实生命表上使用EXPLAIN ANALYZE进行了快速测试.

符合条件kat_id>的184568行中的74208行50.所有查询都返回相同的结果.我依次运行10次以排除缓存效果并附加最佳结果作为注释:

SELECT SUM((kat_id > 50)::int)                      FROM log_kat; -- 438 ms
SELECT COUNT(NULLIF(kat_id > 50,FALSE))            FROM log_kat; -- 437 ms
SELECT COUNT(CASE WHEN kat_id > 50 THEN 1 END)      FROM log_kat; -- 437 ms
SELECT COUNT((kat_id > 50) OR NULL)                 FROM log_kat; -- 436 ms
SELECT SUM(CASE WHEN kat_id > 50 THEN 1 ELSE 0 END) FROM log_kat; -- 432 ms

性能几乎没有任何真正的差异.

猜你在找的MsSQL相关文章