首页 > 趣闻 > 正文内容

从慢查询到秒响应:SQL索引优化与执行计划分析指南

趣闻2025-05-27 14:36:45

你的数据库是不是总在关键时刻卡壳?

"每次点'查询'按钮就像在抽奖,运气好等3秒,运气差直接转圈圈..."——这是某物流公司程序员的真实吐槽。但说句大实话,90%的慢查询问题都能靠索引优化解决。今天咱们就手把手教你,用最简单的方式把龟速查询变成火箭速度。


一、??先逮住慢查询这个'元凶'??

"我都不知道哪些SQL慢,怎么优化?"这事儿好办,就像查监控找小偷。以MySQL为例:

  1. 开启慢查询日志:在配置文件加上这三行
ini复制
slow_query_log = 1  
slow_query_log_file = /var/log/mysql/slow.log  
long_query_time = 1  # 超过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=1WHERE 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       |
+----+-------------+-------+------+---------------+-----+---------+-----+------+----------+-------------+

??重点盯住这三列??:

  1. ??type??:

    • ALL(全表扫描):赶紧加索引
    • index(全索引扫描):比ALL好点但仍有问题
    • range(范围扫描):合格线
    • const(常量查询):最优解
  2. ??rows??:预估扫描行数,超过1万就要警惕

  3. ??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多个索引吗?这会导致:

  1. 写数据变慢(每次INSERT都要更新所有索引)
  2. 查询优化器选择困难症(可能选错索引)

??该删就删的三种情况??:

  1. 超过半年没被使用的索引
  2. 区分度低的索引(比如status字段)
  3. 重复功能的索引(已有(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秒。


个人观点:优化是门平衡艺术

干了十年数据库调优,我发现新手最容易犯两个错误:要么无脑堆索引,要么过度追求极致。说点大实话:

  1. ??不要试图优化所有查询??,先抓TOP3慢查询
  2. ??索引维护成本常被忽视??,每次建索引前想想写入性能
  3. ??执行计划会骗人??,实际执行时间才是硬道理
  4. ??有时候硬件升级更划算??,特别是遇到历史遗留系统

就像老司机开车,该快的时候敢踩油门,该慢的时候会点刹车。下次遇到慢查询,别急着抓狂,按这个指南一步步来,保准让你的数据库跑得比外卖小哥还快。

搜索