Mysql 数据库使用入门系列:Mysql 查询优化,如何调整索引让查询更快(三)

今天讲一下 Mysql 的查询优化相关的知识点,查询优化是 Mysql 使用进阶的必经之路。同样的表结构,索引设计需要完美配合业务查询,才能将业务的查询速度发挥到最优。

为什么要优化查询?要提升网站的响应速度,数据库查询无疑是关键一环。程序员都知道,一个 Web 页面上,可能涉及到多个查询动数据库中取数据,一般情况下,这些查询都是串行执行的,假设一个面涉及到查库 10 次,如果你的每条 sql 查询速度在 100 ms 以上,那不算传输和业务代码处理时间,你这个页面的最快加载完时间将在 100ms x 10 = 1s 以上。当然我这是举个例子,不可能每个sql 都这么慢,但是实际情况是每个页面也不仅仅10次查询,往往多到几十次。这就是需要优化数据查询的原因。

另外,Mysql 的查询优化,也是面试中的一个重点。如果你的简历中有 Mysql 数据库,那么面试官少不了会提问索引、查询优化相关的问题。如果这个公司的业务,偏向于数据处理方面,数据库的问题肯定是重中之重。甚至分库分表、分布式设计,或者根据一些业务场景,让你设计相关数据表的结构,这些问题肯定都少不了。

这篇文章,主要就是来讲解到底该如何优化 sql 查询,调整索引才能让查询更快。

Mysql 索引的适用场景

索引的核心作用是加速查询过滤(WHERE)、关联(JOIN)、排序(ORDER BY)、分组(GROUP BY) 操作,以下场景优先考虑建索引:

  1. WHERE 子句中频繁出现的条件字段 例如:WHERE user_id = 123WHERE status = 'active',对user_idstatus建立索引可快速定位符合条件的行。
  2. JOIN 关联的字段 多表连接时,关联字段(如user.idorder.user_id)需建立索引,避免表连接时的全表扫描。
  3. ORDER BY/GROUP BY 的字段 排序或分组操作若基于某字段(如ORDER BY create_time),索引可避免 MySQL 的临时表排序(Using filesort)。
  4. 高频查询的返回字段(覆盖索引) 若查询仅需返回少量字段(如SELECT id, name FROM user WHERE age > 30),可建立包含这些字段的复合索引(如(age, id, name)),实现 “索引覆盖”,避免回表查询数据。

如何调整索引适应业务查询

1. 优先选择高选择性字段

这里的选择性,也叫列的区分度(或者散列度,有的叫列的基础),总之,意思指的是,这个字段内的不重复数据行数占总数据行数的比例。(选择性 = 不重复值数量 / 总记录数)。选择性越高,索引过滤效果越好。

  • user_id(几乎唯一,选择性接近 1)比gender(仅男 / 女,选择性低)更适合建索引。
  • 一个表有10w 数据,status 字段只有三个值,1/2/3,那么这个选择性(或散列度)就很低,不适合建索引。如果这个查询很频繁,又确实需要建索引怎么办?那这时候最优选择是建复合索引。

复合索引就是多个字段共同建立的一个索引。复合索引中,应将选择性高的字段放在前面(遵循 “最左前缀匹配原则”)。select id, name from user where create_time > xxx and status=2,就可以建立 索引Key(create_time, status),create_time 的可选择性几乎为1,所以它作为联合索引的第一个值,status 因为区分度很小,所以作为第二个值。

2. 复合索引的顺序至关重要

复合索引(多字段组合)遵循 “最左前缀匹配原则”:MySQL 会从左到右匹配索引字段,若左边字段未被使用,后续字段无法触发索引。

  • 例:索引(a, b, c)可匹配WHERE a=?WHERE a=? AND b=?WHERE a=? AND b=? AND c=?,但无法匹配WHERE b=?WHERE b=? AND c=?
  • 设计建议:按 “查询频率→选择性” 排序,高频出现的字段放左,同频时选择性高的放左。

上节的sql 语句(select id, name from user where create_time > xxx and status=2)中,where 条件,由于是先写的 create_time 然后 status ,所以它跟我们的索引天然适配。但是,如果你写的sql 为 where status=2 and create_time > xxx,就不会走刚才建立的联合索引 Key(create_time, status)

这就是最左匹配原则。要求sql 中条件顺序,需要跟 索引的顺序保持一致。

如果 sql 中的条件只有 where create_time > xxx还会走联合索引吗,答案是肯定的。也就是说联合索引,只要复合最左优先原则即可匹配索引,不需要完全匹配(所有条件必须都存在)。

复合索引可以提升索引的覆盖度(减少回表查询),相比建立多个单个字段索引降低了存储空间。提升组合查询效率。

3. 控制索引数量,避免过度索引

索引会消耗存储空间,且会降低插入、更新、删除的性能(因为每次写操作需同步维护索引)。

  • 建议:单表索引不超过 5-8 个,删除长期未使用的索引(可通过sys.schema_unused_indexes视图查看)。

4. 避免对 “低价值” 字段建索引

以下场景不适合建索引:

  • 表数据量极小(如几百行):全表扫描比索引查询更快。
  • 频繁更新的字段:索引会增加更新成本(如用户的last_login_time频繁变动)。
  • 低选择性字段(如status只有 2 个值):索引过滤效果差,MySQL 可能直接走全表扫描。

5. 合理设计字符串索引的长度

对长字符串(如varchar(255))建索引时,可指定前缀长度(如INDEX idx_name (username(10))),减少索引占用空间。

  • 原则:前缀长度需足够区分大部分值(可通过SELECT COUNT(DISTINCT LEFT(username, 10)) / COUNT(*)判断选择性)。

由于此部分内容较多,以上是关于 Mysql 查询优化的部分内容,后续相关内容,如何选择单字段索引还是复合索引,单字段索引和复合索引的优缺点是什么,这部分内容请关注后续文章更新。文章每日更新。欢迎常来。