SQL 索引优化

索引优化是 SQL 优化中最有效、性价比最高的技术手段,正确的索引设计能将 SQL 执行速度提升 10-1000 倍。它的核心本质是用空间换时间,通过构建有序的数据结构,将全表扫描的 O (n) 时间复杂度降低为索引扫描的 O (log n)。

1、索引基础

1.1、什么是索引

索引是一种与表关联的可选数据库对象,它存储了表中一列或多列的值以及对应的行物理地址(ROWID),能够快速定位到满足条件的数据行,而无需扫描整个表。

简单理解:索引就像书的目录,通过目录可以快速找到章节内容,而不需要逐页翻阅整本书。

1.2、索引的核心作用

  • 加速查询:大幅减少数据访问量,提高 SELECT、UPDATE、DELETE 语句的执行速度
  • 加速排序和分组:如果 ORDER BY/GROUP BY 的列有索引,Oracle 可以直接使用索引的有序性,避免排序操作
  • 保证数据唯一性:唯一索引可以确保列值不重复
  • 加速表连接:连接列上的索引可以大幅提升多表连接性能

1.3、索引的开销

索引会带来以下开销:

  • 存储开销:索引需要占用额外的磁盘空间(通常为表大小的 10%-30%)
  • 写入开销:INSERT/UPDATE/DELETE 操作会同时更新所有相关索引,降低写入性能
  • 维护开销:索引会产生碎片,需要定期重建或合并

索引是一把双刃剑,只在必要的列上创建索引,避免过度索引。

2、索引类型

2.1、B 树索引(默认索引)

  • 特点:最通用的索引类型,支持等值查询、范围查询、排序和分组
  • 适用场景:高基数列(不同值多的列,如员工号、订单号)、OLTP 系统
  • 不适用场景:低基数列(如性别、状态)、频繁更新的列
  • 创建语法:CREATE INDEX idx_emp_ename ON emp(ename);

2.2、唯一索引

  • 特点:确保索引列的值唯一,主键约束会自动创建唯一索引
  • 适用场景:主键、唯一键列
  • 性能优势:查询时找到第一个匹配项就停止,比普通索引更快
  • 创建语法:CREATE UNIQUE INDEX idx_emp_empno ON emp(empno);

2.3、复合索引(组合索引)

  • 特点:基于多个列创建的索引,是生产环境中最常用的索引类型
  • 核心原则:等值查询列在前,范围查询列在后,过滤性好的列在前
  • 前缀性原则:只有查询条件包含索引的前导列时,才能使用该索引
  • 创建语法:CREATE INDEX idx_emp_deptno_sal ON emp(deptno, sal);

2.4、函数索引

  • 特点:基于列的函数或表达式创建的索引,解决 "索引列上使用函数导致索引失效" 的问题
  • 适用场景:查询中经常对列使用函数或表达式
  • 创建语法
    • 解决WHERE UPPER(ename)='SMITH'索引失效问题
    • CREATE INDEX idx_emp_upper_ename ON emp(UPPER(ename));

2.5、位图索引

  • 特点:使用位图存储索引信息,每个位代表一行数据是否包含该键值
  • 适用场景:低基数列(如性别、状态)、数据仓库、只读表、批量更新
  • 不适用场景:高并发 OLTP 系统、频繁更新的列
  • 创建语法:CREATE BITMAP INDEX idx_emp_gender ON emp(gender);

2.6、反向键索引

  • 特点:将索引键值的字节顺序反转,解决 "索引热点块" 问题
  • 适用场景:序列生成的主键列(如订单号、用户 ID),这些列的值是连续递增的,会导致索引的右侧叶子节点成为热点
  • 创建语法:CREATE INDEX idx_orders_order_id ON orders(order_id) REVERSE;

2.7、分区索引

  • 特点:与分区表配合使用,每个分区对应一个独立的索引分区
  • 类型
    • 本地分区索引:索引分区与表分区一一对应(推荐)
    • 全局分区索引:索引分区与表分区不对应
  • 适用场景:大于 10GB 的分区表
  • 本地创建语法:CREATE INDEX idx_trans_trans_date ON transactions(trans_date) LOCAL;

2.8、索引组织表(IOT)

  • 特点:表的数据按索引的顺序存储,表本身就是索引,没有单独的表段
  • 适用场景:小表、查询主要通过主键访问的表
  • 优势:避免回表操作,查询速度极快
  • 创建语法
sql 复制代码
CREATE TABLE emp_iot (
  empno NUMBER PRIMARY KEY,
  ename VARCHAR2(20),
  sal NUMBER
) ORGANIZATION INDEX;

3、索引扫描类型

执行计划中的索引扫描类型直接决定了 SQL 的性能,必须熟练掌握每种扫描的触发条件和特点。

扫描类型 英文名称 触发条件 性能 说明
唯一索引扫描 INDEX UNIQUE SCAN 唯一索引的等值查询 最优 最多返回一行数据,找到后立即停止
索引范围扫描 INDEX RANGE SCAN 索引的范围查询(>、<、BETWEEN、LIKE 'xxx%') 扫描索引的一部分叶子节点
索引快速全扫描 INDEX FAST FULL SCAN 查询所有索引列,不需要排序 多块读扫描整个索引,比全表扫描快
索引全扫描 INDEX FULL SCAN 需要排序的结果集,且排序列是索引列 单块读扫描整个索引,结果有序
索引跳跃扫描 INDEX SKIP SCAN 复合索引的前导列没有出现在查询条件中,但后续列有过滤条件 11g + 特性,性能不如包含前导列的查询
全表扫描 TABLE ACCESS FULL 没有合适的索引,或全表扫描比索引扫描更快 最差 扫描整个表的所有数据块

关键说明

  • 索引快速全扫描和索引全扫描的区别:快速全扫描是多块读,结果无序;全扫描是单块读,结果有序
  • 索引跳跃扫描是 Oracle 的优化手段,但性能不稳定,最好避免依赖它
  • 小表(<1000 行)的全表扫描可能比索引扫描更快,因为索引扫描需要两次 IO(索引 + 回表)

实例:某公司 ERP 索引优化

**S(Situation - 情境):**某数据库运行2年后,频繁DML操作导致多个核心索引碎片率超过40%,索引高度从3层增长到5层,查询性能持续下降。

**T(Task - 任务):**制定索引维护计划,消除碎片、降低索引高度,恢复查询性能。

A(Action - 行动):

1、分析所有核心索引的碎片率

2、碎片率>30%的索引使用ALTER INDEX ... REBUILD ONLINE重建

3、碎片率10%-30%的使用COALESCE合并

4、在业务低峰期分批执行

**R(Result - 结果):**平均索引高度从5层降至3层,索引范围扫描性能提升40%-60%,并在线重建未影响业务正常运行,建立每季度索引维护计划。

相关推荐
倒流时光三十年2 小时前
PostgreSQL HOT 优化 - 大白话解释
数据库·postgresql·hot
Boop_wu2 小时前
[Java EE进阶] 博客系统
数据库·sql
Juicedata2 小时前
JuiceFS 1.4|大规模元数据操作优化:批量删除、克隆与 Redis 缓存全解析
数据库·redis·缓存
这个DBA有点耶2 小时前
SQL改写实战(续):子查询vs JOIN的深层原理
数据库·sql
yyuuuzz2 小时前
独立站搭建的几个核心技术问题
运维·服务器·网络·数据库·aws
小蒋学算法2 小时前
redis分布式锁实现
数据库·redis·分布式
白菜欣2 小时前
【MySQL】MySQL数据的增删改查(入门版)
数据库·mysql