分区裁剪在多表连接中不会自动“传染”,关键取决于连接条件能否让优化器推导出分区边界;若ON条件中对分区键使用函数、类型不一致或字段名不同,即使逻辑等价,也会导致裁剪失效。
分区裁剪在多表连接中不会自动“传染”——即使一张表成功裁剪,另一张表若没参与裁剪逻辑,整个连接仍可能扫全量数据。关键不是“有没有分区”,而是“连接条件是否让优化器能推导出分区边界”。
为什么 ON 条件写对了还是没裁剪?
常见错误是把分区键当成普通字段用:比如两张表都按 order_date RANGE 分区,但连接写成 t1.order_date = TRUNC(t2.order_date)。函数包裹直接让 t2.order_date 失去分区键语义,t2 无法裁剪。
- 确保两边都是裸列:
t1.order_date = t2.order_date,不加任何函数、类型转换或表达式 - 检查字段名是否完全一致:
t1.dt和t2.order_date即使值相同,也不会触发裁剪 - 确认数据类型严格匹配:
DATEvsTIMESTAMP隐式转换会中断裁剪链 - 避免在连接字段上建函数索引(如
CREATE INDEX idx ON t2(TRUNC(order_date))),这会让优化器放弃原生分区识别
如何验证连接时真正发生了分区裁剪?
光看执行计划里有没有 PARTITION RANGE 不够,得盯住三处:
-
PARTITION RANGE SINGLE或ITERATOR:前者表示精准定位单一分区,后者往往意味着裁剪失败或动态范围未定 -
ACCESS PREDICATES中是否含分区键谓词,例如access("T1"."ORDER_DATE"=TO_DATE(' 2024-05-20 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) -
STARTS值:如果t2有 64 个分区,但STARTS = 1,说明只启动了 1 个分区扫描;若STARTS = 64,哪怕写了等值连接,实际仍是全分区扫
小表也分区时,怎么避免“假裁剪”?
小表不分区时,大表分区连接常退化为 Broadcast Join;但小表强行分区后,若分区数太少或边界不对齐,Oracle 可能走 Partial Partition-Wise Join——看着像裁剪,实则每个大表分区仍要跟所有小表分区做连接。
- 小表分区数 ≥ 大表分区数 × 并行度(例如大表 12 分区、并行度 4,则小表至少需 48 分区)
- 必须使用相同分区策略+相同分区键+完全一致的边界定义(不能一个用
VALUES LESS THAN (DATE '2024-01-01'),另一个用VALUES LESS THAN (TO_DATE('2024-01-01','YYYY-MM-DD'))) - 运行
DBMS_STATS.GATHER_TABLE_STATS时带上granularity => 'ALL',否则分区级统计为空,优化器不敢信任裁剪结果
最容易被忽略的是统计信息粒度和分区边界表达式的字面一致性——它们不报错,但会让裁剪在执行计划里“静默失效”。别只盯着 SQL 写法,执行前务必查 DBA_TAB_PARTITIONS.NUM_ROWS 是否非空,再比对两个表的 HIGH_VALUE 字符串是否逐字相等。


















