sql - SQL Server 中的 COUNT(*) 是常数时间操作吗?如果没有,为什么不呢?

标签 sql sql-server count

我正在 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/

相关文章:

mysql - 如何创建枢轴以避免 ID 重复?

sql-server - 旋转 SPLIT_STRING 的结果?

sql - 构建不包含基于层次结构的数据的 SQL 查询

mysql - 如何使用 MySQL 以三列为一组检索最新的对?

Swift NSHTTPCookieStorage 计数 :2

java - 在 Java 中使用正则表达式获取 n 个单词

sql - Firebird Cursors - 你为什么要使用一个

sql - 查找引用某个表中特定列的所有存储过程

sql - MS SQL 到 MySQL

sql-server - 在 SQL Server 中将列类型从 TinyInt 转换为 Int