Daily Study
更新: 6/19/2025 字数: 0 字 时长: 0 分钟
Daily Plan
#todo
- [ ]
Mysql慢查询相关
与Redis延迟区分开!
发现慢查询
- 开启慢查询日志
sql
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
-- 设置慢查询的阈值时间,单位为秒。例如,超过1秒的查询就算慢查询。
SET GLOBAL long_query_time = 1;
-- (可选,但强烈推荐) 记录没有使用索引的查询。这类查询通常是潜在的性能瓶颈。
SET GLOBAL log_queries_not_using_indexes = 'ON';
- 使用工具进行日志分析:
- mysqldumpslow:MySQL官方自带的工具,可以对慢查询日志进行分类、排序,找出最耗时的SQL。
- pt-query-digest:Percona Toolkit中的一个强大工具,功能远超
mysqldumpslow
,能生成非常详细和专业的分析报告。
- 查看当前线程监控:
SHOW FULL PROCESSLIST
这个命令可以查看当前正在MySQL中执行的所有线程。如果某个线程的Time
列数值很大,并且State
不是Sleep
,那么它很可能就是一条正在执行的慢查询。你可以据此找到对应的SQL语句并手动终止它(KILL [id];
)
分析慢查询
定位到SQL语句后,使用 EXPLAIN
进行分析
列名 | 关键值解读 | 优化方向 |
---|---|---|
type | 性能从好到坏: system > const > eq_ref > ref > range > index > ALL 出现 ALL 是最坏的情况,表示MySQL正在进行全表扫描,即遍历表的每一行来查找匹配项。这是必须优化的信号。 | 尽量避免ALL 和index ,目标是优化到range 或更好。 |
key | 实际使用的索引。如果这一列是 NULL ,表示MySQL没有使用任何索引来执行查询。 | 确保查询使用了最合适的索引。 |
rows | MySQL估算的为了找到结果,需要读取的行数。这个数字越大,查询通常越慢。 | 通过索引或其他优化手段,减少需要扫描的行数。 |
Extra | 包含了非常重要的额外信息。 • Using filesort :表示MySQL无法利用索引完成排序,不得不在内存或磁盘上进行额外的排序操作,性能开销极大。• Using temporary :表示MySQL需要创建一个临时表来处理查询,通常发生在GROUP BY 或UNION 等操作中,同样非常耗费性能。 | 必须想办法消除Using filesort 和Using temporary ,通常通过创建合适的索引来解决。 |
慢查询优化
- 索引优化:参照Mysql索引相关
- SQL改写:
- 避免
SELECT *
:只查询你需要的列,尤其是在大表上。这能减少网络传输量,并且更有可能用上覆盖索引。 - 避免在索引列上使用函数或计算:
- 坏:
WHERE YEAR(create_time) = 2025
。这会导致索引失效。 - 好:
WHERE create_time >= '2025-01-01' AND create_time < '2026-01-01'
。
- 坏:
- 小表驱动大表:在多表
JOIN
时,尽量让结果集小的表作为驱动表。 - 避免
OR
:在某些情况下,使用OR
可能会导致索引失效。可以考虑用UNION ALL
来代替。 - 使用
LIMIT
:如果你只需要一部分数据,一定要使用LIMIT
,尤其是在删除或更新大量数据时,分批处理。
- 避免
- 架构与设计层优化:
- 引入缓存:对于读多写少的、非实时性要求高的数据,引入Redis或Memcached等缓存层,将热点数据放入缓存,极大减轻数据库压力。
- 读写分离:对于读请求远大于写请求的场景,搭建主从复制架构,让主库负责写,多个从库负责读,分摊读压力。
- 分库分表:当单表数据量达到千万甚至上亿级别时,需要考虑水平或垂直分片,将数据分散到不同的表或数据库中。