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

SQL 查询突然变慢,是不是数据库扛不住了?
不是所有“突发流量”都该由数据库硬扛。多数情况下,慢查询、锁等待、连接数打满才是表象,背后往往是没做读写分离、缺少缓存兜底,或单条 SQL 没走索引。先别急着扩容,查 SHOW PROCESSLIST 看有没有 Locked 或 Sending 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 和事务日志刷盘:
本书全面介绍PHP脚本语言和MySOL数据库这两种目前最流行的开源软件,主要包括PHP和MySQL基本概念、PHP扩展与应用库、日期和时间功能、PHP数据对象扩展、PHP的mysqli扩展、MySQL 5的存储例程、解发器和视图等。本书帮助读者学习PHP编程语言和MySQL数据库服务器的最佳实践,了解如何创建数据库驱动的动态Web应用程序。
- 批量写入优先用
INSERT INTO ... VALUES (...), (...), (...),而不是循环单条INSERT;每批控制在 500~1000 行,太大反而触发锁升级或内存溢出 - 临时关闭非关键业务的唯一索引检查(
SET unique_checks=0),导入完成后再开,但仅限离线导入场景 - 如果是日志类数据,考虑迁移到
ClickHouse或TimescaleDB,别硬塞进 MySQL - 主库压力持续高时,检查
innodb_log_file_size是否过小——日志太小会导致频繁刷盘,建议设为 1G~4G(需重启生效)
连接数被打满,Too many connections 怎么破?
这通常是连接泄漏或连接池配置失当:
- 应用端必须设置连接超时(
connect_timeout)、空闲超时(idle_timeout)、最大连接数(max_connections),不能依赖数据库默认值 - MySQL 侧调大
wait_timeout和interactive_timeout前,先确认是不是应用没正确 closeConnection或ResultSet - 短连接风暴(如 PHP-FPM 每次请求新建连接)比长连接更危险,优先切到连接池(如 HikariCP、Druid)
- 临时救急可用
KILL掉状态为Sleep且Time超过 60 秒的连接,但只是掩耳盗铃,得回溯代码里哪块没释放资源
真实压测中,80% 的“扛不住”其实发生在应用没关自动提交、ORM 生成了 N+1 查询、或者前端重试逻辑没加退避——数据库只是把上游的问题放大了而已。









