oracle分区表数据倾斜是物理分布失衡而非统计偏差,需从存储层(dba_tab_partitions与dba_segments交叉验证)和访问层(v$pq_tqstat观察并行负载)双线排查,结合高基数字段验证与range-hash等组合策略按访问模式设计。

Oracle分区表数据倾斜不是统计信息不准导致的执行计划偏差,而是物理分布本身失衡——I/O、锁、并行任务全压在少数几个分区上,必须从存储层和访问模式双线排查。
查分区行数与物理空间是否匹配
只看 NUM_ROWS 会误判:它是采样估算值,不反映空洞、压缩或热点访问。真正有效的信号来自 DBA_TAB_PARTITIONS 和 DBA_SEGMENTS 的交叉比对。
- 执行以下查询,重点关注三类异常组合:
SELECT p.partition_name, p.num_rows, s.bytes/1024/1024 AS mb, ROUND(s.bytes / NULLIF(p.num_rows, 0), 2) AS avg_row_bytes FROM dba_tab_partitions p JOIN dba_segments s ON p.table_owner = s.owner AND p.table_name = s.segment_name AND p.partition_name = s.partition_name WHERE p.table_name = '<code>YOUR_TABLE</code>' AND p.table_owner = '<code>YOUR_SCHEMA</code>' ORDER BY p.num_rows DESC; -
num_rows高但mb低 → 可能存在大量空值或启用压缩,需查AVG_ROW_LEN和COMPRESSION -
mb高但num_rows低 → 极可能有大量DELETE留下的空洞,立刻检查DELETES和EMPTY_BLOCKS -
avg_row_bytes远高于表平均值 → 该分区存了大量 LOB 或长字符串,会加剧 buffer cache 压力
看实际运行时的并行负载是否失衡
数据量均衡 ≠ 流量均衡。一个分区即使行数中等,若被高频点查或作为连接驱动表,仍会成为瓶颈。物化视图刷新、大表 JOIN 或 GROUP BY 场景下,必须观察真实运行时各并行进程的处理量。
- 刷新或执行关键 SQL 期间,查
V$PQ_TQSTAT(需SELECT_CATALOG_ROLE):SELECT dfo_number, tq_id, server_type, num_rows, elapsed_time FROM V$PQ_TQSTAT WHERE dfo_number = (SELECT MAX(dfo_number) FROM V$PQ_TQSTAT) ORDER BY tq_id, server_type;
- 同一
tq_id下不同server_type的num_rows差异 >5 倍即属明显倾斜 - 若发现某几个
SERVER_TYPE = 'P00x'长时间卡在px server wait或enq: TX - row lock contention,基本可锁定是分区级 I/O 或锁热点
改分区策略前先验证字段基数
HASH 分区不能“一设就灵”,关键看分片键本身是否具备高基数且真实均匀。用低基数字段做 HASH 分区,只会让多个分区空转,热点照旧。
- 必须先查真实去重数:
SELECT COUNT(DISTINCT <code>your_partition_column</code>) FROM <code>YOUR_TABLE</code>;
- 若结果远小于预设分区数(如
COUNT(DISTINCT region_code)= 34,却建了 64 个 HASH 分区),HASH 无效 - 优先选
user_id、order_id、transaction_no这类全局唯一、随机生成的字段;避免用status、gender、is_deleted - 禁止对表达式建 HASH 分区,如
PARTITION BY HASH(UPPER(user_name))—— Oracle 不支持,且破坏散列均匀性
组合分区要按访问模式设计,不是套模板
RANGE-HASH 不是万能解药,滥用 LIST-HASH 反而白搭。组合分区的价值在于把生命周期管理(RANGE)和数据打散(HASH)解耦,必须贴合高频查询条件。
- 高频查询常带时间条件 + 用户 ID → 用
RANGE(order_date) SUBPARTITION BY HASH(user_id),每月主分区内部再分 8 子分区 - 若 LIST 键本身低基数(如
product_type IN ('A','B','C')),子分区再 HASH 也救不了整体倾斜 - DML 影响不可忽视:组合分区的
INSERT会多一层子分区路由开销,需实测吞吐变化;UPDATE若跨子分区,可能触发迁移
最易被忽略的一点:即使你把分区调得再均匀,如果业务写入始终集中在最新分区(比如新订单全落 order_date >= TRUNC(SYSDATE)),那个分区依然会是 I/O 和锁的单点。这时必须配合应用层限流、冷热分离归档,或引入时间+哈希二级路由,单纯靠 DB 层分区调整解决不了根因。











