3

我必须根据 where 子句对某些列进行求和,以便更好地理解我在这里实现了一个临时表

declare @tbl table(a int ,b int,c int)
insert into @tbl values(1,2,3)
insert into @tbl values(2,2,3)
insert into @tbl values(1,3,1)
insert into @tbl values(1,2,3)
insert into @tbl values(1,2,3)

并用于查找 a,b,c ob 的值的总和 a,b,c 的基础;我正在使用以下查询

 SELECT (
         SELECT SUM(a) from @tbl where a=1         
         )AS a ,          
          (SELECT SUM(b) from @tbl where b=2

         )AS b ,         
          (SELECT SUM(c) from @tbl where c=3

         )AS c

我请我的一位朋友对这项工作进行单行查询,他建议我遵循以下几行

select sum((case  when a=1 then a  else null end)),
        sum((case  when b=2 then b  else null end)),
        sum((case  when c=3 then c  else null end))
         from @tbl

现在我正在考虑如果我有 27 列和数百万条记录,性能会更快吗?

或任何其他方法来实现这一点,这将比这两个更好地提高性能

4

3 回答 3

5

扩展 Martin 的答案 - 这取决于您拥有哪些索引以及该列的填充方式(可空或不可空)。考虑这个例子。

create table tbl (id int identity primary key, a int ,b int,c int, d int)
insert tbl values(1,2,3,null)
insert tbl values(2,null,3,1)
insert tbl values(1,null,1,4)
insert tbl values(1,null,3,5)
insert tbl values(1,null,3,6)
insert tbl select a,b,c,d from tbl --10
insert tbl select a,b,c,d from tbl --20
insert tbl select a,b,c,d from tbl --40
insert tbl select a,b,c,d from tbl --80
insert tbl select a,b,c,d from tbl --160
insert tbl select a,b,c,d from tbl --320
insert tbl select a,b,c,d from tbl --640
insert tbl select a,b,c,d from tbl --1280
insert tbl select a,b,c,d from tbl --2560
insert tbl select a,b,c,d from tbl --5120
insert tbl select a,b,c,d from tbl --10240

b 列被创建为可为空的,并且只有 20% 是非空的。现在,对表运行查询(没有索引)。在运行它之前,请确保按 Ctrl-M(显示实际执行计划)。在同一批次中运行两个查询,即突出显示两个查询的文本并执行。

SELECT (SELECT SUM(a) from tbl where a=1) AS a ,          
       (SELECT SUM(b) from tbl where b=2) AS b ,         
       (SELECT SUM(c) from tbl where c=3) AS c

select sum((case  when a=1 then a  else null end)),
       sum((case  when b=2 then b  else null end)),
       sum((case  when c=3 then c  else null end))
from tbl

我不会在这里用图像让您厌烦,但请看一下计划,该计划将显示最高查询的成本约为 75%,而最低查询的成本为 25%。这是预期的,75%:25% = 3:1,这是由于第一个查询准确地通过表 3 次。现在创建这三个索引:

create index ix_tbl_a on tbl(a)
create index ix_tbl_b on tbl(b)
create index ix_tbl_c on tbl(c)

然后,重新运行查询批处理(两者一起)。这一次,您会看到大约 51% 到 49% 的成本。相当接近。原因是因为(b)被稀疏填充的列很容易SUM单独从索引页中获取。通过在每个索引页检索比数据页上的聚集索引(将包含所有列)更多的行,甚至其他 2 列也得到了帮助。

当您将此扩展为 27 列时,如果每列填充稀疏并且27 列中的每一列都有索引,则第一个表单可以运行得更快。一个很大的问题,即便如此,它可能只会稍微快一点。

于 2012-10-13T21:51:19.360 回答
4

第二个选项使表格单次通过;第一个进行多次传球。在性能方面,在大多数情况下,第二种选择应该更好。

于 2012-10-13T17:56:08.427 回答
3

这取决于你有什么索引。

如果abcall 都被索引,那么原始版本可能会明显更快。特别是如果表格的很大一部分不符合任何标准。

如果您根本没有有用的索引,那么选择是 3 次扫描而不是 1 次扫描,因此CASE版本应该更快。

于 2012-10-13T19:46:30.333 回答