SQL优化实战:如何让查询速度提升10倍

前言

数据分析师工作中,SQL是最核心的技能之一。但很多人的SQL写得很慢,查询跑了10分钟还不出结果,严重影响工作效率。

本文结合实际案例,分享SQL优化的核心思路,帮助你把查询速度从10分钟优化到1分钟以内。

一、为什么SQL会慢

SQL查询慢的本质原因只有一个:扫描了太多数据。理解这一点,所有的优化手段都能推导出来。

常见的慢查询原因:

  • SELECT * 全表扫描
  • WHERE条件没有索引
  • JOIN没有正确的连接条件
  • GROUP BY/DISTINCT 数据量太大
  • 子查询嵌套层数过多

二、案例分析:订单报表优化

2.1 原始查询(耗时8分钟)

复制代码
SELECT 
    o.order_id,
    o.user_id,
    o.order_time,
    o.amount,
    u.username,
    u.city,
    p.product_name,
    p.category
FROM orders o
LEFT JOIN users u ON o.user_id = u.user_id
LEFT JOIN order_items oi ON o.order_id = oi.order_id
LEFT JOIN products p ON oi.product_id = p.product_id
WHERE o.order_time >= '2025-01-01'
    AND o.order_time < '2026-01-01'
    AND u.city IN ('北京', '上海', '广州', '深圳')
ORDER BY o.order_time DESC;

2.2 优化思路

第一步:添加合适的索引

复制代码
-- 为 WHERE 条件字段添加索引
CREATE INDEX idx_orders_time ON orders(order_time);
CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_users_city ON users(city);

-- 为 JOIN 字段添加索引
CREATE INDEX idx_order_items_order ON order_items(order_id);
CREATE INDEX idx_products_id ON products(product_id);

第二步:减少扫描范围

复制代码
-- 先筛选再JOIN,减少中间数据量
SELECT 
    o.order_id,
    o.user_id,
    o.order_time,
    o.amount,
    u.username,
    u.city,
    p.product_name,
    p.category
FROM (
    -- 先筛选主表
    SELECT order_id, user_id, order_time, amount
    FROM orders
    WHERE order_time >= '2025-01-01'
      AND order_time < '2026-01-01'
) o
LEFT JOIN (
    -- 再筛选用户表
    SELECT user_id, username, city
    FROM users
    WHERE city IN ('北京', '上海', '广州', '深圳')
) u ON o.user_id = u.user_id
LEFT JOIN order_items oi ON o.order_id = oi.order_id
LEFT JOIN products p ON oi.product_id = p.product_id
ORDER BY o.order_time DESC;

第三步:用EXISTS替代IN(适用于子查询)

复制代码
-- 优化前(IN子查询)
SELECT * FROM orders 
WHERE user_id IN (
    SELECT user_id FROM users WHERE city = '北京'
);

-- 优化后(EXISTS)
SELECT * FROM orders o
WHERE EXISTS (
    SELECT 1 FROM users u 
    WHERE u.city = '北京' AND u.user_id = o.user_id
);

2.3 优化结果

优化阶段 耗时 说明
原始查询 8分钟 全表扫描
添加索引 3分钟 索引生效
减少扫描 45秒 先筛再JOIN
最终优化 12秒 综合优化

提升倍数:40倍

三、常用优化技巧总结

3.1 索引优化

复制代码
-- 组合索引遵循最左前缀原则
-- 创建组合索引
CREATE INDEX idx_col1_col2 ON table_name(col1, col2);

-- 查询能命中索引的情况
WHERE col1 = 'xxx'           -- ✅ 命中
WHERE col1 = 'xxx' AND col2 = 'yyy'  -- ✅ 命中
WHERE col2 = 'yyy'           -- ❌ 不命中

-- 避免在索引列上使用函数
WHERE YEAR(create_time) = 2025        -- ❌ 不命中索引
WHERE create_time >= '2025-01-01'    -- ✅ 命中索引

3.2 LIMIT分页优化

复制代码
-- 优化前(深分页慢)
SELECT * FROM orders 
ORDER BY order_id 
LIMIT 1000000, 20;

-- 优化后(基于ID分页)
SELECT * FROM orders 
WHERE order_id > 1000000
ORDER BY order_id 
LIMIT 20;

3.3 COUNT优化

复制代码
-- 优化前(COUNT * 全表扫描)
SELECT COUNT(*) FROM orders WHERE status = 1;

-- 优化后(使用索引计数)
SELECT COUNT(1) FROM orders WHERE status = 1;

-- 或者维护统计表(实时性要求不高时)

四、如何判断SQL性能

使用 EXPLAIN 分析执行计划:

复制代码
EXPLAIN SELECT * FROM orders WHERE order_time >= '2025-01-01';

-- 关键字段说明:
-- type: 连接类型(const > eq_ref > ref > range > ALL)
-- key: 实际使用的索引
-- rows: 预计扫描行数
-- Extra: 额外信息(Using index, Using filesort等)

五、总结

SQL优化的核心原则:

  • 减少数据扫描量:WHERE条件尽量精确
  • 合理使用索引:为高频查询字段建索引
  • 避免全表扫描:不用SELECT *,少用函数
  • 优化JOIN顺序:小表驱动大表
  • 分析执行计划:用EXPLAIN定位问题

记住:SQL优化是一个持续的过程,没有银弹,只有不断分析和迭代。


作者简介:船长,数据分析师,关注数据分析、职场成长、投资理财。

相关推荐
Apache IoTDB1 天前
时序数据库 IoTDB + 时序智能服务平台 TimechoAI 亮相中国核电信息技术高峰论坛
数据库·时序数据库·iotdb
未若君雅裁1 天前
Redis 和 MySQL 双写一致性:延迟双删、读写锁、MQ、Canal 怎么选?
数据库·redis·面试
罗超驿1 天前
9.深度剖析MySQL约束的工程设计:自增主键的分布式局限、外键约束的权衡,与CHECK的版本适配实践
数据库·mysql
Kiyra1 天前
Agent 的记忆不是存数据库就行:上下文预算与轻量记忆的设计实战
数据库·人工智能·后端·面试·职场和发展·哈希算法
jiayong231 天前
MySQL 8.0 数据库恢复问题完整解决方案
数据库·mysql
ChaITSimpleLove1 天前
优化 WSL2 性能:为 Docker 和 K8s 定制高效内存配置指南
docker·容器·性能优化·kubernetes·wsl2·windows开发·pwsh
czlczl200209251 天前
普通索引和唯一索引 查询性能差异
数据库
@小柯555m1 天前
MySql(正则表达式--电话号码格式校验)
数据库·sql·mysql·正则表达式
van久1 天前
Day29:Redis 缓存实战
数据库·redis·缓存
源码之家1 天前
计算机毕业设计:Python医疗数据分析可视化系统 Flask框架 随机森林 机器学习 疾病数据 智慧医疗 深度学习(建议收藏)✅
python·机器学习·信息可视化·数据分析·flask·课程设计