庆阳市网站建设_网站建设公司_跨域_seo优化
2026/1/16 15:47:14 网站建设 项目流程

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!


在日常开发中,我们经常会遇到 SQL 查询慢得像蜗牛的情况。明明数据量不大,却查个几秒钟甚至十几秒——这时候,MySQL 索引就是你最该检查的地方!

今天我们就用Java + Spring Boot的方式,结合真实业务场景,手把手带你搞懂 MySQL 索引的使用、误区和最佳实践。


一、什么是索引?为什么需要它?

想象一下你在一本 500 页的字典里找“苹果”这个词:

  • 没有索引:你得一页一页翻,直到找到。
  • 有索引(目录):直接翻到“P”开头的部分,快速定位。

数据库索引同理:它是对表中一列或多列的值进行排序的一种结构,用来加速查询速度


二、常见索引类型(MySQL InnoDB 引擎)

类型说明
主键索引(PRIMARY KEY)唯一、非空,一张表只能有一个
唯一索引(UNIQUE)值唯一,可为空(但只能有一个 NULL)
普通索引(INDEX / KEY)最常用,允许重复、允许 NULL
联合索引(复合索引)多个字段组合成一个索引,遵循最左前缀原则
全文索引(FULLTEXT)用于文本搜索(如文章内容),不适用于普通等值/范围查询

⚠️ 注意:InnoDB 默认使用 B+ 树实现索引,MyISAM 也是,但存储结构不同。


三、真实业务场景:用户订单查询慢

📌 需求背景

某电商系统,order_info表结构如下:

CREATE TABLE `order_info` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `user_id` BIGINT NOT NULL, `order_status` TINYINT NOT NULL COMMENT '0-待支付,1-已支付,2-已取消', `create_time` DATETIME NOT NULL, `amount` DECIMAL(10,2) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB;

现在有个接口:查询某个用户最近 30 天的所有已支付订单

// OrderService.java public List<OrderInfo> findPaidOrdersByUser(Long userId, LocalDateTime startTime) { return orderMapper.selectByUserIdAndStatusAndTime(userId, 1, startTime); }

对应的 SQL 可能是:

SELECT * FROM order_info WHERE user_id = ? AND order_status = 1 AND create_time >= ?

❌ 反例:无索引,全表扫描

如果order_info表有 100 万条数据,而没有任何索引(除了主键),每次查询都要扫描整张表 ——性能灾难!

你可以用EXPLAIN查看执行计划:

EXPLAIN SELECT * FROM order_info WHERE user_id = 123 AND order_status = 1 AND create_time >= '2026-01-01';

结果会显示:

  • type: ALL(全表扫描)
  • rows: 1000000(扫描了百万行)
  • Extra: Using where

这就是典型的“慢查询”根源!


四、正确做法:创建联合索引

✅ 正确索引设计

根据查询条件:user_idorder_statuscreate_time

我们应该创建一个联合索引

ALTER TABLE order_info ADD INDEX idx_user_status_time (user_id, order_status, create_time);

为什么顺序是user_id → order_status → create_time

  • user_id是高区分度字段(每个用户订单少)
  • order_status是等值查询(=1)
  • create_time是范围查询(>=),放最后(B+树特性决定)

✅ 执行计划验证

再次执行EXPLAIN

EXPLAIN SELECT * FROM order_info WHERE user_id = 123 AND order_status = 1 AND create_time >= '2026-01-01';

结果:

  • type: range
  • key: idx_user_status_time
  • rows: 50(只扫描几十行)
  • Extra: Using index condition

✅ 查询速度从 2 秒降到 10 毫秒!


五、Spring Boot 代码实战

1. 实体类

// OrderInfo.java @Data @TableName("order_info") public class OrderInfo { private Long id; private Long userId; private Integer orderStatus; private LocalDateTime createTime; private BigDecimal amount; }

2. Mapper 接口(MyBatis-Plus)

// OrderMapper.java @Mapper public interface OrderMapper extends BaseMapper<OrderInfo> { @Select("SELECT * FROM order_info " + "WHERE user_id = #{userId} " + "AND order_status = #{status} " + "AND create_time >= #{startTime}") List<OrderInfo> selectByUserIdAndStatusAndTime( @Param("userId") Long userId, @Param("status") Integer status, @Param("startTime") LocalDateTime startTime ); }

3. Service 调用

@Service public class OrderService { @Autowired private OrderMapper orderMapper; public List<OrderInfo> findRecentPaidOrders(Long userId) { LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30); return orderMapper.selectByUserIdAndStatusAndTime(userId, 1, thirtyDaysAgo); } }

💡 提示:生产环境建议用 MyBatis-Plus 的 LambdaQueryWrapper,更安全。


六、索引使用注意事项(避坑指南)

⚠️ 1. 最左前缀原则

联合索引(a, b, c),以下查询能命中索引:

  • WHERE a = 1
  • WHERE a = 1 AND b = 2
  • WHERE a = 1 AND b = 2 AND c >= '2026-01-01'

但以下不能部分命中

  • WHERE b = 2❌(跳过 a)
  • WHERE a = 1 AND c = 'xxx'❌(跳过 b,c 无法使用索引)
  • WHERE a > 1 AND b = 2⚠️(a 是范围,b 无法用索引)

⚠️ 2. 不要在索引列上做函数操作

❌ 错误写法:

SELECT * FROM order_info WHERE DATE(create_time) = '2026-01-16';

✅ 正确写法:

SELECT * FROM order_info WHERE create_time >= '2026-01-16 00:00:00' AND create_time < '2026-01-17 00:00:00';

函数会导致索引失效!

⚠️ 3. 避免冗余索引

比如已有(user_id, order_status),又单独建user_id索引 ——冗余!

因为联合索引的最左前缀已经覆盖了user_id单独查询。

⚠️ 4. 索引不是越多越好

  • 插入/更新/删除时要维护索引,写性能下降
  • 索引占用磁盘空间
  • 建议:单表索引不超过 5 个,联合索引字段不超过 3~4 个

七、如何监控慢查询?

my.cnf中开启慢查询日志:

slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 1 # 超过1秒记录 log_queries_not_using_indexes = 1 # 记录未使用索引的查询

然后定期分析日志,优化 SQL。


八、总结

场景是否需要索引建议
高频查询字段✅ 必须如 user_id、status
低区分度字段(如性别)❌ 谨慎索引效果差
经常 ORDER BY / GROUP BY✅ 考虑可避免 filesort
大文本字段(如 content)❌ 不适合用全文索引或 ES

记住一句话:索引是把双刃剑,用得好飞天,用不好拖垮数据库!


视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询