SQL的性能不在于语法多复杂,而在于是否符合数据库的执行逻辑。一条SQL在数据库内部的执行顺序,决定了我们如何写出高效的查询。
SQL的“秘密执行顺序”
这是SQL语句在数据库内部的真实执行顺序,也是优化的核心逻辑:
1. FROM 与 JOIN -- 确定数据来源2. WHERe -- 初步筛选3. GROUP BY -- 分组聚合4. HAVINg -- 对分组后筛选5. SELECt -- 选择字段6. DISTINCT -- 去重7. ORDER BY -- 排序8. LIMIT/OFFSET -- 限制结果记住这个顺序,你的SQL优化就成功了一半。
优化实战:让SQL按“正确顺序”工作
案例1:WHERe要尽早过滤
低效写法:
SELECT user_id, COUNT(*) FROM orders GROUP BY user_id HAVINg user_id IN (SELECt id FROM users WHERe status = 'active');-- 先对所有订单分组,再用子查询过滤高效写法:
SELECt o.user_id, COUNT(*) FROM orders oJOIN users u ON o.user_id = u.id AND u.status = 'active'GROUP BY o.user_id;-- 先过滤活跃用户,再分组统计原理:在FROM/JOIN阶段就过滤数据,减少后续处理的数据量。
案例2:避免在WHERe中对字段进行计算
低效写法:
SELECt * FROM orders WHERe YEAR(create_time) = 2024 AND MonTH(create_time) = 1;-- 每行都要计算YEAR()和MonTH(),无法使用索引高效写法:
SELECt * FROM orders WHERe create_time >= '2024-01-01' AND create_time < '2024-02-01';-- 直接使用索引范围查询案例3:JOIN的顺序优化
低效写法:
SELECt * FROM large_table lJOIN small_table s ON l.id = s.large_idWHERe l.category = 'A';-- 先对300万行的大表做JOIN高效写法:
SELECt * FROM (SELECt * FROM large_table WHERe category = 'A') lJOIN small_table s ON l.id = s.large_id;-- 先用WHERe将大表从300万行过滤到1万行案例4:SELECt只取需要的列
低效写法:
SELECT * FROM users WHERe age > 20 ORDER BY create_time DESC LIMIT 100;-- 读取所有字段,包括不必要的大文本字段高效写法:
SELECt id, name, age, create_time FROM users WHERe age > 20 ORDER BY create_time DESC LIMIT 100;-- 只读取实际需要的字段关键优化原则
1. 索引生效的黄金法则
- 索引在WHERe、JOIN、ORDER BY阶段使用
- 遵循最左前缀原则
- 避免对索引列进行运算或函数处理
2. 减少中间数据集
-- 错误:产生大量中间数据SELECt * FROM ( SELECt * FROM logs WHERe level = 'ERROR') t ORDER BY time DESC LIMIT 10;-- 正确:尽早应用LIMITSELECt * FROM logs WHERe level = 'ERROR' ORDER BY time DESC LIMIT 10;3. EXPLAIN是你的最佳工具
每个优化都要用EXPLAIN验证:
EXPLAIN SELECt u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id WHERe u.created_at > '2024-01-01'GROUP BY u.id HAVINg COUNT(o.id) > 5;关注:
- type列:ALL(全表扫描)→ index → range → ref → eq_ref → const
- rows列:估算扫描行数
- Extra列:Using filesort、Using temporary需要警惕
实战:一条SQL的完整优化
原始查询(执行慢):
SELECt DISTINCT u.*, (SELECT COUNT(*) FROM orders o WHERe o.user_id = u.id) as order_countFROM users uLEFT JOIN orders o ON u.id = o.user_idWHERe u.status = 'active' AND o.amount > 1000ORDER BY u.create_time DESC;优化步骤:
1.移除不必要的DISTINCT
SELECt u.*, COUNT(o.id) as order_countFROM users uJOIN orders o ON u.id = o.user_id WHERe u.status = 'active' AND o.amount > 1000GROUP BY u.idORDER BY u.create_time DESC;2.添加合适索引
CREATE INDEX idx_users_status ON users(status);CREATE INDEX idx_orders_user_amount ON orders(user_id, amount);3.使用覆盖索引进一步优化
SELECt u.id, u.name, u.email, u.create_time, COUNT(o.id) as order_countFROM users uJOIN orders o ON u.id = o.user_id WHERe u.status = 'active' AND o.amount > 1000GROUP BY u.idORDER BY u.create_time DESC;总结:高效SQL的四个层次
- 基础层:正确使用WHERe提前过滤
- 索引层:确保查询能用上合适的索引
- 结构层:优化JOIN顺序和子查询
- 存储层:考虑分库分表、读写分离
记住:数据库是按照固定顺序执行SQL的,你的任务就是让这个执行过程尽可能高效。 每次写SQL时,心里默念执行顺序,思考如何让每一步处理的数据量最小化,这就是SQL优化的核心秘诀。
好的SQL不是复杂的SQL,而是符合数据库思维的SQL。
