一、慢查询的本质认知
1.1 什么是真正的慢查询?
- 执行时间超过long_query_time阈值(默认10秒)
- 逻辑读超过10,000次的查询
- 返回行数异常多的查询(即使执行时间短)
1.2 性能瓶颈的典型分布
mermaid
pie
title 性能瓶颈来源
"索引缺失" : 45
"不当连接" : 25
"数据量过大" : 15
"配置不当" : 10
"硬件限制" : 5
二、问题定位三板斧
2.1 慢查询日志捕获
sql
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2; -- 单位秒
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
2.2 实时诊断利器
sql
-- 查看当前运行线程
SHOW PROCESSLIST;
-- 查看锁等待情况
SELECT * FROM information_schema.INNODB_TRX;
2.3 性能分析黄金搭档
sql
EXPLAIN FORMAT=JSON
SELECT * FROM orders WHERE user_id = 100 AND status = 'pending';
关键指标解读:
- type列:从ALL(全表扫描)到const(常量查询)
- rows列:预估扫描行数
- Extra列:Using filesort/Using temporary危险信号
三、索引优化实战手册
3.1 索引设计原则
- 最左前缀原则
- 区分度优先原则(高基数列在前)
- 覆盖索引策略
- 索引下推优化(ICP)
3.2 索引失效的十种场景
sql
-- 案例:隐式类型转换导致索引失效
SELECT * FROM users WHERE phone = 13800138000; -- phone是varchar类型
-- 正确写法
SELECT * FROM users WHERE phone = '13800138000';
3.3 复合索引优化示例
sql
-- 原始查询
SELECT * FROM orders
WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'
AND status = 'shipped'
ORDER BY amount DESC
LIMIT 100;
-- 优化索引方案
ALTER TABLE orders ADD INDEX idx_status_time_amount (status, create_time, amount);
四、SQL语句优化技巧
4.1 分页查询优化
sql
-- 传统分页(性能随offset增大而下降)
SELECT * FROM products ORDER BY id LIMIT 100000, 20;
-- 优化方案:游标分页
SELECT * FROM products WHERE id > 100000 ORDER BY id LIMIT 20;
4.2 Join查询优化
sql
-- 低效的嵌套循环Join
SELECT * FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id = u.id
);
-- 优化为Hash Join
SELECT u.*, o.order_no
FROM users u
STRAIGHT_JOIN orders o ON u.id = o.user_id;
4.3 批量操作优化
sql
-- 低效的逐条插入
INSERT INTO logs (content) VALUES ('log1');
INSERT INTO logs (content) VALUES ('log2');
-- 批量插入优化
INSERT INTO logs (content) VALUES
('log1'), ('log2'), ..., ('log1000');
五、高级优化策略
5.1 查询重写引擎
sql
-- 原始查询
SELECT DISTINCT department
FROM employees
WHERE salary > 100000;
-- 优化改写
SELECT department
FROM employees
WHERE salary > 100000
GROUP BY department;
5.2 数据归档策略
sql
-- 历史数据归档方案
CREATE TABLE orders_archive LIKE orders;
INSERT INTO orders_archive
SELECT * FROM orders
WHERE create_time < '2022-01-01';
DELETE FROM orders WHERE create_time < '2022-01-01';
5.3 参数调优要点
ini
# my.cnf关键配置
innodb_buffer_pool_size = 80% of total RAM
innodb_log_file_size = 1G
max_connections = 500
thread_cache_size = 100
六、全链路优化案例
案例背景
电商订单查询接口响应时间超过3秒,涉及表:
- orders(1000万条)
- users(500万条)
- products(50万条)
优化过程
- 慢日志分析:发现多表Join+排序导致临时表
- 执行计划解读:出现Using filesort和Using temporary
- 优化方案:
- 建立复合索引:(user_id, status, create_time)
- 重写查询为覆盖索引查询
- 增加内存排序缓冲区
优化前后对比
指标 | 优化前 | 优化后 |
执行时间 | 3.2s | 0.15s |
扫描行数 | 1.2M | 100 |
返回行数 | 1000 | 1000 |
七、性能监控体系
7.1 监控指标矩阵
- QPS/TPS波动
- 锁等待时间
- 缓冲池命中率
- 临时表创建次数
7.2 可视化工具栈
- Prometheus + Grafana监控
- Percona Monitoring and Management
- 阿里云DAS智能诊断
八、优化禁忌清单
- 禁止SELECT * 查询
- 避免在WHERE条件使用函数
- 警惕大事务中的慢查询
- 慎用OR条件组合查询
- 杜绝无限制的结果集返回
九、未来优化方向
- 基于机器学习的索引推荐(如Index Advisor)
- 云原生架构下的读写分离优化
- 分布式数据库的查询下推
- HTAP混合负载优化
结语:构建性能优化思维
优秀的数据库优化工程师需要具备:
- 全链路视角:从应用代码到硬件配置
- 数据敏感度:准确识别关键瓶颈点
- 平衡的艺术:在空间与时间、一致性与性能间取舍
记住:优化永无止境,但需遵循"二八定律",用20%的精力解决80%的性能问题。当面对海量数据时,有时改变数据组织方式(如分库分表)比单纯优化SQL更有效。持续监控、渐进优化,才能构建高性能的数据库体系。