不能只查NUM_ROWS判断分区倾斜,因其是采样估算值、不反映数据分布密度与空洞率、且无法体现热点key导致的I/O和CPU实际倾斜;须结合DBA_TAB_PARTITIONS、DBA_SEGMENTS及DBA_HIST_SQLSTAT等多视图交叉验证。
直接看 num_rows 不可靠,它只是采样估算值,且不区分分区,无法反映分区级倾斜。
为什么不能只查 NUM_ROWS 就判断分区倾斜
Oracle 的 NUM_ROWS 来自 DBA_TAB_PARTITIONS 或 USER_TAB_PARTITIONS,但它有三个硬伤:
- 它是
DBMS_STATS采样收集的统计信息,默认不保证精确,尤其对大表或未及时更新时误差可能达 20% 以上 - 该字段只记录每个分区的行数估算,不包含数据分布密度、空洞率、索引碎片等关键指标,单看数字无法判断是“真多”还是“假多”(比如大量 delete 后未 shrink)
- 即使各分区
NUM_ROWS相差不大,也可能因 热点 key 集中在某几个分区(如时间分区中最新分区承载 80% 写入),导致实际 I/O 和 CPU 倾斜,而NUM_ROWS完全不体现这种流量特征
必须结合 DBA_TAB_PARTITIONS + DBA_SEGMENTS 对比验证
真正有效的检查方式是交叉比对行数与物理存储,暴露“行多但空间小”或“空间大但行少”的异常信号:
- 执行查询:
YOUR_TABLE
- 重点关注三类异常组合:
-
num_rows高但mb低 → 可能存在大量空值或压缩,需查AVG_ROW_LEN和COMPRESSION -
mb高但num_rows低 → 极可能有大量DELETE留下的空洞,立刻检查DELETES和EMPTY_BLOCKS -
avg_row_bytes远高于表平均值 → 该分区存了大量 LOB 或长字符串,会加剧 buffer cache 压力
-
真正反映倾斜风险的是 DBA_HIST_SQLSTAT 中的分区访问模式
数据量均衡 ≠ 流量均衡。一个分区即使行数中等,若被高频点查或作为连接驱动表,仍会成为瓶颈:
- 用如下语句定位哪些分区被 SQL 实际访问最多:
SELECT p.partition_name, COUNT(*) AS exec_count FROM dba_hist_sql_plan hp JOIN dba_tab_partitions p ON hp.object_owner = p.table_owner AND hp.object_name = p.table_name AND hp.partition_start = p.partition_name WHERE hp.sql_id IN ( SELECT sql_id FROM dba_hist_sqlstat WHERE plan_hash_value != 0 AND last_active_time > SYSDATE - 1 ) GROUP BY p.partition_name ORDER BY exec_count DESC;
- 注意:
partition_start字段在执行计划中仅当 Oracle 明确做了分区裁剪(Partition Pruning)才会填充,如果为空,说明该 SQL 没走分区裁剪,整表扫描 —— 这本身就是一种隐性倾斜 - 配合
V$SQL_PLAN_MONITOR查实时执行中的STARTS和OUTPUT_ROWS,比历史统计更准
最常被忽略的一点:NUM_ROWS 倾斜只是表象,真正要盯的是 DBA_TAB_MODIFICATIONS 里各分区的 INSERTS/UPDATES/DELETES 累计值 —— 它们直接决定后续统计信息是否失真,以及是否触发自动收缩或合并分区动作。











