mysql原生不支持按用户限制cpu,防慢查询需组合max_execution_time(中断长select)和resource group(约束select调度),写操作只能靠cgroups等外部手段。

MySQL 原生不支持按用户限制 CPU 使用率,所谓“防慢查询打满 CPU”必须拆解为两个动作:中断慢 SELECT(用 MAX_EXECUTION_TIME),和约束其调度位置(用 RESOURCE GROUP,但仅限 SELECT)。写操作(INSERT/UPDATE/DELETE)完全不受控,只能靠外部手段。
为什么 MAX_QUERIES_PER_HOUR 对 CPU 完全无效
这个参数只计语句条数,不看执行时间。一个 SELECT SLEEP(30) 算 1 次,却能独占 CPU 30 秒;而 100 个毫秒级 SELECT 加起来可能才占 2% CPU,却已触发配额报错 ERROR 1226 (42000): User 'xxx' has exceeded the 'max_questions' resource。它适合防爬虫轮询,不是防 CPU 打满。
隐式查询(如外键检查、触发器、SELECT @@version)也会计数,实际撞限比预期快。ORM 框架(如 Laravel 的预编译、Django 的连接检测)会额外发查询,设太小容易误伤。必须用 CREATE USER 或 ALTER USER 设置,GRANT ... WITH 在 5.7+ 已废弃且行为不可靠。
真正能拦慢查询的只有 MAX_EXECUTION_TIME
MAX_EXECUTION_TIME 是唯一能中断长耗时 SELECT 的机制,单位毫秒,只对 SELECT 生效,对写操作无作用。
- 会话级设置:
SET SESSION max_execution_time = 3000,后续所有SELECT超过 3 秒自动被KILL QUERY - 语句级提示更精准:
SELECT /*+ MAX_EXECUTION_TIME(2000) */ * FROM orders WHERE ...,只影响当前语句 - 全局设置风险高:
SET GLOBAL max_execution_time = 1000会影响所有用户,包括 DBA 自己的诊断查询 - 该变量在 MySQL 5.7.8+ 才可用,且默认值为 0(不限制)
RESOURCE GROUP 只能约束 SELECT 的 CPU 调度
MySQL 8.0.19+ 的 RESOURCE GROUP 不是“限 CPU 百分比”,而是把线程绑定到指定逻辑核(VCPU)并调低调度优先级。它对写操作完全无效。
- 创建必须带
TYPE = USER和真实 VCPU(如VCPU = 2-3),漏掉任一字段就等于没生效 -
SET RESOURCE GROUP low_prio FOR 12345只影响下一条SELECT,正在执行的慢查询不会中断或降速 - 绑定前需确认线程状态不是
Sleep,否则报错ERROR 3661 (HY000) - Linux 下需给
mysqld进程加CAP_SYS_NICE权限:setcap cap_sys_nice+ep /usr/sbin/mysqld,否则THREAD_PRIORITY设了也白设
写操作打满 CPU 时,你只能靠外部手段
当 UPDATE、DELETE 或大事务导致 CPU 飙升时,MySQL 内部没有任何资源组或会话变量能干预其调度或中断执行。必须依赖:
- cgroups(Linux 内核级资源隔离)限制
mysqld进程整体 CPU 配额 - 代理层(如 ProxySQL、MaxScale)做请求拦截与超时控制
- 应用层 query timeout(如 JDBC 的
socketTimeout)配合max_rows会话限制兜底
最容易被忽略的是:资源组绑定后不中断当前语句,也不影响写操作;而 MAX_EXECUTION_TIME 对非 SELECT 语句完全静默——这两点一旦理解偏差,配置就形同虚设。











