SQL 大数据量查询优化方法

2次阅读

sql性能优化需避免索引失效、深分页、低效join和count瓶颈:where禁用函数/计算,order by+limit须匹配索引,join用小表驱动并确保类型一致,count(*)宜用覆盖索引或计数表,索引价值取决于字段值分布。

SQL 大数据量查询优化方法

WHERE 条件没走索引,查得慢还爆内存

不是所有 WHERE 都能用上索引。常见坑是写成 WHERE SUBSTRING(phone, 1, 3) = '138'WHERE status + 0 = 1 —— 这类表达式会让索引失效,引擎被迫全表扫描。

实操建议:

  • EXPLAINtype 是否为 ALL(全表扫描)或 index(索引全扫),理想是 refrange
  • 避免在索引列上做函数、计算、隐式类型转换;手机号查前缀就建 phone_prefix 字段并单独索引
  • 字符串比较注意 collation,utf8mb4_0900_as_csutf8mb4_general_ci 对大小写和性能影响不同

ORDER BY + LIMIT 在大数据集上卡死

比如 select * FROM orders ORDER BY created_at DESC LIMIT 10,表面看只取 10 行,但 mysql 可能先排序全部 5000 万行再截断。

实操建议:

  • 确保 ORDER BY 字段有索引,且和 LIMIT 组合使用时,索引顺序匹配(如 INDEX(created_at) 支持 ORDER BY created_at DESC
  • 分页深了别用 OFFSET,改用游标:记下上一页最后一条的 created_atid,下一页查 WHERE created_at
  • 如果业务允许,加 WHERE created_at > DATE_SUB(NOW(), INTERVAL 7 DAY) 先缩小范围,再排序

JOIN 多张大表,执行计划崩了

三张千万级表 JOIN,没控制好驱动表和连接条件,容易触发临时表 + 文件排序,磁盘 IO 拉满,查询超时。

实操建议:

  • EXPLAIN format=jsonjoin_buffer_size 是否被撑爆,以及哪张表是 驱动表table 列最先出现的那张)
  • 小表驱动大表:把过滤后只剩几百行的表放 FROM,大表放 JOIN 右侧;必要时用 STRAIGHT_JOIN 强制顺序
  • 连接字段类型必须严格一致(比如都是 BIGINT UNSIGNED),否则隐式转换让索引失效
  • 避免 SELECT *,只查真正需要的字段,减少网络传输和临时表体积

统计 COUNT(*) 卡住,或者结果不准

对亿级表跑 COUNT(*),InnoDB 要遍历主键索引,不是 O(1);而用缓存值或近似统计又可能漏数据。

实操建议:

  • 精确计数且频率低:加覆盖索引(如 INDEX(dummy) using BTREE,字段设为常量 TINYINT default 0),让引擎扫更小的二级索引
  • 高频统计需求:用单独的计数表,每次 INSERT/delete 后用事务同步更新,别依赖实时 COUNT
  • 接受误差:MySQL 8.0+ 可开 innodb_stats_persistent 并定期 ANALYZE TABLE,配合 SELECT table_rows FROM information_schema.tables 查估算值

真正难的不是加索引,而是判断「这列值的分布是否值得建索引」——比如性别字段只有两个值,加索引反而拖慢写入;而用户 ID 的唯一性高,哪怕没在 WHERE 出现,也可能被优化器选作连接路径。这类权衡没法靠规则穷举,得看 EXPLAIN 输出里的 rowsfiltered 实际值。

text=ZqhQzanResources