SQL 格式化 / 优化分析器 / 结构可视化
SELECT
*
FROM
users u
WHERE
DATE(u.created_at) = '2025-01-01'
AND u.name LIKE '%john%'
AND u.id IN (
SELECT
user_id
FROM
orders
WHERE
total > 100
)
ORDER BY
RAND ()
LIMIT
10000, 20;优化分析
高`LIKE '%xxx'` 前导通配符使索引失效
LIKE 模式以 `%` 开头时,B+Tree 索引无法定位起始扫描位置,会退化为全表扫描。表越大越慢。
建议: 业务允许的话改用 `LIKE 'xxx%'`(前缀匹配);如必须做模糊全文搜索,考虑全文索引、Elasticsearch 或反向索引方案。
- L4:
LIKE '%john%' AND u.id IN (SELECT user
高`ORDER BY RAND()` 严重性能问题
RAND() 会对每一行生成一个随机数再排序,等于全表扫描 + 全表排序。10 万行的表执行可能需要数秒。
建议: 改用先取一个随机偏移再 LIMIT,例如 `WHERE id >= (SELECT FLOOR(RAND()*MAX_ID)) LIMIT 1`,或在应用层取 ID 范围内的随机值。
- L6:
ORDER BY RAND() LIMIT 10000, 20;
高WHERE 子句中字段被函数包裹
`WHERE DATE(created_at) = ...` 这样的写法会让索引失效,数据库无法利用 created_at 上的索引。
建议: 改成范围查询:`WHERE created_at >= '2025-01-01' AND created_at < '2025-01-02'`;如必须用函数,考虑生成列 + 函数索引。
- L3:
WHERE DATE(u.created_at) = '2025-01-01' AND u.name LIKE '%
高大 `OFFSET` 分页(深分页问题)
`LIMIT 10000, 20` 数据库需要先扫描跳过前 10000 行,越深越慢。第 10 万页可能需要数秒。
建议: 改用「游标分页」:记下上一页最后一行的 ID,下一页用 `WHERE id > <last_id> LIMIT 20`,性能与页数无关。
- L7:
LIMIT 10000, 20
中使用 `SELECT *`
查询所有列会增加网络传输量与解析开销,且无法走「覆盖索引」(covering index);表结构变化时还可能影响调用方。
建议: 只列出真正需要的列,例如 `SELECT id, name, email FROM users`。
- L1:
SELECT * FROM users u WHERE DATE(u.created_at) = '2025-01-01
中`IN (SELECT ...)` 子查询
部分数据库会把 IN 子查询执行为半连接,但有些版本会退化为对每行做一次子查询。
建议: 改写为 JOIN:`SELECT a.* FROM a JOIN b ON a.id = b.a_id`,让优化器更容易选择最优执行计划。
- L5:
IN (SELECT user_id FROM orders WHERE total > 100) ORDER BY R