一、索引概述
索引是数据库中用于加速数据查询的重要数据结构。索引能够将数据查找时间从O(n)降低到O(log n),显著提升查询性能。
二、B+树索引原理
2.1 B+树结构
B+树是一种平衡树结构,所有数据都存储在叶子节点,非叶子节点只存储索引键:
graph TD
A[根节点] --> B[中间节点1]
A --> C[中间节点2]
A --> D[中间节点3]
B --> E[叶子节点1]
B --> F[叶子节点2]
C --> G[叶子节点3]
C --> H[叶子节点4]
D --> I[叶子节点5]
D --> J[叶子节点6]
E --> F
F --> G
G --> H
H --> I
I --> J
2.2 B+树特性
| 特性 | 描述 | 优势 |
|---|---|---|
| 平衡树 | 左右子树高度差不超过1 | 查询稳定 |
| 所有数据在叶子节点 | 非叶子节点只存索引 | 范围查询高效 |
| 叶子节点链表 | 叶子节点双向链接 | 顺序扫描高效 |
| 多路分支 | 每个节点多个子节点 | 减少IO次数 |
2.3 B+树查询过程
sequenceDiagram
participant Client as 客户端
participant Root as 根节点
participant Middle as 中间节点
participant Leaf as 叶子节点
Client->>Root: 查询键值
Root->>Middle: 根据键值定位中间节点
Middle->>Leaf: 根据键值定位叶子节点
Leaf-->>Client: 返回数据
三、B+树插入与删除
3.1 插入操作
B+树插入需要维护平衡性:
flowchart TD
A[插入键值] --> B{节点是否满}
B -->|否| C[直接插入]
B -->|是| D[分裂节点]
D --> E[提升中间键到父节点]
E --> F{父节点是否满}
F -->|否| G[完成插入]
F -->|是| H[递归分裂]
H --> E
3.2 删除操作
B+树删除也需要维护平衡性:
flowchart TD
A[删除键值] --> B{节点是否空}
B -->|否| C[直接删除]
B -->|是| D{兄弟节点是否有多余}
D -->|是| E[借键值]
D -->|否| F[合并节点]
F --> G[更新父节点]
G --> H{父节点是否需要调整}
H -->|是| I[递归调整]
H -->|否| J[完成删除]
四、MySQL索引类型
4.1 主键索引
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL
);
4.2 唯一索引
CREATE UNIQUE INDEX idx_users_email ON users(email);
4.3 普通索引
CREATE INDEX idx_users_name ON users(username);
4.4 复合索引
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);
五、全文索引
5.1 全文索引概述
全文索引用于文本搜索,支持自然语言查询:
-- 创建全文索引
ALTER TABLE articles ADD FULLTEXT INDEX idx_articles_content(content);
-- 使用全文索引
SELECT * FROM articles WHERE MATCH(content) AGAINST('关键词');
5.2 全文索引原理
graph TD
A[文档] --> B[分词器]
B --> C[词元]
C --> D[倒排索引]
D --> E{查询词}
E --> F[匹配文档]
D --> D1[词1: 文档1,文档2]
D --> D2[词2: 文档2,文档3]
D --> D3[词3: 文档1,文档3]
5.3 全文索引配置
-- 配置最小词长
SET GLOBAL ft_min_word_len = 2;
-- 配置停用词文件
SET GLOBAL ft_stopword_file = '/path/to/stopwords.txt';
-- 自定义分词器
ALTER TABLE articles ADD FULLTEXT INDEX idx_content (content)
WITH PARSER ngram;
六、覆盖索引
6.1 覆盖索引概述
覆盖索引是指索引包含查询所需的所有列,不需要回表查询:
graph TD
A[普通索引查询] --> B[索引查找]
B --> C[回表查询]
C --> D[返回结果]
E[覆盖索引查询] --> F[索引查找]
F --> G[返回结果]
6.2 覆盖索引示例
-- 创建覆盖索引
CREATE INDEX idx_users_name_email ON users(username, email);
-- 查询只需要username和email,使用覆盖索引
SELECT username, email FROM users WHERE username = 'test';
-- 查询需要额外字段,无法使用覆盖索引
SELECT username, email, phone FROM users WHERE username = 'test';
6.3 覆盖索引优化
通过合理设计索引,实现覆盖查询:
| 查询场景 | 索引设计 | 是否覆盖 |
|---|---|---|
| WHERE a=1 SELECT b,c | (a,b,c) | 是 |
| WHERE a=1,b=2 SELECT c | (a,b,c) | 是 |
| WHERE a=1 SELECT b,c,d | (a,b,c) | 否 |
| WHERE b=1 SELECT a | (a,b) | 否 |
七、索引优化策略
7.1 索引选择原则
- 在WHERE、JOIN、ORDER BY子句中的列创建索引
- 选择选择性高的列作为索引
- 复合索引遵循最左前缀原则
- 避免在频繁更新的列上创建索引
- 避免过多索引,影响写入性能
7.2 最左前缀原则
复合索引只对最左前缀有效:
graph TD
A[复合索引: a, b, c] --> B[a]
A --> C[a, b]
A --> D[a, b, c]
B --> B1[WHERE a=1]
C --> C1[WHERE a=1 AND b=2]
D --> D1[WHERE a=1 AND b=2 AND c=3]
E[无法使用索引] --> E1[WHERE b=2]
E --> E2[WHERE b=2 AND c=3]
7.3 索引失效场景
-- 索引失效场景
SELECT * FROM users WHERE username LIKE '%test'; -- 前缀模糊匹配
SELECT * FROM users WHERE age + 1 = 10; -- 列上有表达式
SELECT * FROM users WHERE CAST(age AS CHAR) = '10'; -- 类型转换
SELECT * FROM users WHERE status IN (1, 2, 3); -- IN可能失效
SELECT * FROM users WHERE name = 'test' OR age = 10; -- OR条件
八、索引维护
8.1 索引碎片
索引碎片会影响查询性能,需要定期整理:
-- 查看索引碎片
SHOW INDEX FROM users;
-- 整理索引(InnoDB)
ALTER TABLE users ENGINE=InnoDB;
-- 重建索引
DROP INDEX idx_users_name ON users;
CREATE INDEX idx_users_name ON users(username);
8.2 索引统计信息
-- 查看索引统计
ANALYZE TABLE users;
-- 查看执行计划
EXPLAIN SELECT * FROM users WHERE username = 'test';
-- 查看索引使用情况
SHOW PROFILE;
九、索引设计实践
9.1 电商订单表索引设计
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
status INT,
total_amount DECIMAL(10,2),
order_date DATETIME,
INDEX idx_orders_user (user_id),
INDEX idx_orders_status_date (status, order_date),
INDEX idx_orders_date (order_date)
);
9.2 用户表索引设计
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
email VARCHAR(100),
phone VARCHAR(20),
status INT,
created_at DATETIME,
UNIQUE INDEX idx_users_email (email),
UNIQUE INDEX idx_users_phone (phone),
INDEX idx_users_status (status),
INDEX idx_users_created (created_at)
);
十、总结
B+树是数据库索引的核心数据结构,通过合理设计索引能够显著提升查询性能。全文索引用于文本搜索,覆盖索引能够避免回表查询。索引优化是数据库性能调优的重要手段,需要结合业务场景和查询模式进行设计。