我正在 another post 中阅读此讨论这个问题是由其他人提出的。在阅读讨论之前,我一直认为 SQL Server(和其他 DBMS)在元数据中的某个位置保留每个表的全局行数,但讨论似乎表明事实并非如此。为什么? Count(*)
(没有任何过滤)是一个如此常见的操作,如果它是 O(1),将会获得巨大的提升。即使不考虑 COUNT(*)
,表中的总行数也是一个基本信息。他们为什么不记录下来?
此外,为什么我们需要“加载”整行(如我链接的帖子中所示)只是为了对它们进行计数?索引或 PK 等不应该足以对它们进行计数吗?
最佳答案
不,COUNT(*)
不是恒定时间操作。 COUNT(*)
必须返回符合当前扫描谓词(即 WHERE
子句)的行数,这样就可以返回元数据属性无效的。但即使没有谓词,COUNT 仍然必须满足当前的事务隔离语义,即。返回可见行数(例如已提交)。因此,在 SQL Server 中,COUNT
必须并且将会实际扫描并计算行数。某些系统允许返回 faster 'estimate' counts .
此外,作为旁注,依赖 sys.partitions
中的行
是不可靠的。毕竟,如果这个计数能够保证准确,那么我们就不需要 DBCC UPDATEUSAGE(...) WITH COUNT_ROWS
。从历史上看,有几种情况会导致该计数器偏离现实(主要是最小记录的插入回滚),我所知道的一切都已修复,但这仍然留下了以下问题:1)从具有错误的早期版本升级的表和2 )其他尚未发现的错误。
In addition, why do we need to "load" entire rows (as indicated in the post I linked) just to count them? Shouldn't indexes or PKs etc. be sufficient to count them?
这并不是 100% 正确。至少有两种情况不会“加载整行”:
- 窄行存储索引仅加载“索引”行,该行可能要小得多
- 列存储数据仅加载相关的列段
我上面所说的大部分内容并不适用于 Hekaton 表。
关于sql - SQL Server 中的 COUNT(*) 是常数时间操作吗?如果没有,为什么不呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44158023/