哪些情况下不走索引
  • 全表扫描可能更优时
    • 当表中数据量较小时,全表扫描可能比使用索引更快。
    • 当查询结果占全表数据比例较高时(通常超过5%-20%)
  • 索引列未在查询中使用
    • 查询条件中未使用索引列,索引不会被使用。
  • 索引列被函数或表达式处理
    • 对索引列使用函数或表达式(如UPPER(column_name)等函数或者salary * 1.1 > 5000等表达式)会导致索引失效。解决方法:1.避免对索引列使用函数(重写查询条件,直接使用原始列。例如,将 TRUNC(date_col) = '2023-01-01' 改为 date_col BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59')2.创建函数索引 (可针对表达式创建函数索引。例如:CREATE INDEX idx_upper_name ON employees(UPPER(name));)
  • 隐式类型转换
    • 查询条件中索引列与比较值类型不一致时,Oracle可能进行隐式类型转换,导致索引失效。SELECT * FROM employees WHERE employee_id = '100'; -- employee_id 是数字类型,这里,employee_id是数字类型,而'100'是字符类型,Oracle会将'100'隐式转换为数字100。
  • 使用LIKE且通配符在前
    • 当使用LIKE进行模糊查询且通配符(如%或_)出现在字符串的开头时(例如LIKE '%value'),索引通常无法被使用
  • IS NULL或IS NOT NULL
    • 查询条件中使用IS NULL或IS NOT NULL时,索引通常不会被使用。 解决方法:反向索引、全文索引、函数索引等方式(详见blog)
  • 复合索引未使用前导列
    • 复合索引未按顺序使用前导列时,索引可能无法使用。组合索引为 (dept_id, job_id) ,SELECT * FROM employees WHERE job_id = 'DEV'; -- 未使用前导列dept_id,例外:Oracle支持**索引跳跃扫描(Index Skip Scan)**,但仅在某些条件下生效(如前导列重复值多)。
  • 分区表未使用分区键
    • 查询未使用分区键时,索引可能无法使用。
  • 若索引或表的统计信息未更新,优化器可能错误估算成本,选择全表扫描
  • 不等于操作符(`!=`、`<>`)或`NOT IN`、`NOT EXISTS`通常会导致全表扫描
    • **例外**:如果过滤后的数据量极小(如`WHERE id NOT IN (1)`且表中99%数据为1),可能走索引。
  • `OR`连接的多个条件若无法同时使用索引,可能导致全表扫描:
  • 强制全表扫描的HINT
    • (sql,SELECT /*+ FULL(employees) */ * FROM employees; -- 强制全表扫描)
  • 索引列选择性低(如性别列)时(索引列数据分布不均)
  • 索引失效时
  • 索引列存在大量NULL值
    • 若索引列包含大量NULL值,且查询条件是`IS NULL`,可能不走索引:SELECT * FROM tasks WHERE end_date IS NULL; -- 索引不存储NULL值(B-Tree索引),解决方法**: 使用位图索引(Bitmap Index)或添加`NVL`函数索引:sql CREATE INDEX tasks_null_idx ON tasks(NVL(end_date, SYSDATE));
  • IS NULL或IS NOT NULL
    • 索引可能无法使用
  • DISTINCT或ORDER BY或GROUP BY
    • 索引可能无法使用