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

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

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

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


当前回答

如果你正在使用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 =错误。相同或更多取决于写入(这里的删除是按小时计算的)

如果使用插入触发器代价太大,但可以使用删除触发器,并且有一个自动递增的id,那么在对整个表进行一次计数后,将计数记为last-count和last- counts -id,

然后每天只需要为id > last- counting -id计数,将其添加到last-count中,并存储新的last- counting -id。

如果被删除记录的id <= last-count -id,删除触发器将递减last-count。

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

这取决于数据库。有些方法可以加速计数,例如通过跟踪索引中的行是活的还是死的,从而允许只扫描索引来提取行数。其他的则不是,因此需要访问整个表并逐个计算活动行。对于一张大桌子来说,这两种方式都很慢。

请注意,您通常可以通过使用查询优化工具、表统计信息等提取一个良好的估计。例如,在PostgreSQL的例子中,你可以从你的表中解析explain count(*)的输出,并得到一个相当好的行数估计。这就引出了你的第二个问题。

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

严重吗?:-)你真的是指一个有数十亿行的表的精确计数吗?你真的确定吗?: -)

如果您真的这样做了,您可以使用触发器跟踪总数,但如果这样做了,请注意并发性和死锁。

如果SQL Server版本是2005/2008,您可以使用dmv来计算表中的行数:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 ddps.row_count 
FROM sys.indexes AS i 
 INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID 
 INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID 
 AND i.index_id = ddps.index_id 
WHERE i.index_id < 2 
 AND o.is_ms_shipped = 0 
ORDER BY o.NAME 

对于SQL Server 2000数据库引擎,sysindexes可以工作,但强烈建议避免在将来的SQL Server版本中使用它,因为它可能在不久的将来被删除。

示例代码摘自:如何快速轻松地获取表行计数

我不认为有一个通用的总是最快的解决方案:一些RDBMS/版本对SELECT COUNT(*)进行了特定的优化,使用更快的选项,而其他版本只是简单的表扫描。对于第二组,您需要访问文档/支持站点,这可能需要编写一些更具体的查询,通常是以某种方式命中索引的查询。

编辑:

Here's a thought that might work, depending on your schema and distribution of data: do you have an indexed column that references an increasing value, a numeric increasing ID, say, or even a timestamp or date? Then, assuming deletes don't happen, it should be possible to store the count up to some recent value (yesterday's date, highest ID value at some recent sample point) and add the count beyond that, which should resolve very quickly in the index. Very dependent on values and indices, of course, but applicable to pretty much any version of any DBMS.