前言
"苏工,订单列表又崩了!"
接到电话时,我对着监控大屏上999ms的SQL响应时间哭笑不得。
几年来,我发现一个定律:所有SQL问题都是在凌晨三点爆发!
今天抽丝剥茧,教你用架构师的思维给慢SQL开刀手术。
希望对你会有所帮助。
1 术前检查:找准病灶
1.1 EXPLAIN 查看执行计划
使用EXPLAIN查看SQL语句的执行计划,相当于给SQL拍了张X光。
下面是一个典型的SQL问题,它是某电商平台历史订单查询的SQL语句:
SELECT * FROM orders o LEFT JOIN users u ON o.user_id = u.id LEFT JOIN products p ON o.product_id = p.id WHERE o.create_time > '2023-01-01' AND u.vip_level > 3 AND p.category_id IN (5,8) ORDER BY o.amount DESC LIMIT 1000,20;
使用EXPLAIN关键字查看执行计划的结果如下:
+----+-------------+-------+------+---------------+------+---------+------+---------+---------------------------------+ | id | select_type | table | type | possible_keys | key | rows | Extra| key_len | +----+-------------+-------+------+---------------+------+---------+------+---------+---------------------------------+ | 1 | SIMPLE | o | ALL | idx_user_time | NULL | 1987400 | Using where; Using filesort | | 1 | SIMPLE | u | ALL | PRIMARY | NULL | 100000 | Using where | | 1 | SIMPLE | p | ALL | PRIMARY | NULL | 50000 | Using where | +----+-------------+-------+------+---------------+------+---------+------+---------+---------------------------------+
诊断报告:
- 全表扫描三连击(type=ALL)
- filesort暴力排序(内存警告)
- 索引全军覆没
技术大厂[跳板][跳板],前后端测试捞人,待遇还可以,感兴趣可以试试~
2 手术方案:精准打击
2.1 单表代谢手术
如果通过执行计划查到是索引有问题,我们就需要单独优化索引。
病根:JSON字段索引失效
错误用法:
ALTER TABLE users ADD INDEX idx_extend ((extend_info->'$.is_vip'));
extend_info字段是JSON类型的字段,即使创建了索引,索引也会丢失。
正解姿势(MySQL 8.0+):
ALTER TABLE users ADD INDEX idx_vip_level (vip_level); ALTER TABLE orders ADD INDEX idx_create_user (create_time, user_id) COMMENT '组合索引覆盖查询';
创建组合索引覆盖查询。
2.2 血管疏通术
卡点分析:
原始join顺序是:
orders → users → products
优化后的方案:
(子查询过滤users) → products → orders
调整执行顺序,用小表驱动大表。
重写后的SQL:
SELECT o.* FROM products p INNER JOIN ( SELECT o.id, o.amount, o.create_time FROM orders o WHERE o.create_time > '2023-01-01' ) o ON p.id = o.product_id INNER JOIN ( SELECT id FROM users WHERE vip_level > 3 ) u ON o.user_id = u.id WHERE p.category_id IN (5,8) ORDER BY o.amount DESC LIMIT 1000,20;
术后效果:
- 先扫小表(users过滤后只有100条)
- 消除冗余字段传输
- 减少Join时临时表生成
2.3 开颅手术
通过执行计划锁定了问题,走错索引了,该怎么处理呢?
可以通过FORCE INDEX强制指定索引:
SELECT /*+ INDEX(o idx_create_user) */ o.id, o.amount FROM orders o FORCE INDEX (idx_create_user) WHERE o.create_time > '2023-01-01';
使用衍生表加速:
SELECT * FROM ( SELECT id, amount FROM orders WHERE create_time > '2023-01-01' ORDER BY amount DESC LIMIT 1020 ) tmp ORDER BY amount DESC LIMIT 1000,20;
医嘱:
- 警惕OR导致的索引失效
- 用覆盖索引避免回表查询
- CTE表达式谨慎使用
2.4 生命体征监测
查看索引使用:
SHOW INDEX FROM orders;
监控索引使用率:
SELECT object_schema, object_name, index_name, count_read, count_fetch FROM performance_schema.table_io_waits_summary_by_index_usage WHERE index_name IS NOT NULL;
——转载自:苏三说技术#畅聊专区#


登录 或 注册 后才可以进行评论哦!
还没有评论,抢个沙发!