SQL全知全解之性能优化~性能优化十个小技巧!
注:本期视频需要一点SQL语法基础,如果对基础有疑问的可以参考上期文章<MySQL基础全知全解>~
本期内容乏味且枯燥,如有需要或是想要了解学习请耐心观看。
<( ̄︶ ̄)↗[GO!GO!GO!]
全篇文字2000+
在数据库管理和应用开发中,SQL 查询的性能优化至关重要。高效的 SQL 查询不仅可以提高应用的响应速度,还能降低服务器负载,提升用户体验。接下来,我将分享 SQL 优化的实用技巧,并结合具体代码示例,帮助你构建高效、稳定的数据库应用( ̄︶ ̄)↗
1、查询设计优化
(一)选择合适的查询字段
只检索需要的列,避免使用SELECT *。例如,如果只需要用户的姓名和年龄,应写成:
SELECT name, age FROM users;
而不是SELECT * FROM users。这样可以减少数据传输量,提高查询性能。
(二)使用索引
为经常用于查询条件(如WHERE子句)、连接条件(JOIN子句)的列创建索引。假设存在orders表,经常根据订单日期order_date进行查询,可通过以下语句创建索引:
CREATE INDEX idx_order_date ON orders (order_date);
注意:索引不是越多越好,过多的索引会增加插入、更新和删除操作的成本。
(三)避免使用子查询(在适当的时候)
有时候子查询可以用连接(JOIN)来代替。
例如,查询每个部门的员工人数,使用连接的方式:
SELECT d.department_name, COUNT(e.employee_id)
FROM departments d
JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_name;
比使用子查询更高效一丝丝( ̄︶ ̄)↗
(四)优化子查询(当必须使用时)
如果子查询不可避免,确保子查询的条件尽可能简单。比如,从orders表中查询金额大于平均订单金额的订单,优化后的子查询代码:
SELECT * FROM orders
WHERE order_amount > (
SELECT AVG(order_amount)
FROM orders
);
避免在子查询中进行复杂计算,如:
-- 不推荐,子查询包含复杂计算
SELECT *
FROM orders
WHERE order_amount > (
SELECT SUM(order_amount) COUNT(*)
FROM orders
WHERE order_date >= '2024-01-01' AND order_date <= '2024-12-31'
);
(五)使用临时表(谨慎使用)
对于复杂的查询,有时可以将中间结果存储在临时表中。例如,先查询出每个月的订单总金额存入临时表,再基于临时表查询总金额最高的月份:
-- 创建临时表存储每个月订单总金额
CREATE TEMPORARY TABLE monthly_order_total AS
SELECT
YEAR(order_date) AS order_year,
MONTH(order_date) AS order_month,
SUM(order_amount) AS total_amount
FROM
orders
GROUP BY
YEAR(order_date), MONTH(order_date);
-- 从临时表查询总金额最高的月份
SELECT
order_year,
order_month,
total_amount
FROM
monthly_order_total
WHERE
total_amount = (SELECT MAX(total_amount) FROM monthly_order_total);
创建和维护临时表会占用额外资源。
(六)避免使用OR条件(在可能的情况下)
OR条件可能会使查询优化器无法有效地使用索引。如果可能,可以将OR条件转换为UNION操作。例如,查询年龄为 20 岁或者姓名为 “张三” 的用户:
-- 不太好的写法
SELECT * FROM users WHERE age = 20 OR name = '张三';
-- 较好的写法
SELECT * FROM users WHERE age = 20
UNION
SELECT * FROM users WHERE name = '张三';
(七)使用EXISTS代替IN(在适当的时候)
当子查询结果集较大时,EXISTS通常比IN更高效。例如,查询有订单的用户:
EXISTS一旦找到匹配的记录就会停止查询子查询。
-- 使用EXISTS
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE u.user_id = o.user_id);
-- 使用IN
SELECT * FROM users u
WHERE u.user_id IN (SELECT user_id FROM orders);
<EXISTS>注解:EXISTS子查询只关注子查询是否能返回结果行,而不关心返回的具体数据内容 。使用SELECT 1,这里的1可以替换为任何常量(如SELECT 0、SELECT 'x'等),数据库不会实际去获取和处理这个值,只是判断子查询是否有数据返回。如果子查询(SELECT 1 FROM orders o WHERE u.user_id = o.user_id)能找到满足条件的记录,即存在与users表中某用户关联的订单记录,那么EXISTS条件就为TRUE,主查询会将对应的用户记录选取出来。
(八)优化GROUP BY和HAVING子句
确保GROUP BY子句中的列是索引的一部分,这样可以提高分组操作的性能。对于HAVING子句,尽量将过滤条件放在WHERE子句中(如果可能)。比如,查询平均订单金额大于 100 且订单数量大于 5 的用户:
-- 较好的写法,先在WHERE过滤数据,再分组和HAVING过滤
SELECT user_id, AVG(order_amount) AS avg_amount, COUNT(*) AS order_count
FROM orders
WHERE order_amount > 50 -- 提前过滤
GROUP BY user_id
HAVING AVG(order_amount) > 100 AND COUNT(*) > 5;
-- 不好的写法,未在WHERE过滤
SELECT user_id, AVG(order_amount) AS avg_amount, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
HAVING AVG(order_amount) > 100 AND COUNT(*) > 5 AND order_amount > 50;
(九)优化DISTINCT操作
如果DISTINCT操作涉及的列有索引,可以提高查询效率。并且尽量减少使用DISTINCT。例如,查询唯一的部门名称:
-- 假设department_name列有索引
SELECT DISTINCT department_name FROM departments;
(十)优化ORDER BY子句
对 <ORDER BY> 子句中的列创建索引,可以加快排序速度。如果可能,将ORDER BY和LIMIT结合使用,减少排序的数据量。例如,查询工资最高的前 10 名员工:
-- 假设salary列有索引
SELECT * FROM employees ORDER BY salary DESC LIMIT 10;
以上就是本期分享的SQL语法上的十个优化小技巧啦,如果本期文章对你有所帮助,请点赞收藏一下吧!同时SQL优化不仅仅在于语法上,合理的表结构设计、数据库配置等也是至关重要的。
结尾彩蛋:本期特别枯燥,能看到末尾说明你很希望提升自己的SQL相关能力,这里准备了一份小“礼物”,私信“SQL学习”则可获得一份关于 <高性能SQL全解> 的相关资料哦~