为什么要学查询优化?
想象一下,当你写了一条SQL查询,点击执行后却要等十几秒页面才加载出来——这时候用户可能已经放弃了。查询优化的核心目标就是让SQL更快执行,减少数据库负载,提升整个系统的响应速度。对初学者来说,掌握一些基础技巧,就能显著改善查询效率,避免“简单问题复杂化”。
一、新手最容易犯的3个查询错误¶
在优化之前,先看看你是否踩过这些坑:
1. 全表扫描:没加索引,让数据库从头遍历整个表(比如查询SELECT * FROM users WHERE name='小明',而name是大表的字段且无索引)。
2. SELECT :一次性取所有字段,导致大量不必要的数据传输和内存占用。
3. 滥用JOIN或复杂条件*:JOIN太多表、或在WHERE里用函数包裹索引字段(比如YEAR(create_time)=2023)。
二、5个必学的简单优化技巧¶
技巧1:给查询条件加索引(避免全表扫描)¶
问题:如果查询条件字段没有索引,数据库会“逐个检查”表中每一行,这就是“全表扫描”,数据量大时极其缓慢。
解决:给高频查询的字段加索引。
举例:
-- 未优化:全表扫描(假设users表有10万行,name无索引)
SELECT * FROM users WHERE name='小明';
-- 优化:给name加索引(执行一次,后续查询受益)
CREATE INDEX idx_name ON users(name);
-- 优化后:数据库直接通过索引定位数据,type从ALL变为ref(EXPLAIN可验证)
注意:
- 索引不是越多越好!写得越多,插入/更新/删除时维护索引的成本越高(比如用户表的id主键默认有索引,无需重复建)。
- 优先给“重复值少、查询条件多”的字段加索引(如user_id比username(可能重名)更合适)。
技巧2:避免SELECT *,只取需要的字段¶
问题:SELECT *会返回表中所有字段,包括大字段(如text类型),导致IO效率极低。
解决:明确列出需要的字段。
举例:
-- 错误:返回所有字段,包含大文本等冗余数据
SELECT * FROM orders;
-- 优化:只取核心字段(如id、order_no、amount)
SELECT id, order_no, amount FROM orders;
效果:数据量越大,SELECT *的劣势越明显,减少字段能直接降低网络传输和内存占用。
技巧3:优化JOIN操作:小表驱动大表¶
问题:JOIN多个表时,表的连接顺序错误会导致“大表被全表扫描”。
解决:用小表驱动大表(先过滤小表,再关联大表),且优先用INNER JOIN(只保留匹配的数据)。
举例:
-- 错误:大表orders在前,先全表扫描大表,再关联小表order_items
SELECT o.id, oi.product_id FROM orders o LEFT JOIN order_items oi ON o.id=oi.order_id WHERE o.status='已完成';
-- 优化:先过滤orders小表(假设status='已完成'的数据少),再关联order_items大表
SELECT o.id, oi.product_id FROM
(SELECT id FROM orders WHERE status='已完成') o -- 小表
LEFT JOIN order_items oi ON o.id=oi.order_id; -- 再关联大表
原理:数据库JOIN时会以“左表”为基准,小表数据少,遍历次数更少,效率更高。
技巧4:别在索引字段上用函数¶
问题:在WHERE条件中对索引字段用函数(如YEAR()、DATE()),会导致索引失效,重新全表扫描。
错误举例:
SELECT * FROM sales WHERE YEAR(sale_date)=2023; -- sale_date的索引被YEAR()函数“破坏”
解决:把函数逻辑移到字段本身,避免索引失效。
优化后:
-- 用BETWEEN代替函数,让索引生效
SELECT * FROM sales WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31';
技巧5:用EXPLAIN分析查询计划(关键!)¶
新手必学工具:EXPLAIN能帮你“看穿”SQL执行过程,快速定位问题。执行EXPLAIN + SQL,看输出的type列和Extra列:
- type列:ALL(全表扫描,差!改!)、ref(走索引,优)、eq_ref(主键关联,最好)。
- Extra列:Using filesort(排序无索引)、Using temporary(创建临时表)—— 遇到这些要警惕!
举例:
EXPLAIN SELECT * FROM users WHERE name='小明';
如果type是ALL,说明全表扫描;如果是ref,说明索引生效,查询快。
三、3个常见误区(避开就能少踩坑)¶
-
误区1:索引越多越好
索引会加速查询,但会拖慢插入/更新/删除。比如给users表的status(只有“0/1/2”三个值)建索引,反而让每次更新都要维护索引,得不偿失。 -
误区2:OR条件导致索引失效
用OR连接条件时,可能无法同时走多个索引。例如:
SELECT * FROM users WHERE id=1 OR name='张三'; -- 可能无法用id的索引
替代方案:用UNION ALL拆分条件(如果两个字段的索引可以独立使用):
(SELECT * FROM users WHERE id=1) UNION ALL (SELECT * FROM users WHERE name='张三');
- 误区3:COUNT(*) = 快
COUNT(*)统计行数很快(MySQL会直接走索引计数),但COUNT(DISTINCT name)会慢(需去重)。如果不需要去重,用COUNT(1)或COUNT(*)即可。
四、总结:从小技巧开始,逐步优化¶
- 先查再优化:用
EXPLAIN定位全表扫描、索引失效等问题。 - 基础技巧优先:加索引、
SELECT指定字段、优化JOIN顺序。 - 避免重复造轮子:网上已有很多优化案例,遇到问题多搜“EXPLAIN分析”“索引失效”等关键词。
记住:查询优化不是“玄学”,而是基于“减少数据处理量+合理利用索引”的科学方法。掌握这些基础技巧,你就能写出“一看就快”的SQL啦!