SQL:使用count()与保持单独的字段

时间:2011-02-24 19:32:10

标签: sql performance count

我对SQL性能有疑问,并希望有人能得到答案。

我有数据库表tbl_users,我想获得我拥有的用户总数。我可以把它写成SELECT COUNT(*) FROM tbl_users。我认为这样的查询会产生性能影响,因为我有少数用户和几百万用户。 (因此,假设#1是我拥有的行越多,此查询将消耗的资源就越多。)

在这种特殊情况下,我需要以相对较高的频率运行此查询,每次我需要获取最新数据(因此,缓存不是一种选择)。

假设我的第一个问题是正确的,那么我想到了以下方式构建它:

  • 使用字段userCounter
  • 创建tbl_stats
  • 每次在tbl_users中插入时,userCounter都会更新为+1
  • 每次我需要获取用户数时,我都可以从tbl_stats中提取一个字段

现在,我意识到通过这样做,userCounter中的数据在技术上是重复的,这是不好的形式。

那么,我的第一个查询(假设数百万行数据)会消耗那么多资源来保证我实现我的替代设计吗?如果是这样(或者可能是的话),那么我的替代设计是否符合最佳实践?

6 个答案:

答案 0 :(得分:4)

如果您的表被索引,几乎可以肯定,那么select count(*)的性能可能不会像您预期的那样糟糕 - 即使您有数百万行。

但是,如果确实成为一个问题,那么请考虑使用索引视图,而不是推出自己的解决方案。

答案 1 :(得分:2)

我认为这是您真正需要衡量绩效以做出正确决策的场景之一。我敢打赌,一个简单的COUNT()不会产生足够的延迟,你需要实现你提出的解决方案。

如果您担心我会将COUNT()封装在函数或存储过程中,那么如果性能确实成为问题,您可以在以后快速将其交换出来。

答案 2 :(得分:2)

我有一个包含近500万条记录的数据库表,以下查询在不到一秒的时间内返回

select count(userID) from tblUsers

此查询在2秒内返回

select count(*) from tblUsers

我个人只是选择count()而不是创建重复字段

答案 3 :(得分:2)

在某些系统上,您可以要求系统为您维护计数。例如,在SQL Server中,您可以在计数上有indexed view

create view vwCountUsers
with schema binding
as
select count_big(*) as count
from dbo.tbl_users;

create clustered index cdxCountUsers on vwCountUsers (count);

系统会为您保留计数,并且几乎可以免费使用。

答案 4 :(得分:1)

如果您有迫切的需求和真实的商业案例,那么准确的计数,那么触发器就是最佳选择。只需确保它满足所有多用户问题,例如并发和事务。

它可能会成为一个瓶颈,因为不是5个事务能够插入到新表中,它们将排队等待更新userCounter表,甚至可能会出现死锁。

还有其他选项可用于不太准确的计数,但如果您想要准确,则其他选择很少,但我会尝试考虑一些:

  1. 您可以对数据进行分区,并在userCounter存储中按天计数。如果仅在当天添加数据,请执行select sum(dailycount) from counter + select count(*) from table where {date=today}

  2. 您至少可以使用nolock或readpast选项来减少资源使用:

  3. select * from tbl with (readpast)
    select * from tbl with (nolock)
    

答案 5 :(得分:1)

有些事情因性能原因而预先计算是有意义的(多年数据的复杂计算)。这就是为什么数据仓库在很​​多时候都存在加速报告的原因。如果您在表上有任何索引,则选择count(*)通常不是其中之一。还有更糟糕的性能问题需要解决。我得到1秒的时间将计数返回到一个有1300万行的表格上。

我所有关于编写代码的能力比替代方案更好(避免相关子查询,使用基于集合的operatiosn而不是游标,具有sargable where子句),但这是一个不应该的mirco优化解决,直到出现真正的性能问题。