Skip to content

MySQL SQL 优化实战

TIP

SQL 优化是数据库性能调优的核心。良好的 SQL 写法可以指数级提升查询性能。

避免 SELECT *

sql
-- ❌ 坏习惯:查询所有列
SELECT * FROM user WHERE age > 18;

-- ✅ 只查需要的列
SELECT id, name, age FROM user WHERE age > 18;

合理使用索引

sql
-- ❌ 索引列上使用函数
SELECT * FROM user WHERE DATE(created_at) = '2024-01-01';

-- ✅ 改为范围查询(走索引)
SELECT * FROM user WHERE created_at >= '2024-01-01' AND created_at < '2024-01-02';

避免隐式类型转换

sql
-- ❌ phone 是 VARCHAR 类型
SELECT * FROM user WHERE phone = 1234567890;  -- 不走索引

-- ✅ 使用字符串
SELECT * FROM user WHERE phone = '1234567890';  -- 走索引

优化分页查询

sql
-- ❌ 传统分页(大偏移量时性能差)
SELECT * FROM user ORDER BY id LIMIT 100000, 10;

-- ✅ 子查询优化(利用索引覆盖)
SELECT * FROM user
WHERE id > (SELECT id FROM user ORDER BY id LIMIT 100000, 1)
ORDER BY id
LIMIT 10;

-- ✅ 记录上次最大值(适合滚动分页)
SELECT * FROM user WHERE id > 100000 ORDER BY id LIMIT 10;

优化 JOIN

sql
-- ✅ 小表驱动大表
-- 假设 user 表 100 行,order 表 10000 行
SELECT u.*, o.order_amount
FROM user u
INNER JOIN order o ON u.id = o.user_id  -- user 驱动 order

-- ✅ JOIN 字段要有索引
CREATE INDEX idx_user_id ON `order`(user_id);

使用 EXISTS 代替 IN

sql
-- ❌ IN 子查询
SELECT * FROM user WHERE id IN (
    SELECT user_id FROM order WHERE amount > 1000
);

-- ✅ EXISTS(子查询不会全表扫描)
SELECT * FROM user u WHERE EXISTS (
    SELECT 1 FROM `order` o WHERE o.user_id = u.id AND o.amount > 1000
);

使用 UNION ALL 代替 UNION

sql
-- ❌ UNION 会去重排序(额外开销)
SELECT name FROM user
UNION
SELECT name FROM old_user;

-- ✅ UNION ALL 直接合并(如果不需要去重)
SELECT name FROM user
UNION ALL
SELECT name FROM old_user;