我曾经读过一些文章,说当表有很多行和很多列时,SELECT COUNT(*) FROM TABLE_NAME将会很慢。

我有一个可能包含数十亿行的表(它大约有15列)。有没有更好的方法来获得一个表的行数的精确计数?

在回答之前请考虑以下问题:

我正在寻找一个数据库供应商 独立的解决方案。如果是也可以 涵盖MySQL, Oracle, MS SQL Server。 但如果真的没有数据库 供应商独立的解决方案,然后我 会接受不同的解决方案吗 针对不同的数据库供应商。 我不能使用任何外部工具 这样做。我主要是在找一个 基于SQL的解决方案。 我不能规范化我的数据库设计 任何进一步的。它已经在3NF中,而且 很多代码已经写好了 围绕它。


当前回答

PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'

其他回答

如果你正在使用Oracle,那么这个怎么样(假设表的统计信息更新了):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

Last_analyzed将显示上次收集统计数据的时间。

简单的回答是:

数据库供应商独立的解决方案=使用标准= COUNT(*) 有近似的SQL Server解决方案,但不要使用COUNT(*) =超出范围

注:

COUNT(1) = COUNT(*) = COUNT(主键)以防万一

编辑:

SQL Server示例(14亿行,12列)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1运行,5分46分钟,计数= 1,401,659,700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

2次,都在1秒内,计数= 1,401,659,670

第二个有较少的rows =错误。相同或更多取决于写入(这里的删除是按小时计算的)

为我准备了一张很大的桌子,

SELECT COUNT(1) FROM TableLarge 

花了37秒

SELECT COUNT_BIG(1) FROM TableLarge

只需要4秒钟。

如果你有一个典型的表结构,其中有一个自动递增的主键列,其中的行永远不会被删除,下面的方法将是确定记录计数的最快方法,并且应该在大多数ANSI兼容的数据库中类似地工作:

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

我使用的MS SQL表包含数十亿行,需要亚秒级的数据响应时间,包括记录计数。通过比较,类似的SELECT COUNT(*)将花费数分钟来处理。

这并不是一个与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语句中完成的。