执行计划中未出现PARTITION START/STOP即表示分区裁剪失效,说明Oracle正全分区扫描;需通过EXPLAIN PLAN验证,重点检查PARTITION RANGE SINGLE/ITERATOR是否存在,若为PARTITION RANGE ALL则明确失效。

执行计划里没出现 PARTITION START/STOP 就说明裁剪失效
分区裁剪是否起作用,不看 SQL 写得多漂亮,只看执行计划里有没有 PARTITION START 和 PARTITION STOP 这两行。没有?那 Oracle 正在全分区扫描,和没分区一样。
检查方式固定:先跑 EXPLAIN PLAN FOR SELECT ...,再查 SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)。重点盯 OPERATION 列是否含 PARTITION RANGE SINGLE 或 PARTITION RANGE ITERATOR;若看到 PARTITION RANGE ALL,就是明确的失效信号。
常见误判点:
- 执行计划里有
PARTITION字样 ≠ 裁剪生效(比如PARTITION LIST ALL是反例) -
OBJECT_NAME显示的是物化视图名,但PARTITION_START是KEY—— 说明重写发生了,但分区键没被识别 - 用了绑定变量却没开
bind_aware,硬解析时计划已定,后续值再合适也白搭
WHERE 条件里对分区键用了函数或类型转换
这是 Java 应用里最高频的坑。Oracle 优化器需要静态推导分区边界,一旦分区键被包装,就失去确定性。
以下写法直接阻断裁剪:
-
WHERE TRUNC(create_date) = DATE '2024-01-01'→ 函数包裹 -
WHERE create_date = '2024-01-01'→ 字符串字面量触发隐式转换(字段是DATE) -
WHERE create_date BETWEEN TO_DATE(?, 'YYYY-MM-DD') AND ...→ 绑定变量 + 函数
Java 中必须用类型匹配的 setter:
- 字段是
DATE→ 用setDate(),不是setString() - 字段是
TIMESTAMP→ 用setTimestamp(),传java.time.LocalDateTime需转为java.sql.Timestamp - DAO 层可加校验:对日期型分区键参数强制要求非字符串类型入参
物化视图查询重写失败导致分区裁剪不触发
你以为在查物化视图,其实优化器根本没走它——因为查询重写没发生。这时候分区裁剪无从谈起。
诊断步骤:
- 运行
DBMS_MVIEW.EXPLAIN_REWRITE,查REWRITE_MECHANISM是否为NO_REWRITE,MESSAGE是否含partition key not used - 确认物化视图 DDL 中的分区键列名与查询中 WHERE 的列名**完全一致**(大小写、引号、别名都不行)
- 禁用所有对分区键的处理:
NVL(dt, sysdate)、COALESCE(dt, ...)、TRUNC(dt)全部不行 - 临时设
QUERY_REWRITE_INTEGRITY=STALE_TOLERATED排除因 MV 状态为STALE导致的静默跳过
注意:QUERY_REWRITE_INTEGRITY=TRUSTED 能强制重写,但会绕过一致性校验,生产环境慎用。
本地索引未维护或状态为 UNUSABLE
删分区后查询变慢、报 ORA-01502,大概率是索引失效了。特别是唯一索引(UNIQUENESS = UNIQUE),DROP PARTITION 或 TRUNCATE PARTITION 后不会自动重建对应索引分区,状态直接变成 UNUSABLE。
验证命令:
SELECT index_name, status, uniqueness FROM all_indexes WHERE table_name = 'YOUR_TABLE';
修复方式:
- 重建整个索引:
ALTER INDEX idx_name REBUILD - 只重建失效分区:
ALTER INDEX idx_name REBUILD PARTITION p_202401 - 建索引时就用
LOCAL关键字,避免全局索引在分区变更时连锁失效
真正麻烦的是:失效可能不立刻暴露。业务流量低时查得慢,高峰一来直接超时——这种延迟显现的问题最易被忽略。


















