不能直接用 count(*) 查分区表数据量,因为会锁表、耗资源、执行慢;应查数据字典 user_tab_partitions 与 user_segments 联查获取估算行数和空间占用,或用 sample block 快速采样计数。

查分区表数据量为什么不能直接用 COUNT(*)?
因为对大分区表全表扫描 COUNT(*) 会锁表、耗资源、执行慢,尤其在生产库上可能拖垮性能。Oracle 提供了更轻量的方式——查数据字典,它不触发实际扫描,而是读取统计信息或段级元数据。
USER_TAB_PARTITIONS 和 USER_SEGMENTS 怎么联查?
分区的数据量信息分散在两个视图:USER_TAB_PARTITIONS 存分区定义(如分区名、高水位键),USER_SEGMENTS 存每个分区对应的段大小(以块为单位)。真实行数得靠 NUM_ROWS 字段,但它依赖统计信息是否最新。
推荐组合查询:
SELECT p.partition_name, s.bytes / 1024 / 1024 AS mb, p.num_rows, p.last_analyzed FROM user_tab_partitions p JOIN user_segments s ON p.partition_name = s.partition_name AND s.segment_name = p.table_name WHERE p.table_name = '<code>YOUR_TABLE_NAME</code>' ORDER BY p.partition_name;
注意点:
-
NUM_ROWS是采样估算值,如果没执行过DBMS_STATS.GATHER_TABLE_STATS,可能为NULL或严重不准 -
BYTES是分配空间,不是实际使用量;空块、未格式化块都算在内 - 分区名大小写敏感,
USER_TAB_PARTITIONS.PARTITION_NAME默认大写
想看真实行数但又不想锁表怎么办?
用并行快速采样计数,比全表 COUNT(*) 快一个数量级,且不会长时间持有 DML 锁:
SELECT partition_name, COUNT(*) OVER (PARTITION BY partition_name) AS row_count FROM <code>YOUR_TABLE_NAME</code> PARTITION (<code>PART_NAME</code>) SAMPLE BLOCK (1);
关键控制点:
-
SAMPLE BLOCK (1)表示随机采样约 1% 的数据块,误差通常 - 必须显式指定分区名(如
PARTITION (P_2024)),不能直接在大表上跑SAMPLE(否则还是扫全表) - 若需更高精度,可升到
SAMPLE BLOCK (5),但耗时线性增长
分区数据倾斜怎么一眼识别?
光看单个分区数字意义不大,重点看分布差异。建议加一列标准差或相对偏差:
SELECT partition_name, num_rows, ROUND(100 * RATIO_TO_REPORT(num_rows) OVER(), 2) AS pct_of_total FROM user_tab_partitions WHERE table_name = '<code>YOUR_TABLE_NAME</code>' ORDER BY num_rows DESC;
这样能立刻发现:某个分区占了 80% 数据,而其他几十个分区加起来才 20% —— 这往往意味着分区键设计不合理,比如用了递增 ID 而非时间字段。
真正麻烦的是 NUM_ROWS 全为 NULL 且业务方催着要数——这时候别硬查,先确认统计信息状态:SELECT stale_stats FROM user_tab_statistics WHERE table_name = 'YOUR_TABLE_NAME';如果是 YES,直接 gather 比硬扫靠谱得多。











