直接查 sys.indexes 无法得到准确行数,因为它不含 rows 字段;必须联合 sys.partitions 或 sys.dm_db_partition_stats 获取近似值,且需注意过滤条件与元数据刷新时机。

直接查 sys.indexes 无法得到准确行数——它本身不存 rows 字段,必须联合 sys.partitions 或 sys.dm_db_partition_stats 才能拿到近似值。
为什么不能只用 sys.indexes 查行数
sys.indexes 只描述索引结构(比如 type = 1 是聚集索引、type = 0 是堆),但它没有 rows 列。真正存行数元数据的是 sys.partitions 和 sys.dm_db_partition_stats。常见错误是写成:
SELECT t.name, i.rows FROM sys.tables t JOIN sys.indexes i ON t.object_id = i.object_id
这会报错:Invalid column name 'rows',因为 sys.indexes 根本没有这个字段。
sys.partitions 联合 sys.indexes 的正确写法
实际要用 sys.indexes 做过滤(只取主数据结构),再靠 sys.partitions 提供 rows:
- 必须加
p.index_id IN (0, 1):只取堆表(index_id = 0)或聚集索引(index_id = 1),跳过非聚集索引的重复计数 - 必须加
t.is_ms_shipped = 0:排除sys.objects这类系统表 - 推荐加
p.partition_number = 1:避免分区表被拆成多行(哪怕不分区也显式指定更稳妥)
完整查询示例:
SELECT t.name AS TableName, SUM(p.rows) AS RowCounts FROM sys.tables t JOIN sys.indexes i ON t.object_id = i.object_id JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id WHERE t.is_ms_shipped = 0 AND p.index_id IN (0, 1) AND p.partition_number = 1 GROUP BY t.name ORDER BY RowCounts DESC;
sys.dm_db_partition_stats 更轻量的替代方案
比 sys.partitions 更推荐用于单表查询,因为它自动按当前数据库上下文过滤,且不含内部对象干扰项:
- 用
OBJECT_ID('Orders')获取表 ID,但注意返回 NULL 时整个查询结果为空(不会报错) - 必须写
index_id (等价于IN (0, 1)),漏掉会导致非聚集索引行数被计入,结果虚高 - 对某张表查总行数,一行就够了:
sys.dm_db_partition_stats.rows
-
UPDATE STATISTICS dbo.Orders;—— 安全,默认采样更新 -
DBCC UPDATEUSAGE(0);—— 修复整个数据库的页和行计数,适合定期维护后执行 - 避免用
WITH ROWCOUNT = ...手动设值,除非你完全清楚后果
真正的坑不在 SQL 写法,而在于误把元数据当实时值——它只在重建索引、大批量 DML、统计更新后才变,日常增删不会触发刷新。










