从慢查询到秒响应:SQL索引优化与执行计划分析指南
你的数据库是不是总在关键时刻卡壳?
"每次点'查询'按钮就像在抽奖,运气好等3秒,运气差直接转圈圈..."——这是某物流公司程序员的真实吐槽。但说句大实话,90%的慢查询问题都能靠索引优化解决。今天咱们就手把手教你,用最简单的方式把龟速查询变成火箭速度。
一、??先逮住慢查询这个'元凶'??
"我都不知道哪些SQL慢,怎么优化?"这事儿好办,就像查监控找小偷。以MySQL为例:
- 开启慢查询日志:在配置文件加上这三行
ini复制slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 1 # 超过1秒的查询都记下来
- 用
mysqldumpslow
工具分析日志
bash复制mysqldumpslow -s t /var/log/mysql/slow.log | head -10
??真实案例??:某电商平台发现有个查询每天执行8000次,平均耗时5.2秒。你猜怎么着?就是个没加索引的订单状态筛选。
二、??索引不是随便建的,得讲究'门当户对'??
"我明明建了索引,怎么没效果?"八成是没对上查询条件。记住这个口诀:??WHERE条件用啥字段,索引就建啥字段??。比如:
sql复制SELECT * FROM users WHERE phone='13800138000' AND status=1
这时候就该建(phone, status)
联合索引,而不是单独给status建索引(因为status只有0/1两种值,区分度太低)。
??三大黄金原则??:
- ? ??最左匹配原则??:
INDEX(a,b,c)
能支持WHERE a=1
、WHERE a=1 AND b=2
,但用不上WHERE b=2
- ? ??覆盖索引优先??:如果索引包含所有查询字段,直接不用回表查数据
- ? ??别在索引列做计算??:
WHERE YEAR(create_time)=2023
会让索引失效
三、??执行计划就像CT扫描,一眼看穿SQL病灶??
在MySQL里敲个EXPLAIN
,你会看到这样的表格:
+----+-------------+-------+------+---------------+-----+---------+-----+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+-----+---------+-----+------+----------+-------------+
??重点盯住这三列??:
-
??type??:
- ALL(全表扫描):赶紧加索引
- index(全索引扫描):比ALL好点但仍有问题
- range(范围扫描):合格线
- const(常量查询):最优解
-
??rows??:预估扫描行数,超过1万就要警惕
-
??Extra??:
- Using filesort:说明在内存排序,考虑加索引优化排序
- Using temporary:用了临时表,可能需要重构查询
??实战分析??:某论坛的帖子列表查询耗时8秒,EXPLAIN
显示type=ALL、rows=120万。加上(category_id, create_time)
索引后,type变成range,rows降到800,查询时间缩短到0.3秒。
四、??联合索引的顺序比你想得更重要??
建联合索引就像搭积木,顺序错了全盘皆输。记住这个秘诀:??把筛选数据量少的字段放前面??。举个栗子:
- 用户表有100万数据
- 性别字段gender(男/女各50万)
- 城市字段city(北京用户10万)
如果要查WHERE gender='男' AND city='北京'
,应该建(city, gender)
。因为先通过city筛选出10万条,再用gender筛选5万条。反过来顺序的话,先筛选gender得到50万条,再用city筛选就慢多了。
五、??有时候删索引比加索引更管用??
见过一张表建了20多个索引吗?这会导致:
- 写数据变慢(每次INSERT都要更新所有索引)
- 查询优化器选择困难症(可能选错索引)
??该删就删的三种情况??:
- 超过半年没被使用的索引
- 区分度低的索引(比如status字段)
- 重复功能的索引(已有
(a,b)
索引,又单独建a
索引)
??血泪教训??:某金融系统删掉8个无用索引后,交易流水表的写入速度从每秒200条提升到1500条。
六、??执行计划里的隐藏彩蛋——索引下推??
MySQL5.6开始支持的??Index Condition Pushdown(ICP)?? 功能,能让查询再快一步。举个例子:
sql复制SELECT * FROM orders WHERE region='华东' AND amount>5000
如果建了(region,amount)
索引:
- 没有ICP时:先按region查所有'华东'订单,再回表筛选amount>5000
- 开启ICP后:直接在索引层完成region和amount的筛选,减少回表次数
??性能对比??:某物流公司的运单查询开启ICP后,CPU使用率下降40%,查询耗时从1.2秒降到0.4秒。
个人观点:优化是门平衡艺术
干了十年数据库调优,我发现新手最容易犯两个错误:要么无脑堆索引,要么过度追求极致。说点大实话:
- ??不要试图优化所有查询??,先抓TOP3慢查询
- ??索引维护成本常被忽视??,每次建索引前想想写入性能
- ??执行计划会骗人??,实际执行时间才是硬道理
- ??有时候硬件升级更划算??,特别是遇到历史遗留系统
就像老司机开车,该快的时候敢踩油门,该慢的时候会点刹车。下次遇到慢查询,别急着抓狂,按这个指南一步步来,保准让你的数据库跑得比外卖小哥还快。