Oracle Jonathan Lewis 索引策略深度

Oracle Jonathan Lewis 索引策略深度

来源:Jonathan Lewis / jonathanlewis.wordpress.com 适用版本:Oracle Database 8i+ 文档版本:v1.0 / 2026-07-22


1. 概述

Jonathan Lewis 对索引策略有深度分析[1]。

详细见:Oracle AskTOM-索引策略问答


2. 索引基础

2.1 B-Tree 结构

- Root
- Branch
- Leaf
- 行数据(ROWID)

2.2 访问路径

- INDEX UNIQUE SCAN
- INDEX RANGE SCAN
- INDEX FAST FULL SCAN
- INDEX FULL SCAN
- INDEX SKIP SCAN

2.3 Jonathan 观点

- 索引是双刃剑
- 加速查询,减慢 DML
- 平衡

3. B-Tree 索引

3.1 结构

- Root → Branch → Leaf
- Leaf 存储 (key, ROWID)
- 有序

3.2 高度

- blevel = height - 1
- 0:Root+Leaf
- 1:1 Branch
- 2+:多 Branch

3.3 I/O

- 访问次数 = blevel + 1 + 表访问
- blevel 小好

4. 复合索引

4.1 列顺序

- 等值列在前
- 范围列在后
- 选择性高的在前
- 或查询模式

4.2 Jonathan 规则

- 等值优先
- 范围在后
- 评估业务查询

4.3 示例

-- 查询:WHERE deptno=10 AND salary>5000
CREATE INDEX idx_emp ON emp(deptno, salary);
-- 好:deptno 等值在前,salary 范围在后

5. 覆盖索引

5.1 原理

- 索引包含所有查询列
- 避免 TABLE ACCESS
- 性能提升

5.2 示例

-- 查询:SELECT deptno, ename FROM emp WHERE id=10
CREATE INDEX idx_emp_cover ON emp(id, deptno, ename);
-- 索引覆盖,无需回表

5.3 Jonathan 观点

- 覆盖索引性能好
- 但 DML 代价
- 评估

6. 跳跃扫描

6.1 INDEX SKIP SCAN

- 复合索引第一列未查
- CBO 跳跃
- 适合低基数第一列

6.2 示例

-- 索引 (gender, id)
SELECT * FROM emp WHERE id=10;
-- CBO 可能 SKIP SCAN

6.3 Jonathan 分析

- 第一列低基数
- SKIP SCAN 有效
- 评估

7. 反向键索引

7.1 原理

- 反转键值
- 分散热点
- RAC 友好

7.2 创建

CREATE INDEX idx_emp_rev ON emp(id) REVERSE;

7.3 限制

- 不支持范围查询
- 仅等值
- 评估

7.4 Jonathan 建议

- 顺序插入热点
- RAC 块争用
- 评估

8. 函数索引

8.1 原理

- 函数结果索引
- 避免计算

8.2 创建

CREATE INDEX idx_upper_ename ON emp(UPPER(ename));

8.3 查询

SELECT * FROM emp WHERE UPPER(ename) = 'ALICE';

8.4 Jonathan 观点

- 大小写不敏感
- 计算列
- 优化

9. 位图索引

9.1 适用

- 低基数列
- 数据仓库
- 不适合 OLTP

9.2 创建

CREATE BITMAP INDEX idx_emp_gender ON emp(gender);

9.3 优势

- 低基数高效
- AND/OR 高效
- 空间小

9.4 Jonathan 警告

- OLTP 死锁风险
- DML 代价大
- 评估

10. IOT(索引组织表)

10.1 原理

- 表存储在索引中
- 主键查询高效
- 节省空间

10.2 创建

CREATE TABLE emp (
  id NUMBER PRIMARY KEY,
  name VARCHAR2(100)
) ORGANIZATION INDEX;

10.3 Jonathan 应用

- 主键查询为主
- 减少回表
- 评估

11. Clustering Factor 优化

11.1 问题

- CF 接近行数
- 索引低效

11.2 优化

- 重建表(按索引列排序)
- IOT
- 评估

11.3 Jonathan 方法

-- 重建
CREATE TABLE emp_new AS 
SELECT * FROM emp ORDER BY deptno;
DROP TABLE emp;
RENAME emp_new TO emp;
-- 重建索引

12. 索引监控

12.1 使用监控

ALTER INDEX emp_idx MONITORING USAGE;
SELECT * FROM v$object_usage;

12.2 未使用索引

SELECT * FROM v$object_usage WHERE used='NO';

12.3 Jonathan 建议

- 监控一段时间
- 删除未使用
- 减少 DML 代价

13. 索引重建

13.1 评估

ANALYZE INDEX emp_idx VALIDATE STRUCTURE;
SELECT name, del_lf_rows, lf_rows FROM index_stats;

13.2 重建

ALTER INDEX emp_idx REBUILD ONLINE;

13.3 Jonathan 观点

- 不要定期重建
- 碎片严重才重建
- ONLINE

14. 不可见索引

14.1 创建

CREATE INDEX idx_test ON emp(salary) INVISIBLE;

14.2 测试

ALTER SESSION SET optimizer_use_invisible_indexes=true;

14.3 Jonathan 用途

- 测试索引影响
- 评估
- 删除或启用

15. 最佳实践

  1. 按查询设计:索引
  2. 复合索引:列顺序
  3. 覆盖索引:优化
  4. CF:优化
  5. 监控:使用率
  6. 删除未使用:减少 DML
  7. 不要过度:平衡
  8. 重建:评估
  9. 统计信息:收集
  10. 测试:性能

16. 参考资料

[1] Jonathan Lewis, “Indexing Strategies”, https://jonathanlewis.wordpress.com [2] Jonathan Lewis, “Cost-Based Oracle Fundamentals”, Apress