oracle 索引失效

在 Oracle 11g 中,索引失效的常见原因包括函数修改列、隐式类型转换、统计信息过时等,解决方法需结合版本特性(如虚拟列、索引跳跃扫描)。通过执行计划分析、统计信息维护和合理使用提示(Hints),可有效优化索引使用。对于关键业务 SQL,建议定期监控并绑定执行计划(SQL Plan Management)

1. 索引列被函数或表达式修改

  • 原因 :对索引列使用函数或表达式(如 UPPER(column)column + 1)会导致索引无法匹配。

SELECT * FROM employees WHERE TO_CHAR(hire_date, 'YYYYMMDD') = '20231001';

解决方法

函数索引:为函数或表达式创建专用索引:

CREATE INDEX idx_hire_date_str ON employees(TO_CHAR(hire_date, 'YYYYMMDD'));

2. 复合索引未使用前导列

  • 原因 :复合索引 (col1, col2) 必须使用 col1 才能生效,否则可能失效。

  • Oracle 11g 优化 :支持 索引跳跃扫描(Index Skip Scan),即使未指定前导列,也可能通过跳跃扫描使用索引(但效率较低)。

-- 索引为 (department_id, employee_id)

SELECT * FROM employees WHERE employee_id = 100; -- 可能触发跳跃扫描

3. 隐式类型转换

  • 原因:查询条件与索引列数据类型不匹配(如字符串 vs 数字)。

-- 索引列 employee_id 是 NUMBER 类型

SELECT * FROM employees WHERE employee_id = '100'; -- 隐式转换为字符串

4. 统计信息过时

  • 原因:Oracle 优化器依赖统计信息计算成本,过时统计信息导致误判。
  • Oracle 11g 特性

    • 自动统计信息收集任务(GATHER_STATS_JOB)默认开启,但可能因业务负载被禁用。

    • 新增增量统计信息收集,适用于分区表。

解决方法

  • 手动收集统计信息:

EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT', tabname => 'EMPLOYEES', cascade => TRUE);

检查自动任务状态:

SELECT * FROM DBA_AUTOTASK_CLIENT WHERE TASK_NAME = 'auto optimizer stats collection';

5. 高比例数据返回

  • 原因:当查询返回超过约 15-20% 的数据时,优化器可能选择全表扫描。

  • 解决方法

使用 INDEX 提示强制使用索引(需谨慎):

SELECT /*+ INDEX(employees idx_salary) */ * FROM employees WHERE salary > 5000;

6. 使用 !=NOT IN 操作符

  • 原因:非等值查询可能导致优化器跳过索引。

SELECT * FROM employees WHERE status != 'ACTIVE';

解决方法

改写为 OR 条件或使用 INDEX_FFS(快速全索引扫描)

SELECT * FROM employees WHERE status = 'INACTIVE' OR status = 'PENDING';

7. 索引被标记为 UNUSABLE

  • 原因 :直接路径加载(如 INSERT /*+ APPEND */)或分区维护后,索引可能失效。

检查与修复

-- 检查索引状态

SELECT index_name, status FROM user_indexes WHERE table_name = 'EMPLOYEES';

-- 重建索引

ALTER INDEX idx_emp_name REBUILD;

8. LIKE 以通配符开头

  • 原因LIKE '%abc' 无法利用 B-Tree 索引。

解决方法

  • 反向键索引(Reverse Key Index)

CREATE INDEX idx_name_reverse ON employees(REVERSE(name));

SELECT * FROM employees WHERE REVERSE(name) LIKE REVERSE('%son');

9. OR 条件导致索引失效

  • 原因 :多个 OR 条件未命中联合索引时,触发全表扫描。

解决方法

SELECT * FROM employees WHERE dept_id = 10

UNION ALL

SELECT * FROM employees WHERE salary > 10000;

10. 参数设置影响索引选择

  • 关键参数

    • OPTIMIZER_INDEX_COST_ADJ:调整索引访问成本(默认 100),降低该值可能让优化器更倾向索引。

    • OPTIMIZER_INDEX_CACHING:影响嵌套循环连接中索引的缓存成本。

  • 操作建议

    • 非必要不要修改全局参数,可通过提示(Hint)临时调整

SELECT /*+ OPT_PARAM('optimizer_index_cost_adj', '50') */ * FROM employees WHERE ...;

11. 位图索引的并发问题

  • 原因:位图索引在并发 DML 时易被锁定,导致性能下降或失效。

  • Oracle 11g 优化:支持更多位图索引维护策略,但仍需谨慎使用。

  • 解决方法

    • 在高并发 OLTP 环境中避免使用位图索引。

    • 使用 B-Tree 索引替代。

12. 索引列允许 NULL 值

  • 原因 :B-Tree 索引不存储全 NULL 的条目,IS NULL 查询无法使用索引。

  • 解决方法

    • 创建函数索引:

CREATE INDEX idx_comm_null ON employees(NVL(commission_pct, -1));

SELECT * FROM employees WHERE NVL(commission_pct, -1) = -1;

Oracle 11g 特有工具与诊断方法

执行计划分析

EXPLAIN PLAN FOR [your_query];

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

SQL 调优顾问(SQL Tuning Advisor)

-- 生成调优任务

DECLARE

l_task VARCHAR2(64);

BEGIN

l_task := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_text => 'SELECT * FROM employees WHERE ...');

DBMS_SQLTUNE.EXECUTE_TUNING_TASK(l_task);

END;

/

-- 查看建议

SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK('task_name') FROM dual;

动态性能视图

  • V$SQL_PLAN:查看实际执行计划。

  • DBA_IND_STATISTICS:检查索引统计信息。

相关推荐
♡喜欢做梦1 小时前
【MySQL】深入浅出事务:保证数据一致性的核心武器
数据库·mysql
遇见你的雩风1 小时前
MySQL的认识与基本操作
数据库·mysql
dblens 数据库管理和开发工具2 小时前
MySQL新增字段DDL:锁表全解析、避坑指南与实战案例
数据库·mysql·dblens·dblens mysql·数据库连接管理
weixin_419658312 小时前
MySQL的基础操作
数据库·mysql
不辉放弃3 小时前
ZooKeeper 是什么?
数据库·大数据开发
Goona_3 小时前
拒绝SQL恐惧:用Python+pyqt打造任意Excel数据库查询系统
数据库·python·sql·excel·pyqt
程序员编程指南4 小时前
Qt 数据库连接池实现与管理
c语言·数据库·c++·qt·oracle
幼儿园老大*6 小时前
数据中心-时序数据库InfluxDB
数据库·时序数据库
daixin88486 小时前
Redis过期数据的删除策略是什么?有哪些?
数据库·redis·缓存
陪我一起学编程6 小时前
MySQL创建普通用户并为其分配相关权限的操作步骤
开发语言·数据库·后端·mysql·oracle