查 sys.partitions 比 COUNT() 快,因其 rows 是元数据中维护的近似行数,无需扫描数据页;而 COUNT() 需全表或索引扫描,大表耗时显著。该值非实时精确,仅在统计更新、索引重建等操作后刷新,适合趋势分析而非一致性校验。

为什么查 sys.partitions 比 COUNT(*) 快
因为 sys.partitions.rows 是 SQL Server 维护的近似行数,来自元数据,不触发实际数据扫描。而 COUNT(*) 在大表上会走全表或最小索引扫描——哪怕有聚集索引,也要读取所有叶子页。对千万级以上表,前者毫秒级返回,后者可能耗时数秒甚至分钟。
但要注意:这个值不是实时精确值。SQL Server 只在统计信息更新、重建索引、大批量插入/删除后才刷新它;日常 DML 不会即时同步。所以它适合“看趋势”“排优先级”,不适合做数据一致性校验。
sys.partitions 查询必须加的过滤条件
直接查 sys.partitions 会混入系统表、内部对象、非主分区等干扰项。以下三个条件缺一不可:
-
t.is_ms_shipped = 0:排除 SQL Server 自带的系统表(如sys.objects) -
p.index_id IN (0, 1):只取堆表(index_id = 0)或聚集索引(index_id = 1)的行数;跳过非聚集索引(index_id > 1),它们的rows是重复计数 -
p.partition_number = 1(可选但推荐):避免多分区表中同一张表被拆成多行输出;绝大多数用户表不分区,但显式指定更稳妥
单表行数查询:用 OBJECT_ID() + sys.dm_db_partition_stats
查某张具体表(比如 Orders)时,推荐用动态管理视图 sys.dm_db_partition_stats,它比 sys.partitions 更轻量,且自动按数据库上下文过滤:
SELECT SUM(row_count) AS TotalRows
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('Orders')
AND index_id <p>注意:<code>index_id 等价于 <code>IN (0,1)</code>,语义更紧凑;<code>OBJECT_ID()</code> 返回 <code>NULL</code> 时整个查询结果为空,不会报错,适合嵌入脚本。</code></p><p>常见错误是漏写 <code>WHERE index_id ,导致把非聚集索引的行数也加进来,结果翻倍甚至更高。</code></p><h3>总行数不准?检查统计信息是否过期</h3><p>如果发现 <code>sys.partitions.rows</code> 和 <code>COUNT(*)</code> 差异很大(比如差 5% 以上),大概率是统计信息没更新。执行以下任一操作即可刷新:</p>
-
UPDATE STATISTICS dbo.YourTable WITH ROWCOUNT = 12345678;(手动设值,慎用) -
UPDATE STATISTICS dbo.YourTable;(默认采样,安全) -
DBCC UPDATEUSAGE(0);(修复整个数据库的页和行计数,适合 DBA 定期维护)
特别提醒:sys.dm_db_partition_stats 的 row_count 字段本身不缓存,每次查询都实时读取内存中的最新值,但它依赖底层统计信息的准确性——所以根源还在统计信息是否 fresh。










