SET_VAR是MySQL 8.0.1引入的优化器提示,仅在单条DML语句执行期间临时覆盖指定会话级动态变量,作用域限于该语句本身,不修改@@session值,不支持全局、静态或用户变量。

不能用 SET_VAR 修改系统变量,它只支持会话级变量且仅限于部分可动态设置的变量;误以为能设全局或静态变量是常见错误源头。
什么是 SET_VAR?它根本不是 SET 语句的变体
SET_VAR 是 MySQL 8.0.1 引入的 **优化器提示(optimizer hint)**,语法形如 /*+ SET_VAR(sort_buffer_size = 4194304) */ SELECT ...。它只在单条 SQL 执行期间临时覆盖当前会话的某个变量值,作用域比 SET SESSION 更窄——仅限该语句本身。
- 不改变会话当前的
@@session.sort_buffer_size值,执行完即丢 - 不支持全局变量(
@@global.xxx)、静态变量(如innodb_log_file_size)或用户变量(@myvar) - 只能用于
SELECT、INSERT、UPDATE、DELETE、REPLACE、WITH等 DML 语句开头,不能单独执行
SET_VAR 能设哪些变量?查 performance_schema.variables_info 最准
不是所有会话级变量都支持 SET_VAR。必须同时满足:
VARIABLE_SCOPE = 'SESSION'IS_DYNAMIC = 'YES'-
VARIABLE_NAME在官方文档中明确标注支持 hint(例如sort_buffer_size、join_buffer_size、max_execution_time)
查法示例:
SELECT VARIABLE_NAME, VARIABLE_SCOPE, IS_DYNAMIC
FROM performance_schema.variables_info
WHERE VARIABLE_NAME IN ('sort_buffer_size', 'max_execution_time', 'read_buffer_size');
返回 YES 且 SESSION 才可放心用;若查不到或为 NO,硬写会直接报错:ERROR 3794 (HY000): Variable 'xxx' is not supported by SET_VAR hint。
为什么 SET_VAR 设了没生效?典型踩坑点
常见失效原因不是语法错,而是使用场景或权限卡住:
- 写在注释位置不对:必须是语句最开头的 /*+ ... */,
SELECT /*+ SET_VAR(...) */ ...✅,SELECT ... /*+ SET_VAR(...) */❌ - 变量名拼错或大小写敏感:MySQL 8.0 默认变量名小写,
/*+ SET_VAR(SORT_BUFFER_SIZE = 4M) */会静默失败 - 客户端自动重写 SQL:某些 ORM(如旧版 MyBatis)或代理(如 ProxySQL)可能过滤或转义 hint 注释
- 执行权限不足:虽然不需
SYSTEM_VARIABLES_ADMIN,但若用户被限制使用 optimizer hints(如restrictions插件启用),也会忽略
和 SET SESSION、SET GLOBAL 的关键区别在哪?
三者完全不在同一层级:
-
SET SESSION sort_buffer_size = 4194304:改当前会话后续所有语句的默认值,直到会话断开 -
SET GLOBAL sort_buffer_size = 4194304:改全局值,影响新连接,需SYSTEM_VARIABLES_ADMIN权限 -
/*+ SET_VAR(sort_buffer_size = 4194304) */ SELECT ...:只为此 SELECT 临时调大缓冲区,不影响任何其他语句,也不依赖权限
真正容易被忽略的是:如果一条 SQL 同时用了多个 hint,SET_VAR 的优先级高于会话变量,但低于 optimizer_switch 等更底层控制——这意味着你设了 SET_VAR,却因 optimizer_switch='index_merge=off' 导致实际未走预期索引,问题根源根本不在变量本身。


















