选择计数(*)vs保持计数器

时间:2010-08-17 01:23:05

标签: sql performance counting

假设索引已经到位,并且绝对计数准确性不是必需的(可以关闭一两个),是否可以使用:

选项A

select count(*) 
  from Table 
 where Property = @Property

VS

选项B

update PropertyCounters
   SET PropertyCount = PropertyCount + 1  
 where Property = @Property

然后做:

select PropertyCount 
  from PropertyCounters 
 where Property = @Property

当表格增长到数千/数百万条记录时,我可以合理地期望从选择计数(*)中获得多少性能下降?

5 个答案:

答案 0 :(得分:4)

除了真实数据之外,保持单独的计数列是非规范化。你有可能需要为性能做这件事,但你不应该去那里直到你真的需要。它使你的代码更复杂,更容易出现不一致的情况。

对于查询确实只是SELECT COUNT(property) FROM table WHERE property=...的简单情况,没有理由去反规范化;您可以通过在property列上添加索引来加快速度。

答案 1 :(得分:3)

您没有指定平台,但由于您使用@variables的T-SQL语法,我将冒险尝试SQL Server平台特定答案:

count(*),或严格来说是count_big(*),是一个可以在索引视图中使用的表达式,请参阅Designing Indexed Views

create view vwCounts
with schembinding
as select Property, count_big(*) as Count
from dbo.Table
group by Property;

create unique clustered index cdxCounts on vwCounts(Property);

select Count 
from vwCount with (noexpand)
where Property = @property;

在Enterprise Edition上,优化器甚至会使用原始查询的索引视图:

select count_big(*)
from Table
where Property = @property;

所以最后你得到你的蛋糕并吃掉它:该物业已经由发动机免费聚集和维护。价格是更新必须维护索引视图(他们将重新计算聚合计数),聚合将创建争用的热点(表上的单独行上的锁将争用相同的计数( *)更新索引视图。

答案 2 :(得分:1)

如果你说你不需要绝对的准确性,那么选项B是一种奇怪的方法。如果选项A变得太重(甚至在添加索引之后),您可以将选项A的输出缓存在内存或另一个表(您的PropertyCounters)中,并定期刷新它。

答案 3 :(得分:0)

这不是一般SQL术语中可以回答的问题。除了关于索引等关于影响查询的常规警告之外,它也是平台之间存在相当大差异的东西。

我敢打赌从SQL Server上获得比Postgres更好的性能,直到我在Postgres上考虑后一种方法,而不是在SQL Server上。但是,如果部分索引设置恰好匹配条件,我会打赌Postgres击败SQL Server。这就是我敢打赌的小奖金,不管怎么说,如果我需要考虑它是真的,我会测试。

如果您采用后一种方法,请使用触发器或类似方法强制执行,以免您变得不准确。

答案 4 :(得分:0)

在SQL Server上,如果您不需要绝对准确的计数,您还可以检查目录视图。这样做会容易得多 - 你不必自己计算 - 而且对系统的负担要少得多。毕竟,如果你需要计算表中的所有行,你需要以某种方式扫描该表 - 没有办法解决这个问题。

使用此SQL语句,您将获得数据库中的所有表以及SQL Server保留的行数:

SELECT 
    t.NAME AS TableName,
    SUM(p.rows) AS RowCounts
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
WHERE 
    t.NAME NOT LIKE 'dt%' AND
    i.OBJECT_ID > 255 AND   
    i.index_id <= 1
GROUP BY 
    t.NAME, i.object_id, i.index_id, i.name 
ORDER BY 
    OBJECT_NAME(i.object_id) 

我找不到任何关于目前这些数字究竟是多少的文档 - 通常 - 但根据我自己的经验,他们通常是在现场(除非你正在做一些批量加载或其他东西 - 但在这种情况下,您不希望不断扫描表格以获得准确的计数,或者