全分区匹配指两张表分区结构完全对齐(同列、同策略、边界一致),JOIN时各分区仅与对应分区连接;部分分区匹配则因分区列不同、边界不齐或仅一表分区,导致只能局部利用分区信息,如大表分片扫描而小表全局广播。
什么是 Partition-Wise Join 的“全分区匹配”和“部分分区匹配”
partition-wise join(pwj)不是自动开启的魔法开关,它依赖两张表的分区结构是否对齐、连接键是否与分区键一致。全分区匹配指两张表按相同列、相同分区策略(比如都按 sales_date range 分区且分区边界完全一致),join 时每个分区只跟对应分区做连接;部分分区匹配则是只有一张表分区,或两张表分区列不同、边界不齐——此时 oracle 只能局部利用分区信息,比如把大表按分区切开后,小表仍需全局扫描或广播。
怎么判断执行计划里是不是真用了全分区匹配
别光看 Plan 中有没有 PARTITION LIST ALL 或 JOIN FILTER CREATE,关键要看 ACCESS PREDICATES 和 FILTER PREDICATES 是否包含分区裁剪条件,以及每行的 STARTS 值是否等于实际参与连接的分区数。常见错误是:明明两张表都按 region_id HASH 分区,但 JOIN 条件写成 t1.region_code = t2.region_code(字段名不一致),导致无法对齐,执行计划里 STARTS 显示 64,但实际每个子操作都扫了全部 64 个分区。
- 检查
DBMS_XPLAN.DISPLAY_CURSOR输出中,JOIN 行的PARTITION RANGE是否为ITERATOR(通常表示动态裁剪失败) - 确认两表的分区键表达式完全等价:不能一个用
TRUNC(order_time),另一个用order_date,即使值相同也不匹配 - 注意分区类型兼容性:RANGE + RANGE 可能对齐,但 RANGE + LIST 或 HASH + RANGE 永远不会触发全分区匹配
为什么加了分区还是没走 Partition-Wise Join
最常踩的坑是统计信息过期或缺失。Oracle 在生成执行计划时,如果某张表没有准确的分区级行数(DBA_TAB_PARTITIONS.NUM_ROWS 为空或为 0),优化器会退化为传统连接方式,哪怕 DDL 完全对齐。另一个隐蔽问题是并行度设置:若 PARALLEL 提示只加在主查询,没显式指定子查询并行,或者目标分区数小于并行度,系统可能放弃 PWJ 转而用 Broadcast Join。
- 运行
DBMS_STATS.GATHER_TABLE_STATS时务必带上cascade => TRUE和granularity => 'ALL' - 避免在连接字段上使用函数或隐式转换,例如
TO_CHAR(t1.dt, 'YYYYMMDD') = t2.yyyymmdd会阻断分区键识别 - 当小表也分区时,确保其分区数 ≥ 大表分区数 × 并行度,否则容易触发 “partial partition-wise join” 而非 full
部分分区匹配下还能优化吗
可以,但思路要变:不再指望“每个分区独立连接”,而是聚焦于减少跨分区数据搬运。典型做法是用 JOIN FILTER 配合 Bloom Filter,在大表分区扫描前先预判哪些分区可能命中小表数据。但这要求小表足够小(一般
- 启用前确认参数:
_bloom_pruning_enabled = TRUE(11gR2+ 默认开),但需搭配OPTIMIZER_FEATURES_ENABLE >= '11.2.0.2' - 小表若含大量 NULL 值,Bloom Filter 效果急剧下降,此时手动加
WHERE col IS NOT NULL过滤更稳 - 部分匹配场景下,
/*+ USE_HASH(t1 t2) PQ_DISTRIBUTE(t2, NONE, BROADCAST) */往往比默认计划更可控
分区对齐只是前提,真正决定能否走全分区匹配的是优化器看到的统计信息质量、连接谓词的确定性、以及并行资源的实际可用性——这三个地方出一点偏差,就退回传统连接,而且往往不报错、不警告,只悄悄变慢。











