6

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

选项 A

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

对比

选项 B

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

然后做:

select PropertyCount 
  from PropertyCounters 
 where Property = @Property

随着表增长到数千/数百万条记录,我可以合理地预期执行 select count(*) 会降低多少性能?

4

5 回答 5

5

除了真实数据之外,保留一个单独的计数列是一种非规范化。出于性能考虑,您可能需要这样做是有原因的,但在您真正需要之前,您不应该去那里。它使您的代码更加复杂,出现不一致的可能性更大。

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

于 2010-08-17T01:28:43.397 回答
3

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

count(*), 或者严格来说是count_big(*), 是可以在索引视图中使用的表达式,请参阅设计索引视图

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;

所以最后你得到你的蛋糕并吃掉它:该属性已经由引擎免费为你聚合和维护。代价是更新必须维护索引视图(尽管它们不会重新计算聚合计数)并且聚合将创建争用热点(表上不同行上的锁定将竞争索引视图上的相同计数(*)更新)。

于 2010-08-17T01:42:46.947 回答
1

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

于 2010-08-17T02:06:19.573 回答
0

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

我打赌 SQL Server 在这方面的性能比 Postgres 更好,以至于我会在 Postgres 而不是 SQL Server 上更早地考虑后一种方法。但是,由于设置了部分索引来匹配条件,我敢打赌 Postgres 会击败 SQL Server。不过,这正是我所赌的小额奖金,无论哪种方式,我都会测试我是否需要真正考虑一下。

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

于 2010-08-17T01:48:00.700 回答
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) 

通常,我找不到任何关于这些数字到底有多最新的文档——但根据我自己的经验,它们通常就在现场(除非你正在做一些批量加载或其他事情——但在这种情况下,你不会也不想不断扫描表以获得确切的计数)

于 2010-08-17T05:07:10.457 回答