SQL 大数据量查询优化方案

2次阅读

查询慢主因是where条件未走索引,如like左模糊、字段函数运算;应使用explain分析执行计划,建联合索引、避免运算、显式指定字段、慎用count(*),优先定位真凶再优化。

SQL 大数据量查询优化方案

WHERE 条件没走索引,查得慢到怀疑人生

绝大多数大数据量查询慢,不是数据量大本身的问题,而是 WHERE 条件字段没命中索引。比如对 status 字段做 LIKE '%pending',或在条件里对字段用了函数:WHERE date(created_at) = '2024-01-01' —— 这两种写法都会让索引失效。

实操建议:

  • EXPLAIN 看执行计划,重点盯 type(最好是 refrange)、key(是否用了索引)、rows(预估扫描行数)
  • status 类低基数字段单独建索引意义不大,但和高频过滤字段组合成联合索引就有效,比如 (tenant_id, status, created_at)
  • 避免在索引字段上做运算或类型转换,把 WHERE DATE(created_at) = ... 改成 WHERE created_at >= '2024-01-01' AND created_at

OFFSET 越大越卡,分页查不动了

LIMIT 10000, 20 查第 501 页?数据库得先扫出前 10020 行再丢掉前面的,IO 和 CPU 成倍涨。这不是 sql 写得不好,是 OFFSET 语义本身不适合深分页。

实操建议:

  • 改用游标分页:记住上一页最后一条的 idcreated_at,下一页查 WHERE id > 12345 ORDER BY id LIMIT 20
  • 如果必须用页码,且数据相对静态,可提前物化分页映射(比如用 redis 缓存 page:500 → offset:99980),但要注意数据变更时的失效策略
  • 别在 ORDER BY 字段上用函数,比如 ORDER BY UPPER(name),会强制全表排序,无法利用索引排序能力

select * 拉太多字段,网络和内存都吃不消

查 100 万行,每行多选 3 个 TEXT 字段,结果集可能从 200MB 涨到 2GB。不仅慢,还容易触发 mysqlmax_allowed_packet 错误,或者压垮应用层内存。

实操建议:

  • 永远显式列出需要的字段,删掉所有 *,尤其是别带 jsontextblob 类大字段,除非真要用
  • 大字段单独建宽表或异步加载:主表只存 ID 和摘要,详情走另一条轻量查询
  • 注意 ORM 的懒加载陷阱,比如 djangoselect_related 没配好,一次查出几十张表的全部字段

统计 COUNT(*) 卡住,又不能加缓存

对上亿行表执行 COUNT(*),InnoDB 得扫聚簇索引,哪怕有索引也绕不开。有些场景(比如后台实时看板)确实要准数,但硬查就是扛不住。

实操建议:

  • 确认是否真的需要精确值:用户侧显示“约 1200 万条”比“12003456 条”更合理,可用采样估算,比如 SELECT (COUNT(*) * 10) FROM t TABLESAMPLE BERNOULLI (10)postgresql
  • MySQL 8.0+ 可考虑用 INFORMATION_SCHEMA.INNODB_TABLESTATS 中的 n_rows 近似值,误差通常在 ±10%,但不保证实时
  • 如果业务允许延迟,用定时任务把统计结果写进汇总表,查询走 SELECT total_count FROM stats_summary WHERE table_name = 'orders'

最麻烦的往往不是怎么优化,而是搞不清哪条查询真正拖慢了整体——先用慢日志 + EXPLAIN 定位,别一上来就加索引或分库分表。索引建多了反而让写入变慢,而且优化器也可能选错执行路径。

text=ZqhQzanResources