根本原因是WHERE条件对分区键做函数处理或隐式转换导致优化器无法静态推导分区边界,正确写法需直接等值或范围比较分区键,错误写法包括TRUNC(dt)、字符串与DATE隐式转换等。
根本原因不是分区建得不对,而是查询条件没让优化器“看懂”该扫哪个分区——只要where里对分区键做了任何加工,裁剪就大概率失效。
这是最常见、最隐蔽的失效点。优化器无法从TRUNC(dt)、TO_CHAR(dt, 'YYYYMM')或dt = '2026-06-01'(dt是DATE,字面量是字符串)这类写法里静态推导出分区边界。
WHERE dt = DATE '2026-06-01'、WHERE dt BETWEEN DATE '2026-06-01' AND DATE '2026-06-30'
WHERE TRUNC(dt) = DATE '2026-06-01'、WHERE dt >= '2026-06-01'(触发隐式TO_DATE())、WHERE NVL(dt, DATE '1900-01-01') = ...
PARTITION START和PARTITION STOP显示KEY或ALL,基本可断定裁剪未生效优化器只在能静态确认结果集落在哪些分区时才下推裁剪。一旦分区键出现在子查询内部、ON条件里,或依赖运行时值,裁剪上下文就断了。
SELECT * FROM sales s JOIN (SELECT dt, SUM(amt) FROM log GROUP BY dt) l ON s.dt = l.dt WHERE s.dt = '2026-06-01' —— 这里s.dt虽在外层WHERE,但若sales是大分区表且log子查询未限定dt,驱动顺序可能导致全扫WHERE s.dt IN (SELECT dt FROM calendar WHERE is_holiday = 'N') —— 即使calendar很小,子查询结果不可静态枚举,裁剪放弃物化视图本身不自动继承裁剪能力;本地索引若分区定义与基表不一致,也会导致回表时跨分区随机I/O,间接掩盖裁剪效果。
WHERE必须直接作用于其**实际存在的分区列**,如mv_summary.dt,而非基表列或表达式列CREATE INDEX idx_dt ON t(dt) LOCAL PARTITION BY RANGE (TRUNC(dt, 'MM')),否则USER_IND_PARTITIONS.HIGH_VALUE与USER_TAB_PARTITIONS.HIGH_VALUE不一致,裁剪后仍需跨分区取数据SELECT STALE_STATS FROM USER_TAB_STATISTICS WHERE TABLE_NAME = 'YOUR_TABLE',返回YES需立即刷新真正关键的验证动作不是看SQL“长得像不像能裁剪”,而是查DBMS_XPLAN.DISPLAY_CURSOR输出里的PARTITION START/PARTITION STOP字段是否为具体数字,以及A-Rows是否远小于E-Rows——后者常意味着运行时才定位分区,计划阶段已失焦。