局部索引不走,首要确认where是否包含分区键;若缺失分区键或对其使用函数、隐式转换,将导致分区裁剪失效,执行计划中无partition range即表明局部索引未被启用。
局部索引不走,先确认 where 是否包含分区键
oracle 局部索引(local index)只在查询条件中明确包含分区键(partition key)且能精确裁剪到单个或部分分区时,才可能被使用。如果 where 子句里压根没出现分区键列,优化器会直接跳过所有局部索引,转而选择全表扫描或全局索引(如果存在)。这不是 bug,是设计逻辑:局部索引的物理结构按分区隔离,没有分区键就无法定位该查哪个分区的索引段。
- 典型失效场景:
SELECT * FROM sales WHERE product_id = 1001—— 假设sales按sale_date分区,但查询没提sale_date,哪怕product_id上有局部索引,也不会用 - 必须显式写出分区键:例如
WHERE sale_date >= DATE '2025-01-01' AND product_id = 1001,才能触发分区裁剪(partition pruning),进而启用对应分区的局部索引 - 注意隐式转换风险:若分区键是
DATE类型,但传入字符串(如'2025-01-01'),Oracle 可能执行TO_DATE隐式转换,导致分区裁剪失败 —— 执行计划中会出现filter而非access,这是关键信号
分区键上用了函数或表达式,局部索引就废了
局部索引依赖优化器准确识别“哪些分区需要访问”,一旦对分区键列做了任何计算、函数包装或类型转换,分区裁剪就会失效,整个局部索引链路中断。
- ❌ 失效写法:
WHERE TRUNC(sale_date) = DATE '2025-01-01'、WHERE sale_date + 1 > SYSDATE、WHERE sale_date = TO_DATE('2025-01-01', 'yyyy-mm-dd') - ✅ 安全写法:直接比较原生值,用范围或等值:
WHERE sale_date BETWEEN DATE '2025-01-01' AND DATE '2025-01-31'或WHERE sale_date = DATE '2025-01-01' - 若业务真需函数语义(如“按年月汇总”),不要在 WHERE 里对分区键函数化;改用预计算字段+局部索引,或建函数索引但放弃分区裁剪(此时不如用全局索引)
执行计划里看不到 PARTITION RANGE,说明分区裁剪已失败
判断局部索引是否生效,最直接的方式是看 EXPLAIN PLAN 输出中是否有 PARTITION RANGE 操作符。没有它,意味着优化器连分区都没能锁定,局部索引自然不会参与。
- 运行:
EXPLAIN PLAN FOR SELECT * FROM sales WHERE sale_date = DATE '2025-01-01' AND product_id = 1001;,再查SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); - 健康信号:执行计划中出现
PARTITION RANGE SINGLE或PARTITION RANGE ITERATOR,且下层操作是INDEX RANGE SCAN - 危险信号:出现
PARTITION RANGE ALL(扫全部分区)、FILTER(运行时裁剪)、或干脆只有TABLE ACCESS FULL—— 此时局部索引形同虚设 - 特别注意:
DBA_TAB_PARTITIONS中HIGH_VALUE的实际值可能和直觉不符(比如是VALUES LESS THAN (TIMESTAMP'...')),务必用DBMS_STATS.LOCK_TABLE_STATS确保统计信息最新,否则裁剪估算也会出错
局部索引失效时,别急着重建,先看是否该用全局索引
局部索引不是万能的。当查询模式长期绕过分区键(比如大量按 product_id 或 customer_id 查询),强行依赖局部索引只会让性能更差 —— 因为它被迫扫多个分区的索引段,还无法利用跨分区有序性。
- 适合局部索引的场景:查询带分区键过滤、数据生命周期管理(如按时间自动删旧分区)、高并发写入需减少索引争用
- 适合全局索引的场景:高频非分区键查询、唯一约束需跨分区保证、OLTP 中主键/外键关联频繁
- 混合策略可行:
product_id建全局唯一索引 +sale_date建局部索引,由优化器按谓词自动选;但要注意全局索引维护成本(DML 时需更新所有分区) - 重建局部索引(
ALTER INDEX ... REBUILD PARTITION)只解决索引损坏或碎片问题,不修复逻辑层面的裁剪失效
局部索引是否生效,本质是分区裁剪能否成立;而裁剪成立的前提,是分区键以原始、未变换、类型匹配的方式出现在 WHERE 条件中 —— 这一点比索引本身是否 valid 更关键。











