
SET 语句改的是会话变量还是全局变量?
默认只改当前连接的会话变量,不影响其他连接,也不影响新连接。想改全局变量,必须显式加 GLOBAL 或 @@global. 前缀,否则即使你有 SUPER 权限,SET var = val 也只会作用于当前会话。
-
SET sort_buffer_size = 4194304→ 只改当前会话的sort_buffer_size -
SET GLOBAL sort_buffer_size = 4194304→ 改全局值,但新连接是否生效还取决于配置文件是否持久化 -
SET @@global.sort_buffer_size = 4194304→ 效果同上,语法更显式
哪些变量能用 SET 修改?哪些不能?
不是所有系统变量都支持运行时修改。有些是只读的(比如 version),有些仅在启动时读取(比如 innodb_data_home_dir),强行 SET 会报错:ERROR 1238 (HY000): Variable 'xxx' is a read only variable。
- 查变量是否可动态修改:
SELECT VARIABLE_NAME, VARIABLE_SCOPE, SET_TIME FROM performance_schema.variables_info WHERE VARIABLE_NAME = 'xxx';,关注VARIABLE_SCOPE列是否含GLOBAL或SESSION - 常见可动态设的:
sql_mode、autocommit、max_allowed_packet、wait_timeout - 常见不可设的:
datadir、port、server_id(需重启)
SET @var := value 和 SET @var = value 有什么区别?
两者都用于用户变量赋值,行为一致,:= 是更明确的赋值操作符,避免和 = 在 WHERE 子句中被误解析为比较。但在 SET 语句里,MySQL 允许混用,无实质差异。
-
SET @counter = 1;✅ -
SET @counter := 1;✅(推荐,尤其在复杂表达式中) -
SET @counter = @counter + 1;✅ -
SET @counter := @counter + 1;✅ 更安全,不易被误解为条件判断 - 注意:
@开头的是用户变量,和系统变量(如@@sort_buffer_size)完全无关,不共享作用域,也不能用GLOBAL修饰
SET 修改后为什么没生效?常见掉坑点
最常踩的不是语法错,而是作用域和生命周期理解偏差。比如改了全局变量却忘了新连接要重连才继承新值,或误以为改了会话变量就能影响其他线程。
- 改了
GLOBAL变量,但已有连接仍用旧值 —— 对,这是设计如此,会话变量初始化自全局值,之后独立 - 改了
wait_timeout全局值,但应用连接池没断开重连 → 实际超时时间不变 - 在存储过程中用
SET @x = ...,但调用方没 SELECT 查询该变量 → 用户变量不会自动返回,得显式SELECT @x - 用
SET NAMES utf8mb4时写成utf8→ MySQL 的utf8实际是阉割版,不支持 emoji,必须用utf8mb4
变量修改是即时生效的,但“生效”本身依赖上下文。别指望 SET 一条命令就能一劳永逸,得看它改的是谁、谁在用、什么时候用。











