1. MySQL索引基础概念与作用
索引是数据库系统中用于加速数据检索的数据结构,类似于书籍的目录。当我们需要在MySQL表中查找特定记录时,如果没有索引,数据库需要逐行扫描整个表(称为全表扫描),这在数据量大的情况下效率极低。索引通过创建特定的数据结构,使得数据库可以快速定位到所需数据。
索引的核心价值体现在三个方面:
- 提高查询速度:通过减少需要扫描的数据量,将时间复杂度从O(n)降低到O(log n)
- 保证数据唯一性:唯一索引确保列值的唯一性
- 加速排序和分组:索引已经预先排序,可以避免额外的排序操作
在MySQL中,索引是存储在磁盘或内存中的数据结构,最常见的索引类型是B+树索引。当表数据量超过百万级时,合理使用索引可以使查询性能提升数十倍甚至上百倍。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. MySQL索引类型详解
2.1 按数据结构分类
MySQL支持多种索引数据结构,每种结构适用于不同场景:
-
B+树索引:MySQL默认索引类型,适合范围查询和精确查找。InnoDB和MyISAM引擎都使用B+树,但实现方式不同:
- InnoDB:聚簇索引,叶子节点存储完整数据记录
- MyISAM:非聚簇索引,叶子节点存储数据指针
-
哈希索引:基于哈希表实现,适合等值查询但不支持范围查询。Memory引擎默认使用哈希索引,InnoDB有自适应哈希索引特性。
-
全文索引:用于文本内容的全文搜索,MyISAM和InnoDB(5.6+)都支持。
-
空间索引:用于地理空间数据,只有MyISAM支持。
2.2 按功能分类
-
普通索引:最基本的索引类型,无任何限制
sql复制CREATE INDEX idx_name ON table_name(column_name); -
唯一索引:确保索引列值唯一,允许NULL值
sql复制CREATE UNIQUE INDEX idx_name ON table_name(column_name); -
主键索引:特殊的唯一索引,不允许NULL值
sql复制ALTER TABLE table_name ADD PRIMARY KEY (column_name); -
组合索引:在多个列上建立的索引
sql复制CREATE INDEX idx_name ON table_name(col1, col2, col3); -
前缀索引:对字符串前N个字符建立索引
sql复制CREATE INDEX idx_name ON table_name(column_name(N));
3. 创建索引的正确方法
3.1 单列索引创建
为users表的username列创建普通索引:
sql复制CREATE INDEX idx_username ON users(username);
为products表的product_code列创建唯一索引:
sql复制CREATE UNIQUE INDEX idx_product_code ON products(product_code);
3.2 组合索引创建
为orders表创建组合索引,包含customer_id和order_date列:
sql复制CREATE INDEX idx_customer_order ON orders(customer_id, order_date);
3.3 修改表结构添加索引
为已有表添加主键索引:
sql复制ALTER TABLE employees ADD PRIMARY KEY (emp_id);
添加普通索引:
sql复制ALTER TABLE products ADD INDEX idx_price (price);
3.4 创建索引的最佳实践
-
选择合适的列:
- 高选择性的列(区分度高)
- WHERE子句频繁使用的列
- JOIN操作中使用的列
- ORDER BY/GROUP BY子句中的列
-
组合索引列顺序:
- 高频查询条件放前面
- 高选择性列放前面
- 考虑最左前缀原则
-
避免过度索引:
- 单表索引建议不超过5个
- 不常用的查询不要建索引
- 频繁更新的列谨慎建索引
4. 索引使用注意事项与常见问题
4.1 索引失效场景
-
违反最左前缀原则:
sql复制-- 组合索引(col1, col2, col3) SELECT * FROM table WHERE col2 = 'value'; -- 无法使用索引 -
使用函数或运算:
sql复制SELECT * FROM users WHERE MONTH(create_time) = 3; -- 索引失效 -
隐式类型转换:
sql复制SELECT * FROM users WHERE phone = 13800138000; -- phone是varchar类型 -
使用OR条件:
sql复制SELECT * FROM users WHERE age = 20 OR name = 'John'; -- 可能导致全表扫描 -
LIKE以通配符开头:
sql复制SELECT * FROM products WHERE name LIKE '%apple%'; -- 无法使用索引
4.2 索引使用建议
-
EXPLAIN分析查询:
sql复制EXPLAIN SELECT * FROM orders WHERE customer_id = 100; -
覆盖索引优化:
sql复制-- 建立组合索引(order_id, product_id, quantity) SELECT order_id, product_id FROM order_items WHERE order_id = 1001; -
索引下推优化:
MySQL 5.6+支持将WHERE条件推到存储引擎层过滤 -
定期维护索引:
sql复制ANALYZE TABLE orders; -- 更新索引统计信息
5. 索引性能优化实战案例
5.1 电商系统订单查询优化
场景:订单表有500万数据,需要按用户ID和日期范围查询
优化前:
sql复制SELECT * FROM orders
WHERE user_id = 1001
AND order_date BETWEEN '2023-01-01' AND '2023-03-31'
ORDER BY order_date DESC;
优化步骤:
- 创建组合索引:
sql复制CREATE INDEX idx_user_date ON orders(user_id, order_date); - 使用覆盖索引:
sql复制SELECT order_id, order_date, amount FROM orders WHERE user_id = 1001 AND order_date BETWEEN '2023-01-01' AND '2023-03-31' ORDER BY order_date DESC;
5.2 用户搜索功能优化
场景:用户表username字段模糊搜索
优化方案:
- 使用前缀索引:
sql复制CREATE INDEX idx_username ON users(username(10)); - 对于复杂搜索需求,考虑全文索引:
sql复制CREATE FULLTEXT INDEX idx_ft_username ON users(username); SELECT * FROM users WHERE MATCH(username) AGAINST('john*' IN BOOLEAN MODE);
6. 索引监控与维护
6.1 查看索引使用情况
sql复制-- 查看表索引
SHOW INDEX FROM orders;
-- 查看未使用的索引
SELECT * FROM sys.schema_unused_indexes
WHERE object_schema = 'your_database';
6.2 索引维护操作
-
重建索引:
sql复制ALTER TABLE orders ENGINE=InnoDB; -- 重建表及索引 -
优化表:
sql复制OPTIMIZE TABLE orders; -- 整理碎片 -
删除冗余索引:
sql复制DROP INDEX idx_redundant ON orders;
6.3 监控索引性能
-
使用Performance Schema:
sql复制SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage; -
监控慢查询日志:
sql复制-- 在my.cnf中配置 slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 2
7. 高级索引技术
7.1 函数索引(MySQL 8.0+)
sql复制CREATE INDEX idx_month ON orders((MONTH(order_date)));
7.2 降序索引(MySQL 8.0+)
sql复制CREATE INDEX idx_date_desc ON orders(order_date DESC);
7.3 隐藏索引(MySQL 8.0+)
sql复制-- 创建隐藏索引
CREATE INDEX idx_email ON users(email) INVISIBLE;
-- 切换可见性
ALTER TABLE users ALTER INDEX idx_email VISIBLE;
7.4 索引跳跃扫描(MySQL 8.0+)
当组合索引前导列选择性低时,优化器可能跳过前导列直接使用后续列索引
8. 索引与存储引擎
8.1 InnoDB索引特点
- 聚簇索引结构
- 自适应哈希索引
- 支持事务和行锁
- 二级索引存储主键值
8.2 MyISAM索引特点
- 非聚簇索引结构
- 支持全文索引
- 表级锁
- 索引文件与数据文件分离
8.3 存储引擎选择建议
- 需要事务:InnoDB
- 只读或读多写少:MyISAM
- 内存表:Memory
- 全文搜索:InnoDB+全文索引或专用搜索引擎
9. 索引设计实战经验
-
电商系统:
- 商品表:主键id,SKU唯一索引,分类ID+价格组合索引
- 订单表:订单号唯一索引,用户ID+状态+时间组合索引
-
社交网络:
- 用户表:用户名索引,手机号唯一索引
- 好友关系:双向组合索引(user_id, friend_id)和(friend_id, user_id)
-
日志系统:
- 时间范围查询:时间字段索引
- 高频过滤:业务类型+时间组合索引
10. 常见误区与解决方案
-
误区:索引越多越好
- 问题:影响写入性能,增加维护成本
- 方案:遵循"最少索引"原则,定期清理无用索引
-
误区:所有查询都能用索引
- 问题:复杂条件查询可能无法有效使用索引
- 方案:重写查询或考虑其他优化手段
-
误区:索引可以解决所有性能问题
- 问题:数据量极大时索引效果降低
- 方案:考虑分表分库或使用专业搜索工具
-
误区:组合索引顺序无关紧要
- 问题:错误顺序导致索引失效
- 方案:遵循最左前缀原则,高选择性列在前
