如何写高效的数据库查询 实用操作步骤与避坑指南

避免 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';

观察输出中的 typekeyrows 字段。如果看到 type=ALL,说明在全表扫描;rows 数很大,就得考虑加索引或优化条件。

批量操作用 IN 或临时表

要查多个ID对应的数据,别用循环发几十条 SQL。用 IN 一次性搞定:

SELECT * FROM users WHERE id IN (101, 105, 110, 120);

如果列表特别长,可以建个临时表存这些 ID,然后做 JOIN,效率更高。