-
10个SQL优化技巧,性能提升300%(sql优化从哪几方面入手)
- 网站名称:10个SQL优化技巧,性能提升300%(sql优化从哪几方面入手)
- 网站分类:技术文章
- 收录时间:2025-08-03 01:43
- 网站地址:
“10个SQL优化技巧,性能提升300%(sql优化从哪几方面入手)” 网站介绍
环境:SpringBoot3.4.2
1. 简介
SQL作为数据库交互的核心语言,其查询效率直接决定着应用的响应速度与资源消耗。低效的SQL语句(如全表扫描、无索引查询、复杂嵌套子句等)可能让数据库陷入"CPU狂飙、内存耗尽"的困境,导致系统响应延迟数秒甚至宕机,尤其在处理千万级数据时,性能瓶颈更会指数级放大。而一次精准的SQL优化,往往能让查询耗时从分钟级压缩至毫秒级,显著降低服务器负载,提升用户体验。
本文将通过10个SQL优化实战技巧,助你轻松应对慢查询性能顽疾,让数据库成为应用的"性能引擎"而非"拖油瓶"。
2.实战案例
2.1 能用 GROUP BY 替代时避免使用 DISTINCT
慢查询
SELECT DISTINCT customer_id FROM orders
优化后
SELECT customer_id FROM orders GROUP BY customer_id
数据库引擎对 GROUP BY 的优化有时优于 DISTINCT,尤其在查询字段包含索引列时,而DISTINCT需要额外创建临时表。
2.2 UNION ALL 替代 OR(索引列)
慢查询
SELECT * FROM products WHERE category = 'Electronics' OR category = 'Books'
优化后
SELECT * FROM products WHERE category = 'Electronics'
UNION ALL
SELECT * FROM products WHERE category = 'Books'
当查询条件中有OR且涉及索引列时,使用UNION ALL可以让数据库分别对每个条件使用索引,避免全表扫描。而OR可能导致索引失效,特别是当两个条件涉及不同列时。
2.3 避免对索引列使用函数操作
慢查询
SELECT * FROM users WHERE UPPER(username) = 'JOHNDOE';
优化后
-- 存储时统一大写化,或直接搜索原始值而不应用函数
SELECT * FROM users WHERE username = 'JohnDoe';
函数操作(如UPPER(username))会破坏索引的有序性,导致全表扫描。如果你的mysql版本在8.0.13+以上版本,则可以创建函数索引:
# 注意这里函数索引,需要用括号 "()"
create index idx_name on t_person ((UPPER(username)));
2.4 对大型子查询使用 EXISTS 替代 IN
慢查询
SELECT
*
FROM
orders
WHERE
customer_id IN ( SELECT customer_id FROM blacklist )
优化后
SELECT * FROM orders o WHERE EXISTS (
SELECT 1 FROM blacklist b WHERE b.customer_id = o.customer_id
);
IN 对小型数据集表现良好(此时与EXISTS性能差异可忽略),但当子查询涉及大型数据集或关联查询(Correlated Subquery)时,EXISTS 的性能更优。
2.5 使用覆盖索引
慢查询
SELECT
order_id,
customer_id
FROM
orders
WHERE
order_date >= '2025-05-10'
优化后
CREATE INDEX idx_date_oid_cid ON orders(order_date, order_id, customer_id)
覆盖索引包含查询所需的所有列,数据库无需回表读取数据页(称为 "Index Only Scan")。需要注意:索引列顺序需与查询字段顺序一致,且查询条件包含索引前缀列。
2.6 对大型表进行分区(Partitioning)
预估 orders 表 可能达到上千万的数据量甚至亿级。那么我们在建立表时就针对某个字段建立分区,比如:根据订单的时间字段,如下示例:
CREATE TABLE `t_orders` (
`id` int NOT NULL,
`custom_id` varchar(255) DEFAULT NULL,
`order_no` varchar(255) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
`total_amount` decimal(9,2) DEFAULT NULL,
`order_date` datetime NOT NULL,
PRIMARY KEY (`id`, `order_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
PARTITION BY RANGE COLUMNS(order_date) (
PARTITION p202501 VALUES LESS THAN ('2025-02-01'),
PARTITION p202502 VALUES LESS THAN ('2025-03-01'),
-- 其它月份
PARTITION p202512 VALUES LESS THAN ('2026-01-01'),
PARTITION pfuture VALUES LESS THAN MAXVALUE
);
插入如下数据:
执行如下查询计划
从指定的分区查询数据。
适用场景:时间范围查询(如按日期分区)、区域查询等。
注意:分区键需与查询条件一致,否则可能失效。
2.7 用 UNION ALL 替代 OR
优化前
SELECT
*
FROM
products
WHERE
category = 'Electronics' OR price > 2000
上面SQL执行计划如下:
没有走索引。
优化后
SELECT * FROM products WHERE category = 'PS5'
UNION ALL
SELECT * FROM products WHERE price > 2000;
查看该SQL的执行计划
OR 条件常导致索引失效,而 UNION ALL 可分别对两部分条件使用索引扫描。影响:对大型表可提速 10-100 倍。
2.8 用 NOT EXISTS 替代 NOT IN
优化前
SELECT * FROM customers
WHERE id NOT IN (SELECT customer_id FROM orders)
优化后
SELECT * FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
)
NOT IN对子查询结果中的NULL值敏感(若子查询含NULL,NOT IN永远返回空),而NOT EXISTS无此问题。对大型子查询可提速 5-50 倍。
2.9 使用LIMIT限制ORDER BY结果集
优化前
SELECT * FROM products ORDER BY price DESC
优化后
SELECT * FROM products ORDER BY price DESC LIMIT 10
原查询需对全表数据排序(开销巨大),而 LIMIT 可仅返回前 N 条记录,避免不必要的全表排序。
2.10 使用JOIN替代子查询
优化前
SELECT
*
FROM
employees
WHERE
department_id IN ( SELECT id FROM departments WHERE active = 1 );
优化后
SELECT
e.*
FROM
employees e
JOIN departments d ON e.department_id = d.id
WHERE
d.active = 1
数据库对 JOIN 操作的优化更高效(如合并连接、哈希连接等),而子查询可能触发多次扫描或临时表生成。
更多相关网站
- 面试官问你 MySQL 的线上执行 DDL 该怎么做?...
- MySQL 8.0 的隐藏索引:索引管理的利器,还是性能陷阱?
- MySQL实战:Json字段类型详解(mysql中json类型)
- Spring事务失效的12种解决方案!15年踩坑经验浓缩成这份避雷指南
- 面试官:select语句和update语句分别是怎么执行的?
- 详细了解 InnoDB 内存结构及其原理
- 深度剖析 Spring Boot3 中事务失效的场景与解决方案
- java 使用Jdbc连接mysql数据库以及其存在的问题
- 百万订单背后的架构生死局:SpringCloud Alibaba拯救我们的微服务
- 面试官:20 亿手机号存储选 int 还是 string?varchar 还是 char?
- 面试官:MySQL的自增ID用完了,怎么办?
- 别再用雪花算法生成ID了!试试这个吧
- # mysql 中文乱码问题分析(#mysql5.0中文乱码)
- MySQL分页到了后面越来越慢,有什么好的解决办法?
- Spring Boot3 中实现树表结构数据查询及返回全解析
- SQL外连接优化:经过验证的性能提升
- zPaaS低代码平台使用介绍:第一个功能开发
- 面试官:你对索引了解多少,展开说说
- 最近发表
-
- 基于jeecgboot框架的cloud商城源码分享,兼容单体和微服务模式
- 值得学习的15 个优秀开源的 Spring Boot 学习项目
- 基于SpringBoot低代码平台(基于spring boot)
- 火山引擎基于 Zeppelin 的 Flink/Spark 云原生实践
- 十款优质企业级Java微服务开源项目(开源框架,公司项目等)
- 可以直接拿来做项目的开源框架(可以直接拿来做项目的开源框架是什么)
- Github 2024-05-10 Java开源项目日报 Top10
- 推荐这款企业级!物联网平台支持NB-IoT、蜂窝网络等多种接入方式
- 开源的面向中小企业的进销存管理系统
- Jeecgboot3.2版-postgres脚本制作
- 标签列表
-
- mydisktest_v298 (35)
- sql 日期比较 (33)
- document.appendchild (35)
- 头像打包下载 (35)
- 二调符号库 (23)
- acmecadconverter_8.52绿色版 (25)
- 梦幻诛仙表情包 (36)
- 魔兽模型 (23)
- java面试宝典2019pdf (26)
- disk++ (30)
- 加密与解密第四版pdf (29)
- iteye (26)
- centos7.4下载 (32)
- intouch2014r2sp1永久授权 (33)
- usb2.0-serial驱动下载 (24)
- jdk1.8.0_191下载 (27)
- axure9注册码 (30)
- virtualdrivemaster (26)
- 数据结构c语言版严蔚敏pdf (25)
- 兔兔工程量计算软件下载 (27)
- 代码整洁之道 pdf (26)
- ccproxy破解版 (31)
- aida64模板 (28)
- engine=innodb (33)
- shiro jwt (28)