你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。
文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读
SQL查询优化是提升数据库性能的核心手段之一,特别是当面对大量数据或复杂查询时,优化 SQL 查询能够显著减少数据库的响应时间。以下是几个常见的 SQL 查询优化技巧,并通过实际例子来详细说明每个优化方法。
索引是数据库查询的加速器。没有索引的查询,尤其是涉及大量数据时,可能会非常慢,因为数据库必须扫描整个表来查找匹配的记录。
假设有一个 users 表,如下所示:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
age INT
);
如果你经常按照 email 字段查询用户信息,你应该为 email 列创建索引,以加速查询。
-- 为 email 列创建索引
CREATE INDEX idx_email ON users(email);
优化前的查询:
SELECT * FROM users WHERE email = 'john.doe@example.com';
没有索引的情况下,数据库必须扫描整个表来查找匹配的记录,速度很慢。通过创建索引后,查询速度会显著提高。
如果查询经常涉及多个字段,例如按 name 和 age 查询,你可以创建一个复合索引:
-- 创建复合索引,优化多条件查询
CREATE INDEX idx_name_age ON users(name, age);
优化前的查询:
SELECT * FROM users WHERE name = 'John' AND age > 30;
有了复合索引后,查询会更高效,因为 MySQL 会使用复合索引来加速查询。
SELECT * 会选择所有列,这通常是不必要的,并且可能导致大量不必要的数据被返回。应该明确只选择所需的字段。
优化前的查询:
SELECT * FROM users WHERE id = 1;
假设你只关心 name 和 email 字段,使用 SELECT * 会返回所有字段,这样不但浪费资源,还会增加网络传输的开销。
优化后的查询:
SELECT name, email FROM users WHERE id = 1;
ORDER BY 会对查询结果进行排序,可能会导致性能下降,特别是当排序的列没有索引时。应尽量避免不必要的排序操作,或者确保排序的列上有索引。
优化前的查询:
SELECT * FROM users ORDER BY age DESC;
如果 age 字段上没有索引,ORDER BY 操作将会非常慢,尤其是当数据量很大时。你可以创建索引来加速排序:
-- 为 age 字段创建索引
CREATE INDEX idx_age ON users(age);
优化后的查询:
SELECT * FROM users ORDER BY age DESC;
有了索引后,排序操作将会变得更快。
在 WHERE 子句中使用函数会导致全表扫描,因为索引无法用于函数计算结果。
优化前的查询:
SELECT * FROM users WHERE YEAR(birthdate) = 1990;
YEAR(birthdate) 这样的查询会导致 birthdate 列上的索引失效,因为函数 YEAR(birthdate) 会先被计算,无法利用索引进行加速。
优化后的查询:
可以改为通过一个范围查询来避免函数的使用:
SELECT * FROM users WHERE birthdate >= '1990-01-01' AND birthdate < '1991-01-01';
这样可以利用 birthdate 上的索引,提高查询效率。
在查询中,如果你使用了多个表的连接(JOIN),要确保连接条件的字段上有索引,否则会导致全表扫描,影响性能。如果某个表的数据量非常大,考虑将查询拆解成多个小查询。
假设有两个表:users 和 orders,关系如下:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(255)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
order_date DATE,
amount DECIMAL
);
优化前的查询:
SELECT u.name, o.order_date, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.name = 'John' AND o.amount > 100;
如果 user_id 在 orders 表中没有索引,连接查询会非常慢,MySQL 需要进行全表扫描。解决办法是确保 orders 表中的 user_id 列有索引。
CREATE INDEX idx_user_id ON orders(user_id);
优化后查询性能会大幅提高。
IN 子句在处理大量数据时性能较差,尤其是当 IN 中包含大量值时。可以考虑将 IN 子句转化为 JOIN 或 EXISTS 子句来优化查询。
优化前的查询:
SELECT * FROM users WHERE id IN (1, 2, 3, 4, 5, ... , 1000);
当 IN 中的值很多时,MySQL 可能会进行全表扫描,查询性能差。
优化后的查询:
-- 使用 JOIN 替代 IN
SELECT u.*
FROM users u
JOIN (SELECT id FROM some_other_table WHERE some_condition) t ON u.id = t.id;
或者使用 EXISTS 来代替 IN:
SELECT *
FROM users u
WHERE EXISTS (SELECT 1 FROM some_other_table t WHERE u.id = t.id AND t.some_condition);
在大数据表上进行查询时,务必使用合适的索引,以避免全表扫描。对于没有索引的查询,可以考虑创建索引来加速查询。
优化前的查询:
SELECT * FROM large_table WHERE column1 = 'value';
如果 column1 没有索引,查询会非常慢。你可以为 column1 创建索引:
CREATE INDEX idx_column1 ON large_table(column1);
创建索引后,查询将利用索引加速。
如果查询的结果只需要一部分数据,使用 LIMIT 可以避免返回过多不必要的记录,减少数据库和网络的负担。
优化前的查询:
SELECT * FROM users ORDER BY created_at DESC;
如果只需要最新的 10 个用户,可以使用 LIMIT 来限制返回的记录数:
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;
MySQL 支持查询缓存功能,可以缓存常用的查询结果,避免重复执行相同的查询。尽管在现代的 MySQL 版本中(例如 5.7+)查询缓存已被弃用,但在适合的场景下(如查询频繁但数据更新不频繁),仍然可以启用查询缓存来提升性能。
SET GLOBAL query_cache_size = 1000000; -- 设置查询缓存大小
SET GLOBAL query_cache_type = 1; -- 启用查询缓存
SQL 查询优化涉及很多方面,包括合理使用索引、避免全表扫描、减少不必要的排序和计算、避免不合理的 JOIN、合理拆分查询等。通过对 SQL 查询的分析和调优,可以显著提高 MySQL 数据库的查询性能。通过使用 EXPLAIN 分析查询的执行计划、查看慢查询日志,结合这些优化方法,可以有效减少慢查询,提高系统的响应速度。
今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!