SQL 基础与查询优化入门教程

1次阅读

sql查询慢的主因是where条件写法不当、join导致结果集膨胀及select *滥用;如where中对字段用函数使索引失效,应改用范围查询;join需防一对多膨胀,可用count对比或窗口函数替代;分页宜用游标而非offset。

SQL 基础与查询优化入门教程

SQL 查询慢,不是因为没学过索引,而是因为没想清楚 WHERE 条件怎么写、JOIN 会不会放大结果集、SELECT * 会拖垮什么。

WHERE 子句里用函数导致索引失效

比如 WHERE YEAR(created_at) = 2023 看起来直观,但数据库没法用 created_at 上的索引——因为函数改变了字段原始值,优化器只能全表扫描。

  • 改成范围查询:WHERE created_at >= '2023-01-01' AND created_at
  • 如果必须按月查,优先建函数索引(postgresql 支持 CREATE INDEX ON t ((EXTRACT(YEAR FROM created_at)))mysql 8.0+ 支持函数索引,但需显式定义)
  • 避免在 WHERE 里对字段做运算:WHERE price * 1.1 > 100 同样走不了索引,应改为 WHERE price > 100 / 1.1

JOIN 多张表时结果集意外膨胀

三张表 LEFT JOIN,本意是补全信息,结果行数翻了十几倍——大概率是某张表存在一对多关系,且没加聚合或去重逻辑。

  • 先用 COUNT(*)COUNT(DISTINCT t1.id) 对比,确认是否重复膨胀
  • 检查 JOIN 条件是否遗漏关键字段(比如只连了 user_id,但没限定 tenant_id,跨租户数据混了)
  • 如果只是要关联最新一条记录,别用 JOIN,改用窗口函数:ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY updated_at DESC) 再过滤

ORDER BY + LIMIT 在大数据量下仍很慢

常见于分页场景:SELECT * FROM orders ORDER BY created_at DESC LIMIT 20 OFFSET 10000。OFFSET 越大,数据库越要先扫出前 10020 行再丢弃。

  • 用游标分页替代 OFFSET:WHERE created_at
  • 确保 ORDER BY 字段有索引,且和 WHERE 条件能复用同一索引(例如 WHERE status = 'paid' ORDER BY created_at,适合建联合索引 (status, created_at)
  • 如果排序字段有大量重复值(如 status 只有 3 个取值),务必在 ORDER BY 末尾加上主键,避免排序不稳定:ORDER BY status, id

最常被忽略的点:执行计划不是看一眼 EXPLAIN 就完事,得盯住 rows 估算值是否接近真实扫描行数、type 是不是 rangeref、有没有出现 using filesortUsing temporary——这些才是真正卡顿的信号。

text=ZqhQzanResources