SQL 如何应对突发流量?

9次阅读

sql查询变慢通常不是数据库容量问题,而是慢查询、锁等待、连接数满等表象,根源在于未做读写分离、缺少缓存、索引缺失;应先查进程列表与执行计划,再分层优化读写与连接管理。

SQL 如何应对突发流量?

SQL 查询突然变慢,是不是数据库扛不住了?

不是所有“突发流量”都该由数据库硬扛。多数情况下,慢查询、锁等待、连接数打满才是表象,背后往往是没做读写分离、缺少缓存兜底,或单条 SQL 没走索引。先别急着扩容,查 SHOW PROCEsslIST 看有没有 LockedSending data 卡住的长事务;用 EXPLaiN 确认关键查询是否走了索引——尤其是 WHERE、JOIN、ORDER BY 字段上有没有复合索引覆盖。

如何让 select 不拖垮整个库?

读请求是突发流量中最容易放大的部分,必须隔离:

  • 把报表、后台管理等低优先级查询路由到从库,主库只接核心写入和强一致性读
  • 对高频、变化不频繁的查询加应用层缓存,比如用户资料页用 redis 缓存 5 分钟,避免每秒几百次打到 SELECT * FROM users WHERE id = ?
  • LIMIT 强制分页,禁用 OFFSET 大翻页,改用游标式分页(如 WHERE created_at )
  • 避免在大表上执行 SELECT count(*),改用近似值(mysql 8.0+ 可查 information_schema.INNODB_TABLESTATS)或业务侧维护计数器

INSERT/UPDATE 突增时,怎么防止主库写爆?

写入瓶颈往往卡在磁盘 I/O 和事务日志刷盘:

  • 批量写入优先用 INSERT INTO ... VALUES (...), (...), (...),而不是循环单条 INSERT;每批控制在 500~1000 行,太大反而触发锁升级或内存溢出
  • 临时关闭非关键业务的唯一索引检查(SET unique_checks=0),导入完成后再开,但仅限离线导入场景
  • 如果是日志类数据,考虑迁移到 clickhouseTimescaleDB,别硬塞进 MySQL
  • 主库压力持续高时,检查 innodb_log_file_size 是否过小——日志太小会导致频繁刷盘,建议设为 1G~4G(需重启生效)

连接数被打满,Too many connections 怎么破?

这通常是连接泄漏或连接池配置失当:

  • 应用端必须设置连接超时(connect_timeout)、空闲超时(idle_timeout)、最大连接数(max_connections),不能依赖数据库默认值
  • MySQL 侧调大 wait_timeoutinteractive_timeout 前,先确认是不是应用没正确 close ConnectionResultSet
  • 短连接风暴(如 php-FPM 每次请求新建连接)比长连接更危险,优先切到连接池(如 HikariCP、Druid)
  • 临时救急可用 KILL 掉状态为 SleepTime 超过 60 秒的连接,但只是掩耳盗铃,得回溯代码里哪块没释放资源

真实压测中,80% 的“扛不住”其实发生在应用没关自动提交、ORM 生成了 N+1 查询、或者前端重试逻辑没加退避——数据库只是把上游的问题放大了而已。

text=ZqhQzanResources