一、SQL索引基础:数据库的“目录”系统
1.1 为什么需要SQL索引?
想象一本500页的《现代汉语词典》:
- 没有目录:要查“数据库”一词,需逐页翻阅(全表扫描)
当数据量达到百万级时,SQL索引可将查询速度提升几十到几百倍。
1.2 创建SQL索引的三种方式
-- 方式1:直接创建
CREATE INDEX idx_name ON users(email);
-- 方式2:修改表结构
ALTER TABLE users ADD INDEX idx_name (email);
-- 方式3:建表时创建
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(100),
    INDEX idx_email (email)  -- 普通索引
);
1.3 SQL索引管理命令
|  |  |  | 
|---|
|  | SHOW INDEX FROM users; |  | 
|  | DROP INDEX idx_email ON users; | 
 | 
|  | SELECT ... FORCE INDEX(idx_name) |  | 
二、SQL索引类型详解:数据库的“多重目录”
2.1 按数据结构划分(存储引擎层实现)
📌 重点对比:
-- B+树索引支持的操作
SELECT * FROM users WHERE age > 25;  -- 范围查询
SELECT * FROM users ORDER BY create_time; -- 排序
-- 哈希索引仅支持
SELECT * FROM users WHERE id = 10086; -- 精确匹配
2.2 按字段数量划分
|  |  |  | 
|---|
| 单列索引 |  | INDEX (email) | 
| 联合索引 |  | INDEX (last_name, first_name) | 
⚠️ 联合索引最左前缀原则:
CREATE INDEX idx_name_phone ON users(last_name, phone);
-- ✅ 生效场景
SELECT * FROM users WHERE last_name = '张';
SELECT * FROM users WHERE last_name = '张' AND phone='138****8000';
-- ❌ 失效场景
SELECT * FROM users WHERE phone = '138****8000';
2.3 按功能逻辑划分(最常用分类)
|  |  |  | 
|---|
| 普通索引 |  | ADD INDEX idx_name (name) | 
| 唯一索引 |  | ADD UNIQUE INDEX (email) | 
| 主键索引 |  | ADD PRIMARY KEY (id) | 
| 全文索引 |  | ADD FULLTEXT INDEX (content) | 
| 空间索引 |  | ADD SPATIAL INDEX (geom) | 
主键索引 vs 唯一索引:
INSERT INTO users (id, email) VALUES (NULL, 'a@test.com'); 
-- 主键索引报错:主键不能为NULL
-- 唯一索引允许:唯一索引列允许一个NULL值
2.4 按存储方式划分(InnoDB核心机制)
理解聚簇索引: 假设用户表结构:
聚簇索引(主键索引):
  - 叶子节点存储:| id | name | email | age |
非聚簇索引(普通索引):
  - 叶子节点存储:| age | id |
当通过非聚簇索引查询时:
SELECT name FROM users WHERE age = 30;
执行路径:age索引 -> 主键id -> 聚簇索引 -> 获取数据行
三、模拟数据与应用示例(10万行数据演示)
3.1 数据准备
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    category VARCHAR(50) NOT NULL,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- 插入10万条产品数据(脚本略)
3.2 SQL索引效果对比实验
场景1:无索引基础查询
-- 耗时约350ms
SELECT * FROM products WHERE category = 'electronics';
场景2:创建单列索引后
CREATE INDEX idx_category ON products(category);
-- 耗时降至8ms (提升44倍)
EXPLAIN SELECT * FROM products WHERE category='electronics';
-- 执行计划:type=ref, key=idx_category
场景3:联合索引范围查询
CREATE INDEX idx_category_price ON products(category, price);
-- ✅ 高效查询(使用索引)
SELECT * FROM products 
WHERE category='books' AND price > 100;
-- ❌ 低效查询(未用索引)
SELECT * FROM products WHERE price > 100;
场景4:覆盖索引优化
-- 原始查询(需回表)
SELECT id, name FROM products WHERE category='furniture';
-- 创建覆盖索引
CREATE INDEX idx_cover ON products(category, name, id);
-- 执行计划显示"Using index"
EXPLAIN SELECT id, name FROM products WHERE category='furniture';
四、SQL索引使用注意事项
4.1 SQL索引的代价
4.2 SQL索引失效的六大场景
- 函数操作: - SELECT * FROM users WHERE UPPER(name) = 'JOHN'; -- 失效
 SELECT * FROM users WHERE name = 'John';         -- 有效
 
 
- 隐式类型转换: - -- phone是字符串类型
 SELECT * FROM users WHERE phone = 13800138000; -- 失效
 
 
- 模糊查询通配符开头: - SELECT * FROM users WHERE name LIKE '%son';   -- 失效
 SELECT * FROM users WHERE name LIKE 'Joh%';   -- 有效
 
 
- OR连接非索引列: - -- age列无索引
 SELECT * FROM users WHERE name='John' OR age=30; -- 失效
 
 
- 联合索引跳过首列: - CREATE INDEX idx_name_phone ON users(name, phone);
 SELECT * FROM users WHERE phone='13800138000';   -- 失效
 
 
- 数据倾斜优化器弃用: - -- 90%数据category='electronics'
 SELECT * FROM products WHERE category='electronics'; -- 可能全表扫描
 
 
4.3 SQL索引设计原则
- 高频查询优先:WHERE/JOIN/ORDER BY/GROUP BY涉及的列
- 区分度高原则:选Cardinality值高的列(如身份证号比性别适合)
- 避免冗余索引:INDEX(a,b)  -- 已存在
 INDEX(a)    -- 冗余!
 
 
附录:SQL索引学习地图
graph TD
    A[索引基础] --> B[创建与管理]
    A --> C[类型体系]
    C --> D[数据结构]
    C --> E[字段数量]
    C --> F[功能逻辑]
    C --> G[存储方式]
    D --> H[B+树 vs 哈希]
    E --> I[联合索引最左前缀]
    F --> J[主键/唯一/全文]
    G --> K[聚簇/非聚簇]
    L[实战应用] --> M[性能对比]
    L --> N[覆盖索引]
    L --> O[失效场景]
阅读原文:原文链接
该文章在 2025/9/1 12:07:06 编辑过