索引是帮助MySQL高效获取数据的数据结构,类似于书籍的目录。它能加快数据检索速度,但会增加存储空间和维护成本。
-- 普通索引
CREATE INDEX idx_name ON users(name);
-- 唯一索引
CREATE UNIQUE INDEX idx_email ON users(email);
-- 主键索引(自动创建)
ALTER TABLE users ADD PRIMARY KEY (id);
特点:
-- Memory引擎默认使用哈希索引
CREATE TABLE hash_table (
id INT,
data VARCHAR(100)
) ENGINE=MEMORY;
CREATE INDEX idx_hash USING HASH ON hash_table(id);
特点:
-- 适用于文本搜索
CREATE TABLE articles (
id INT PRIMARY KEY,
content TEXT,
FULLTEXT(content)
);
-- 使用MATCH AGAINST查询
SELECT * FROM articles
WHERE MATCH(content) AGAINST('数据库优化');
空间索引(R-Tree)
-- 适用于地理空间数据
CREATE SPATIAL INDEX sp_index ON locations(coordinates);
-- 索引包含查询所需的所有字段
CREATE INDEX idx_covering ON users(name, age, city);
-- 查询只需扫描索引,无需回表
SELECT name, age FROM users WHERE name = 'John';
复合索引(联合索引)
-- 多列组合索引
CREATE INDEX idx_multi ON users(last_name, first_name, age);
-- 最左前缀原则示例
-- ✅ 可使用索引:WHERE last_name = 'Smith'
-- ✅ 可使用索引:WHERE last_name = 'Smith' AND first_name = 'John'
-- ❌ 不可用索引:WHERE first_name = 'John'
-- ❌ 不可用索引:WHERE age > 25
-- 适合建索引的列:
-- 1. WHERE子句中的列
-- 2. JOIN连接的列
-- 3. ORDER BY/GROUP BY的列
-- 4. SELECT中的覆盖索引列
CREATE INDEX idx_optimize ON orders(
customer_id, -- WHERE条件
order_date, -- 排序和范围查询
status -- 等值查询
);
索引选择策略
| 场景 | 推荐索引类型 | 说明 |
|---|---|---|
| 等值查询 | 哈希索引/B+树 | 哈希更快但有限制 |
| 范围查询 | B+树索引 | 哈希不支持 |
| 模糊查询 | B+树索引 | LIKE 'prefix%' |
| 全文搜索 | 全文索引 | MATCH AGAINST |
| 排序分组 | B+树索引 | 天然有序 |
-- 原则:高选择性列在前,低选择性列在后
-- 选择性 = 不同值数量 / 总行数
-- 示例:城市(低选择性)在前,年龄(高选择性)在后 ❌
CREATE INDEX idx_bad ON users(city, age);
-- 优化:年龄在前,城市在后 ✅
CREATE INDEX idx_good ON users(age, city);
索引下推(ICP)优化
-- MySQL 5.6+ 自动启用
-- 在索引层面过滤数据,减少回表次数
-- 原始查询
SELECT * FROM users
WHERE last_name LIKE '张%'
AND age > 25;
-- 使用复合索引(last_name, age)时
-- ICP会在索引中直接过滤age>25的记录
-- 1. 函数操作导致失效 ❌
SELECT * FROM users WHERE UPPER(name) = 'JOHN';
-- 优化 ✅
CREATE INDEX idx_upper ON users(UPPER(name));
-- 或
SELECT * FROM users WHERE name = 'JOHN';
-- 2. 隐式类型转换 ❌
SELECT * FROM users WHERE phone = 13800138000;
-- phone是VARCHAR类型,比较时发生类型转换
-- 3. OR条件部分未使用索引 ❌
SELECT * FROM users
WHERE name = 'John'
OR age > 25; -- age无索引
-- 4. 使用NOT、!=、<> ❌
SELECT * FROM users WHERE status != 'active';
-- 5. LIKE以通配符开头 ❌
SELECT * FROM users WHERE name LIKE '%son';
innodb_adaptive_hash_index-- MySQL使用多个索引然后合并结果
CREATE INDEX idx_name ON users(name);
CREATE INDEX idx_age ON users(age);
-- 可能触发索引合并
SELECT * FROM users
WHERE name = 'John'
OR age = 30;
-- MySQL 8.0+ 支持
CREATE INDEX idx_desc ON users(created_at DESC, score ASC);
-- 优化降序排序查询
SELECT * FROM users
ORDER BY created_at DESC, score ASC;
-- MySQL 8.0+ 支持
CREATE INDEX idx_func ON users((UPPER(name)));
-- 支持JSON路径索引
CREATE INDEX idx_json ON users((CAST(data->>'$.score' AS SIGNED)));
-- 查看索引使用情况
EXPLAIN SELECT * FROM users WHERE name = 'John';
-- 查看索引统计信息
SHOW INDEX FROM users;
-- 查看索引使用统计(Performance Schema)
SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage;
-- 重建索引(InnoDB)
ALTER TABLE users ENGINE=InnoDB;
-- 或
OPTIMIZE TABLE users;
-- 分析索引统计信息
ANALYZE TABLE users;
-- 强制使用/忽略索引
SELECT * FROM users USE INDEX (idx_name) WHERE ...;
SELECT * FROM users IGNORE INDEX (idx_name) WHERE ...;
| 指标 | 说明 | 建议值 |
|---|---|---|
| 索引大小 | 索引占用的空间 | 不超过数据大小60% |
| 索引命中率 | 索引使用效率 | >95% |
| 重复索引 | 冗余索引数量 | 0 |
| 未使用索引 | 从未使用的索引 | 考虑删除 |
是否需要索引?
├── 是 → 查询频率高吗?
│ ├── 是 → 数据选择性高吗?
│ │ ├── 是 → 创建索引
│ │ └── 否 → 考虑复合索引
│ └── 否 → 不创建
└── 否 → 结束
-- 分区表索引类型
-- 1. 本地索引(每个分区独立)
CREATE INDEX idx_local ON orders(order_date)
LOCAL; -- 每个分区都有该索引
-- 2. 全局索引(跨分区)
CREATE INDEX idx_global ON orders(customer_id)
GLOBAL; -- 整个表一个索引
-- 临时禁用索引(测试删除影响)
ALTER TABLE users ALTER INDEX idx_name INVISIBLE;
-- 恢复索引
ALTER TABLE users ALTER INDEX idx_name VISIBLE;
-- MySQL 8.0优化了倒序索引扫描
-- 支持双向扫描,不再需要专门创建DESC索引
-- 支持更复杂的表达式
CREATE INDEX idx_expression ON users((SUBSTRING(name, 1, 10)));
答:不是。索引会增加:
答:遵循原则:
等值查询字段在前,范围查询字段在后 高选择性字段在前 经常查询的字段在前答:考虑删除:
从未被查询使用的索引 冗余索引(已有复合索引覆盖) 选择性极低的索引(<5%)-- 1. 使用EXPLAIN ANALYZE(MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 25;
-- 2. 查询优化器跟踪
SET optimizer_trace="enabled=on";
SELECT * FROM users WHERE ...;
SELECT * FROM information_schema.optimizer_trace;
-- 3. 使用sys schema分析
USE sys;
SELECT * FROM schema_index_statistics;
MySQL索引优化的核心原则:
理解业务查询模式 合理设计索引结构 持续监控和调整 平衡读写性能记住:没有银弹索引,最佳索引策略需要根据实际业务场景、数据分布和查询模式不断调整优化。建议在生产环境使用前,先在测试环境充分验证索引效果。