mysql中@var是用户变量,独立于系统变量;@@var默认查会话级,未设置则回退全局级,但不实时同步。

MySQL里@var和@@var到底查的是哪层变量
MySQL的变量分三类:用户变量(@var)、系统变量(@@var)、局部变量(存储过程内DECLARE)。但执行时真正生效的,取决于作用域和查找顺序。比如SELECT @@sql_mode不总返回你SET过的值——它可能来自会话级、全局级,甚至启动配置。
系统变量查找逻辑是:先查会话级缓存值,若未显式设置过,则回退到全局值;全局值又优先取自配置文件或启动参数。这个“回退”不是实时同步的,SET GLOBAL之后,已连接的客户端不会自动更新自己的会话值。
-
@@session.var和@@var等价,只影响当前连接 -
@@global.var修改后,新连接才生效,老连接仍用旧会话值 - 用户变量
@var完全独立,不参与系统变量查找链,也无作用域继承 - 某些变量(如
@@autocommit)是只读会话变量,SET GLOBAL会报错ERROR 1238 (HY000): Variable 'autocommit' is a READ ONLY variable
为什么SET @@sort_buffer_size = 4194304没生效
常见现象:执行了SET @@sort_buffer_size = 4194304,再EXPLAIN看排序操作,发现还是用默认值。根本原因是该变量属于“动态只读会话变量”——它允许SET SESSION,但实际生效需满足前提:必须在查询发起前设置,且不能被后续查询中的隐式重置覆盖(例如执行ANALYZE TABLE可能触发内部重置)。
- 该变量单位是字节,但MySQL内部会按页对齐,设为
4194304(4MB)可能被自动调整为4194304 + 页头开销 - 仅对当前连接后续的排序操作生效,已开始的查询不受影响
- 如果连接池复用连接,上一个请求设的值可能污染下一个请求,建议显式重置或使用连接初始化SQL
- 查看真实生效值,别只信
SELECT @@sort_buffer_size,用SHOW VARIABLES LIKE 'sort_buffer_size'更可靠(它强制读会话缓存)
SELECT @a := 1, @@tx_isolation这种混合写法的风险
在一条语句里混用用户变量赋值和系统变量读取,表面能跑,但行为不可靠。MySQL 5.7+对这类表达式的求值顺序不保证,尤其当涉及子查询或JOIN时,@a := 1可能在@@tx_isolation读取前、中、后任意时机执行。
- 不要依赖
SELECT @a := @@sql_mode, @b := @a来“备份”系统变量——@a可能拿到旧值或NULL - 跨语句传递应改用
SET @backup = @@sql_mode+ 单独SELECT @backup - 存储过程中用
DECLARE v_sql_mode VARCHAR(100) DEFAULT @@sql_mode更安全,避免运行时歧义 - MySQL 8.0起,
@@transaction_isolation替代@@tx_isolation,但混用依然有同样问题
配置文件里的max_connections = 200和运行时SET GLOBAL max_connections = 300谁赢
运行时SET GLOBAL赢,但仅限内存生效。MySQL启动时把配置文件值载入全局变量,之后SET GLOBAL直接修改内存中的全局值。不过这个修改不持久——服务重启后,又回到配置文件的值。
- 想永久生效,必须同步改
my.cnf(或mysqld.cnf)并重启,或用mysqld --initialize-insecure重新生成配置(不推荐) -
SET GLOBAL失败常见原因:权限不足(需SUPER或SYSTEM_VARIABLES_ADMIN)、超出max_connections硬上限(由open_files_limit等OS限制反向约束) - 检查是否真改成功,别只看
SELECT @@global.max_connections,用SHOW GLOBAL VARIABLES LIKE 'max_connections'确认 - 注意:某些变量(如
innodb_buffer_pool_size)动态调整有最小粒度(通常1MB),设SET GLOBAL innodb_buffer_pool_size = 1073741823会被自动向上取整到1073741824
变量查找看着是路径问题,其实是状态快照问题——MySQL不做实时反射,每个连接维护自己的一套变量视图,而系统变量本身又分全局/会话两层缓存。最易忽略的,是以为SET完立刻全局可见,或者把用户变量当系统变量使。










