主题
面试速答(先看这里)
**一句话结论:**如何通过SQL 审查发现SQL存在性能问题?
60秒标准回答:
如何通过SQL 审查发现SQL存在性能问题?其实这个问题就是考察你知道不知道都有哪些情况可能到导致一个SQL执行的慢,我们在下面的文章中介绍了可能会导致一个SQL执行慢的原因
可以通过SQL审查发现的问题有以下几个
2、多表join
**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点
回答主线:
- **要点1:**可以通过SQL审查发现的问题有以下几个:
- **要点2:**首先,代码审查的时候,我们也可以直接把SQL拿到,去数据库中执行一把Explain,看看索引的情况,是不是符合预期的。
- **要点3:**这个最容易了,肉眼看一下,算一下就行了,一次查询的字段尽量不要超过20个,并且尽量使用索引覆盖查询、尽量避免无脑使用 SELECT * 查询
- **要点4:**区分度指索引列中不重复值的数量与总行数的比值。
- **要点5:**但是需要注意,并不是所引起区分度不高就不能用,有些特殊情况还是可以用的:
**记忆锚点:**SQL → WHERE → order → JOIN → Transactional → create_time
关键取舍:
- 如何通过SQL 审查发现SQL存在性能问题?
- 如果区分度极低(例如在性别字段 gender 或状态字段 status 上建索引),数据库优化器在计算成本后,会认为走索引再回表的代价比直接全表扫描还要高,从而主动放弃索引。
易错提醒:
- 这个最容易了,肉眼看一下,算一下就行了,一次查询的字段尽量不要超过20个,并且尽量使用索引覆盖查询、尽量避免无脑使用 SELECT * 查询 区分度指索引列中不重复值的数量与总行数的比值。
- 但是需要注意,并不是所引起区分度不高就不能用,有些特殊情况还是可以用的: 长事务会长时间持有锁或者占用数据库连接。
加分表达:
- 检查SQL中是否存在order by这样的操作,以及order by的字段是否有索引 查询是否遵循最左前缀匹配 检查 JOIN 的表数量,通常建议单次 JOIN 不超过 3 张表。
- 其实这个问题就是考察你知道不知道都有哪些情况可能到导致一个SQL执行的慢,我们在下面的文章中介绍了可能会导致一个SQL执行慢的原因: 可以通过SQL审查发现的问题有以下几个: 2、多表join 3、查询字段太多 4、表中数据量太大 5、索引区分度不高 6、数据库连接数不够 7、数据库的表结构不合理 8、数据库IO或者CPU比较高 9、数据库参数不合理 10…
追问准备:
- 围绕「SQL」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「WHERE」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「order」:底层原理是什么?使用时有哪些边界和常见坑?
- 如果线上出现异常,你会如何定位、验证并规避?
典型回答
如何通过SQL 审查发现SQL存在性能问题?其实这个问题就是考察你知道不知道都有哪些情况可能到导致一个SQL执行的慢,我们在下面的文章中介绍了可能会导致一个SQL执行慢的原因:
可以通过SQL审查发现的问题有以下几个:
1、索引失效
2、多表join
3、查询字段太多
4、表中数据量太大
5、索引区分度不高
6、数据库连接数不够
7、数据库的表结构不合理
8、数据库IO或者CPU比较高
9、数据库参数不合理
10、事务比较长
11、锁竞争导致的等待
12、深分页问题
被我标红的是我们可以通过代码审查发现的问题。其他的几个问题不太好通过代码审查发现。一个一个说。
索引失效
首先,代码审查的时候,我们也可以直接把SQL拿到,去数据库中执行一把Explain,看看索引的情况,是不是符合预期的。走没走索引、走了哪个索引这些都可以看的。
我们在下面的文章中介绍了常见的索引失效的情况:
重点关注
WHERE子句中是否对字段使用了函数(如YEAR(create_time) = 2023)。- 检查是否存在隐式类型转换(如
varchar类型的字段传入了数字WHERE phone = 13800138000)。 - 检查是否使用了左模糊查询(
LIKE '%keyword')。 - 检查是否出现索引列参与了计算(
age +1 = 12) - 检查sql中是否出现
or、not null、!=、in等操作。 - 检查SQL中是否存在order by这样的操作,以及order by的字段是否有索引
- 查询是否遵循最左前缀匹配
多表join
- 检查 JOIN 的表数量,通常建议单次 JOIN 不超过 3 张表。
- 检查关联字段(
ON条件)是否都有索引,且数据类型、字符集完全一致。 - 检查是否用小表作为驱动表去驱动大表(小表驱动大表原则)。
📄 ✅MySQL 为什么是小表驱动大表,为什么能提高查询性能?
打开文档:✅MySQL 为什么是小表驱动大表,为什么能提高查询性能?
查询字段太多
这个最容易了,肉眼看一下,算一下就行了,一次查询的字段尽量不要超过20个,并且尽量使用索引覆盖查询、尽量避免无脑使用 SELECT *查询
索引区分度不高
区分度指索引列中不重复值的数量与总行数的比值。如果区分度极低(例如在性别字段 gender 或状态字段 status 上建索引),数据库优化器在计算成本后,会认为走索引再回表的代价比直接全表扫描还要高,从而主动放弃索引。
- 审查单列索引是否建在了枚举值极少(如男/女、是/否)的字段上。
- 审查联合索引的列顺序,是否把区分度低的字段放在了最前面(违反了最左前缀原则的有效利用)。
但是需要注意,并不是所引起区分度不高就不能用,有些特殊情况还是可以用的:
事务比较长
长事务会长时间持有锁或者占用数据库连接。同时,长事务会导致 Undo Log 无法及时清理,增加存储引擎(如 InnoDB)的 MVCC 版本链遍历开销,甚至引发主从延迟。
长事务通过代码也能发现的,这个就不是看SQL,而是看具体的service的方法
- 检查事务块(
@Transactional)内部是否包含了非数据库操作,如 RPC 调用、HTTP 请求、复杂的内存计算或文件读写。 - 检查是否存在循环内执行 SQL 或等待用户输入的情况。
深分页问题
对于有一些定时任务比较常出现这个问题,一定要提前关注,有没有可能存在要翻很多页的情况。
- 检查分页 SQL 中
LIMIT的偏移量(Offset)是否可能随着业务增长而变得极大。 - 检查是否允许用户直接跳转到百万级之后的页码。