我对SQL性能有疑问,并希望有人能得到答案。
我有数据库表tbl_users,我想获得我拥有的用户总数。我可以把它写成SELECT COUNT(*) FROM tbl_users
。我认为这样的查询会产生性能影响,因为我有少数用户和几百万用户。 (因此,假设#1是我拥有的行越多,此查询将消耗的资源就越多。)
在这种特殊情况下,我需要以相对较高的频率运行此查询,每次我需要获取最新数据(因此,缓存不是一种选择)。
假设我的第一个问题是正确的,那么我想到了以下方式构建它:
现在,我意识到通过这样做,userCounter中的数据在技术上是重复的,这是不好的形式。
那么,我的第一个查询(假设数百万行数据)会消耗那么多资源来保证我实现我的替代设计吗?如果是这样(或者可能是的话),那么我的替代设计是否符合最佳实践?
答案 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表,甚至可能会出现死锁。
还有其他选项可用于不太准确的计数,但如果您想要准确,则其他选择很少,但我会尝试考虑一些:
您可以对数据进行分区,并在userCounter存储中按天计数。如果仅在当天添加数据,请执行select sum(dailycount) from counter
+ select count(*) from table where {date=today}
您至少可以使用nolock或readpast选项来减少资源使用:
的
select * from tbl with (readpast)
select * from tbl with (nolock)
答案 5 :(得分:1)
有些事情因性能原因而预先计算是有意义的(多年数据的复杂计算)。这就是为什么数据仓库在很多时候都存在加速报告的原因。如果您在表上有任何索引,则选择count(*)通常不是其中之一。还有更糟糕的性能问题需要解决。我得到1秒的时间将计数返回到一个有1300万行的表格上。
我所有关于编写代码的能力比替代方案更好(避免相关子查询,使用基于集合的operatiosn而不是游标,具有sargable where子句),但这是一个不应该的mirco优化解决,直到出现真正的性能问题。