避免 SELECT *
很多人写查询时习惯用 SELECT *,觉得省事。但其实这会把所有字段都拉出来,哪怕你只用其中两三个。比如查用户表,如果只关心用户名和邮箱,却把密码哈希、创建时间、最后登录IP全捞一遍,网络和内存都在做无用功。应该明确写出需要的字段:
SELECT username, email FROM users WHERE status = 1;
善用索引,但别滥用
索引就像书的目录,能快速定位数据。但不是每个字段都适合加索引。比如用户表的“性别”字段,只有男和女两种值,加了索引也快不起来,反而影响写入性能。而像“手机号”“邮箱”这种唯一性强的字段,加上索引后查询速度提升明显。
常见做法是在 WHERE 条件里频繁使用的字段上建索引。比如:
CREATE INDEX idx_user_email ON users(email);
用 JOIN 要小心
多表关联时,容易一不小心就查出几万行结果。比如订单表连用户表再连地址表,如果没限制条件,页面可能直接卡死。建议先在小范围数据上测试,确认返回行数可控。
另外,尽量让被驱动表(通常是右表)有索引。例如:
SELECT o.id, u.name
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.created_at > '2024-01-01';
这里确保 users.id 是主键或有索引,否则每次匹配都要全表扫描。
分页查询别跳过大量数据
做后台管理列表时,常有人这样写:
SELECT * FROM articles ORDER BY created_at DESC LIMIT 10 OFFSET 10000;
翻到第 1000 页时,数据库得先跳过一万条记录。越往后越慢。更好的方式是记住上一页最后一条的时间戳或 ID,用条件过滤:
SELECT * FROM articles
WHERE created_at < '2023-06-01 10:00:00'
ORDER BY created_at DESC LIMIT 10;
这样不管翻多少页,都是走索引查找,响应几乎不变。
减少嵌套子查询
嵌套太深的子查询不仅难读,还可能导致执行计划变差。比如统计每个分类下的商品数量,有人会这么写:
SELECT name,
(SELECT COUNT(*) FROM products p WHERE p.category_id = c.id)
FROM categories c;
每查一个分类就要跑一次子查询。换成 JOIN 和 GROUP BY 更高效:
SELECT c.name, COUNT(p.id) as product_count
FROM categories c
LEFT JOIN products p ON c.id = p.category_id
GROUP BY c.id, c.name;
利用 EXPLAIN 看执行计划
写完查询别急着上线,先用 EXPLAIN 看看数据库打算怎么执行。比如:
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
观察输出中的 type、key、rows 字段。如果看到 type=ALL,说明在全表扫描;rows 数很大,就得考虑加索引或优化条件。
批量操作用 IN 或临时表
要查多个ID对应的数据,别用循环发几十条 SQL。用 IN 一次性搞定:
SELECT * FROM users WHERE id IN (101, 105, 110, 120);
如果列表特别长,可以建个临时表存这些 ID,然后做 JOIN,效率更高。