我曾经读过一些文章,说当表有很多行和很多列时,SELECT COUNT(*) FROM TABLE_NAME将会很慢。
我有一个可能包含数十亿行的表(它大约有15列)。有没有更好的方法来获得一个表的行数的精确计数?
在回答之前请考虑以下问题:
我正在寻找一个数据库供应商
独立的解决方案。如果是也可以
涵盖MySQL, Oracle, MS SQL Server。
但如果真的没有数据库
供应商独立的解决方案,然后我
会接受不同的解决方案吗
针对不同的数据库供应商。
我不能使用任何外部工具
这样做。我主要是在找一个
基于SQL的解决方案。
我不能规范化我的数据库设计
任何进一步的。它已经在3NF中,而且
很多代码已经写好了
围绕它。
这并不是一个与dbms无关的解决方案,但至少您的客户端代码看不到区别……
创建另一个只有一行和一个整数字段N1的表T,并创建INSERT TRIGGER,只执行:
UPDATE T SET N = N + 1
还可以创建一个DELETE TRIGGER来执行:
UPDATE T SET N = N - 1
一个称职的DBMS将保证2以上操作的原子性,并且N将始终包含准确的行数,然后超级快速地简单地获得:
SELECT N FROM T
虽然触发器是特定于DBMS的,但从T中选择不是,并且您的客户端代码不需要为每个受支持的DBMS更改。
但是,如果表是INSERT或DELETE密集型的,这可能会有一些可伸缩性问题,特别是如果在INSERT/DELETE之后没有立即提交。
1这些名称只是占位符——在生产中使用更有意义的名称。
也就是说,N不能通过读和写N之间的并发事务来改变,只要读和写都是在一条SQL语句中完成的。
我找到了一篇很好的文章:SQL Server-HOW-TO:快速从martijnh1检索表的准确行数,它很好地概述了每个场景。
我需要在需要根据特定条件提供计数的地方进行扩展,当我计算出这一部分时,我会进一步更新这个答案。
与此同时,以下是文章中的细节:
方法1:
查询:
SELECT COUNT(*) FROM Transactions
评论:
执行全表扫描。在大桌子上慢点。
方法2:
查询:
SELECT CONVERT(bigint, rows)
FROM sysindexes
WHERE id = OBJECT_ID('Transactions')
AND indid < 2
评论:
快速检索行数的方法。取决于统计数据,不准确。
运行DBCC UPDATEUSAGE(数据库)WITH COUNT_ROWS,这对于大型表可能会花费大量时间。
方法3:
查询:
SELECT CAST(p.rows AS float)
FROM sys.tables AS tbl
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int)
AND p.index_id=idx.index_id
WHERE ((tbl.name=N'Transactions'
AND SCHEMA_NAME(tbl.schema_id)='dbo'))
评论:
SQL管理工作室计算行数的方法(查看表属性、存储、行数)。非常快,但仍然是大概的行数。
方法4:
查询:
SELECT SUM (row_count)
FROM sys.dm_db_partition_stats
WHERE object_id=OBJECT_ID('Transactions')
AND (index_id=0 or index_id=1);
评论:
操作快(虽然不如方法二快),同样重要的是,可靠。