搞懂这三个命令的区别,核心是 变量作用域(全局 / 会话),你的部分理解需要修正 ——show VARIABLES 并非 “叠加”,而是默认显示「当前会话生效的变量」;session 和 global 变量也并非数量一致,而是有 “仅全局”“仅会话”“两者都有” 三类情况。下面分步骤讲清楚:
三者的本质差异是 查询的变量作用域不同,且 show VARIABLES 有默认行为,具体对比如下:
- 不是 “叠加”:
show VARIABLES 只显示「当前会话生效的变量」,而非同时显示 global 和 session。
其值的来源是:如果当前会话修改过某个变量,就显示修改后的 session 值;如果没修改过,就显示继承自 global 的默认值。
例:global 的 sql_mode 是 '',当前会话执行 SET SESSION sql_mode = 'STRICT_TRANS_TABLES' 后,show VARIABLES like 'sql_mode' 会显示修改后的 session 值,而非同时显示两个值。
假设场景:
- 全局变量
sql_mode 为 ''(宽松模式);
- 你当前会话执行
SET SESSION sql_mode = 'STRICT_TRANS_TABLES'(严格模式);
此时查询结果:
结论:同一变量,session 优先级 > global(当前会话优先用自己的配置,没有则继承 global)。
你的第二个问题:“session 变量允许有哪些?是不是和 global 一样多?”
答案:不一样多。MySQL 的变量分为三类,决定了两者的范围差异:
这类变量是数据库实例的 “基础配置”,无法在会话级别修改,只能全局设置。
- 例子:
datadir(数据存储目录)、port(监听端口)、max_connections(最大连接数)、innodb_buffer_pool_size(InnoDB 缓冲池大小)。
- 特点:
show SESSION VARIABLES 查不到这些变量,只能通过 show GLOBAL VARIABLES 查看。
这类变量和 “当前连接的操作状态” 相关,仅存在于会话中,不影响全局。
- 例子:
insert_id(手动指定的下一个自增 ID)、last_insert_id(当前会话最后插入的自增 ID)、sql_safe_updates(当前会话的安全更新模式)。
- 特点:
show GLOBAL VARIABLES 查不到这些变量,只能通过 show SESSION VARIABLES 查看。
这类变量有全局默认值,每个会话会继承初始值,但可以在会话中单独修改(不影响全局)。
- 例子:
sql_mode(SQL 模式)、wait_timeout(连接超时时间)、character_set_client(客户端字符集)、max_join_size(关联查询的最大行数限制)。
- 特点:
show GLOBAL 和 show SESSION 都能查到,但值可能不同(会话修改后)。
session 变量总数 ≠ global 变量总数,两者有重叠(第三类),但各有独有的变量(第一、二类)。
- 全局变量修改后,已存在的会话不生效,只有新连接会继承新的全局值;
- 有些变量即使是 “既全局又会话”,修改 session 级也可能无效(比如
innodb_buffer_pool_size,虽然能查 session 值,但修改后不生效,因为是共享资源,只能全局配置);
- 权限要求:修改 global 变量需要
SUPER 权限(或 MySQL 8.0+ 的 SYSTEM_VARIABLES_ADMIN 权限),修改 session 变量一般不需要特殊权限;
- 简写:
show LOCAL VARIABLES 等价于 show SESSION VARIABLES(LOCAL 是 SESSION 的别名)。
show GLOBAL VARIABLES:查实例级全局配置,影响所有新连接;
show SESSION VARIABLES:查当前连接的专属配置,仅影响当前连接;
show VARIABLES:默认查 SESSION 变量,即当前会话正在使用的配置(优先用自己的,没有则继承 global);
- session 和 global 变量数量不同,有 “仅全局”“仅会话”“两者都有” 三类,同名变量的会话值会覆盖全局值(仅当前连接)。
如何得知 当前session 有修改过哪些变量? 难道只能一个个的比对吗
不需要一个个手动比对!MySQL 提供了 系统表查询 + 变量来源追踪 的高效方法,能直接筛选出当前会话中被修改过的变量(即「会话值≠全局默认值」的变量)。以下是两种最实用的方案,适配不同 MySQL 版本:
会话变量的初始值默认继承自全局变量,只有「手动修改过」或「连接时自动适配」的变量,才会和全局值不一致。因此,找出「会话值≠全局值」且「变量同时存在于全局和会话」的记录,就是当前会话修改过的变量(排除会话独有变量)。
利用 information_schema 中的 GLOBAL_VARIABLES 和 SESSION_VARIABLES 两张系统表,直接关联比对同名变量的值,差异结果就是修改过的变量。
- 结果会列出所有「会话值≠全局值」的变量,这些变量要么是你手动
SET SESSION 修改的,要么是连接时 MySQL 自动适配的(比如字符集相关变量,若客户端和全局默认字符集不同)。
- 排除了「仅全局变量」(如
datadir)和「仅会话变量」(如 last_insert_id),只聚焦于「可修改且有全局默认值」的变量(正是你关心的 “可能被修改” 的变量)。
MySQL 8.0.11 及以上版本,新增了 performance_schema.variables_info 表,其中 VARIABLE_SOURCE 字段直接记录了「会话变量值的来源」,无需比对,直接筛选来源为 SESSION 的变量即可,更精准高效。
- 无需关联两张表,查询速度更快;
- 能精准区分「手动修改」(来源
SESSION)和「自动适配 / 继承」(来源 GLOBAL),避免误判(比如字符集变量可能因客户端配置自动变化,并非手动修改,方案一会列出,方案二可排除)。
-
变量类型比对问题:
部分变量的全局值和会话值类型可能不同(比如
max_connections 是数字,
sql_mode 是字符串),方案一中用
CAST(xxx AS CHAR) 统一转成字符串比对,避免因类型差异导致的 “假阳性”(比如
123 和
'123' 本应相等,却因类型不同被判为不同)。
-
会话独有变量的处理:
方案一用
INNER JOIN 只保留「既有全局又有会话」的变量,自动排除了
last_insert_id 这类「仅会话变量」(它们不存在全局值,自然不属于 “修改自全局” 的范畴),无需额外过滤。
-
权限要求:
两种方案都需要
SELECT 权限(对
information_schema 或
performance_schema),普通用户默认拥有(除非管理员特意限制),无需
SUPER 权限。
-
修改后不生效的变量:
有些变量(比如
innodb_buffer_pool_size)虽然能
SET SESSION 修改,但实际不生效(因为是全局共享资源),但这两个方案依然会列出它们(只要会话值≠全局值或来源为
SESSION),需注意这类变量的 “修改” 仅为表面值,未实际生效。
- 若使用 MySQL 8.0.11+,优先用 方案二(精准、高效,直接定位手动修改的变量);
- 若使用 MySQL 5.7 及以下,用 方案一(兼容所有版本,能找出所有与全局值不同的变量);
- 两种方案都无需手动比对,直接运行 SQL 即可得到结果,高效解决你的问题。
我是否可以理解为,当启动一个mysql 会话即session的时候, 会创建MySQL的一个session实例,然后 会自动从global实例中继承一些变量(是继承全部吗),然后按需对其中某些变量进行修改,(哪些是可以修改、哪些不能修改的呢?)如不修改, 那么直接去global的变量?
你的理解大体方向正确,但有几个关键细节需要修正和补充,核心结论先明确:
- 会话(session)启动时不会继承全部 global 变量,只继承「既全局又会话的变量」的初始值;
- 不修改会话变量时,用的是「启动时继承的全局初始值」(而非实时读取 global 变量);
- 变量能否修改,取决于它的「类型」和「MySQL 的设计规则」(不是所有变量都能改会话级)。
下面分步骤把逻辑讲透,贴合你的 MySQL 5.7.11 版本:
你说的 “session 实例启动时继承 global 变量”,本质是 会话变量的初始化过程,但继承范围有限,具体分 3 类(沿用之前的变量分类,保持一致):
- 不是 “继承全部 global 变量”:仅第 3 类变量会被会话 “复制初始值”,第 1 类仅全局变量会话根本没有,谈不到继承;
- 不是 “实时读取 global 变量”:会话启动后,第 3 类变量的初始值就和 global 变量 “脱钩” 了 —— 之后哪怕修改了 global 变量,已存在的会话也不会同步(新会话才会用新的 global 值当初始值)。
举个直观例子:
- 全局变量
wait_timeout = 86400(默认 24 小时);
- 你启动一个新会话(session A),会话的
wait_timeout 初始值 = 86400(复制当时的 global 值);
- 之后管理员修改全局变量
SET GLOBAL wait_timeout = 3600(1 小时);
- 会话 A 的
wait_timeout 依然是 86400(不受 global 修改影响),只有新启动的会话 B,才会以 3600 作为初始值。
变量能否修改,核心看「变量类型」和「MySQL 的设计限制」,按 “修改范围”(会话级 / 全局级)分类如下:
- 对应变量类型:第 1 类(仅全局变量);
- 特点:和数据库实例的 “基础配置 / 共享资源” 相关,必须全局统一,不能按会话自定义;
- 例子:
datadir(数据目录)、port(端口)、max_connections(最大连接数)、innodb_buffer_pool_size(InnoDB 缓冲池);
- 说明:
show SESSION VARIABLES 查不到这些变量,只能用 SET GLOBAL xxx 修改(需 SUPER 权限),且新会话才生效。
- 对应变量类型:第 2 类(仅会话变量)+ 部分第 3 类(既全局又会话,但全局级不允许改);
- 特点:和当前会话的 “操作状态” 相关,仅影响当前连接,不涉及全局资源;
- 例子:
- 仅会话变量:
last_insert_id(只能通过插入数据或 SET SESSION last_insert_id = xxx 修改)、sql_safe_updates(仅会话级生效,控制是否允许无 WHERE 的 UPDATE/DELETE);
- 第 3 类但仅能改会话级:
character_set_results(客户端字符集返回格式,全局改意义不大,通常改会话级);
- 说明:修改无需特殊权限,
SET SESSION xxx 即可,断开连接后失效。
- 对应变量类型:大部分第 3 类(既全局又会话的变量);
- 特点:有全局默认值,也支持会话自定义,满足 “全局统一 + 局部灵活” 的需求;
- 例子:
sql_mode(SQL 模式,全局宽松 + 会话严格)、wait_timeout(连接超时,全局 24 小时 + 会话 1 小时)、max_join_size(关联查询最大行数限制)、sort_buffer_size(排序缓冲区大小);
- 说明:
- 改全局:
SET GLOBAL xxx(需 SUPER 权限),新会话生效;
- 改会话:
SET SESSION xxx(普通权限),仅当前会话生效,不影响全局。
有些第 3 类变量(既全局又会话),虽然能执行 SET SESSION xxx,但修改后实际不生效 —— 因为它们是 “全局共享资源”,会话级修改被 MySQL 忽略;
- 例子:
innodb_buffer_pool_size(缓冲池大小)、key_buffer_size(MyISAM 索引缓冲区);
- 说明:这些变量的会话值只是 “显示用”,实际生效的还是全局值,改会话级没用。
你问 “如不修改,那么直接去 global 的变量?”—— 这个理解不准确,正确逻辑是:
- 对于第 3 类变量(既全局又会话):不修改的话,用的是「会话启动时复制的 global 初始值」(不是实时去读 global);
- 对于第 2 类变量(仅会话变量):不修改的话,用的是「MySQL 的会话默认值」(和 global 无关);
- 对于第 1 类变量(仅全局变量):会话中根本查不到,不存在 “取值” 一说。
再举个例子验证:
- 全局
sql_mode = ''(宽松模式);
- 启动会话 A,会话 A 的
sql_mode 初始值 = ''(复制当时的 global 值);
- 管理员修改全局
sql_mode = STRICT_TRANS_TABLES(严格模式);
- 会话 A 不修改自己的
sql_mode,此时查询 show VARIABLES like 'sql_mode',结果还是 ''(不是实时读新的 global 值);
- 新启动会话 B,其
sql_mode 初始值 = STRICT_TRANS_TABLES(复制新的 global 值)。
- 会话启动时,仅「既全局又会话的变量」会复制当前 global 值作为初始值,仅全局变量不继承,仅会话变量自动创建;
- 不修改会话变量时,用的是 “初始值”(第 3 类 = 复制的 global 初始值,第 2 类 = 会话默认值),和后续 global 变量的修改无关;
- 变量能否修改:
- 仅全局变量:只能改 global(需权限,新会话生效);
- 仅会话变量:只能改 session(无权限限制,当前会话生效);
- 既全局又会话的变量:大部分能改两者,少数改 session 不生效;
- 你的核心理解 “会话继承部分 global 变量,按需修改,不修改则用初始值” 是对的,只是要注意 “继承范围” 和 “初始值不实时同步 global” 这两个细节。
如果想快速判断某个变量能否改会话级,直接执行 SET SESSION 变量名 = 新值,若报错 Variable 'xxx' is a GLOBAL variable and should be set with SET GLOBAL,说明该变量只能改 global;若不报错,且查询 show VARIABLES like 'xxx' 是新值,说明改 session 级有效~
MySQL 中 STATUS 怎么理解,和 variables 是关系区别?
要理解 MySQL 中
STATUS 和
variables 的关系与区别,核心一句话就能拎清:
variables 是「配置项」(静态规则),
STATUS 是「运行状态 / 监控数据」(动态结果) —— 配置项决定 MySQL 如何运行,运行状态反映 MySQL 实际运行的效果,两者是 “因” 与 “果” 的关联,但本质完全不同。
variables 是你之前一直关注的 “配置”,核心是「提前设定好的规则」,告诉 MySQL 该用什么字符集、允许多少连接、超时多久断开等。
常见例子(既全局又会话的核心变量):
sql_mode:SQL 模式(规则),决定是否允许零日期、是否严格校验数据;
wait_timeout:连接超时时间(规则),决定客户端闲置多久断开;
character_set_client:客户端字符集(规则),决定 MySQL 如何解析客户端发送的字符;
max_connections:最大连接数(规则),决定 MySQL 最多能同时接受多少连接。
查询示例(你之前用过的):
STATUS 是 MySQL 运行过程中「自动统计的数据」,记录规则执行后的实际效果,比如 “按 max_connections 规则,当前有多少连接在使用”“按 query_cache_type 规则,缓存命中了多少次”。
常见例子(按场景分类):
查询示例(适配你的 5.7.11):
variables 和 STATUS 不是孤立的,而是 “因” 与 “果” 的关系 —— 你修改了配置(variables),最终会体现在状态(STATUS)上;通过状态(STATUS),也能反推配置(variables)是否合理。
举 2 个直观关联例子:
- 配置
max_connections(variables)= 100 → 状态 Threads_connected(STATUS)的最大值不会超过 100(如果超过,会出现 “连接数满” 错误);
- 配置
sql_mode(variables)= STRICT_TRANS_TABLES(严格模式)→ 状态 Com_insert(STATUS)中,因数据不符合规则导致的插入失败数会增加(可结合错误日志查看);
- 配置
wait_timeout(variables)= 3600 → 状态 Threads_connected(STATUS)中,闲置超过 1 小时的连接会被自动断开,连接数会减少。
-
作用域一致性≠含义一致:
两者都支持
GLOBAL 和
SESSION,但含义不同:
show SESSION VARIABLES like 'wait_timeout':当前连接的超时规则(比如 3600 秒);
show SESSION STATUS like 'Threads_connected':当前连接的活跃状态(固定为 1,因为是当前连接自己)。
-
STATUS 是 “累计值”,不是 “实时快照”:
比如
Queries 是从实例 / 连接启动后开始累计的,不是 “当前正在执行的查询数”(当前执行数看
Threads_running)。
-
部分 STATUS 变量名和 variables 类似,但完全不同:
比如
version(STATUS)是 MySQL 版本号(状态),
version_comment(variables)是版本注释(配置),名称接近但含义无关。
- 想「改规则、调配置」→ 用
variables(比如修改字符集、调整超时时间、开启严格模式);
- 想「看状态、查问题」→ 用
STATUS(比如排查连接数满、找慢查询、监控缓存效果);
- 核心逻辑:用 variables 定规则,用 STATUS 看规则的执行效果,两者配合才能完整掌控 MySQL 的运行。
比如你之前想知道 “会话修改了哪些变量”,用 variables 对比;现在想知道 “修改后连接数是否下降”,就用 STATUS 查 Threads_connected —— 这就是两者的实际配合场景。
如下的区别? show GLOBAL STATUS; show SESSION STATUS; show STATUS;
这三个命令的核心区别和 variables 系列完全一致 ——默认行为 + 统计数据的作用域(全局 / 会话),结合你熟悉的 MySQL 5.7.11 版本,用 “统计范围 + 实际用途” 就能讲透,还能直接对应到你的运维场景:
show STATUS 没有 “叠加”,默认只看「当前会话」的统计;
- 全局状态是 “全实例汇总”,会话状态是 “当前连接单独统计”,互不干扰;
- 数据都是 累计值(从实例 / 连接启动时开始算),不是实时 “快照”(比如
Queries 是累计执行的 SQL 总数,不是当前正在执行的数量)。
假设场景:你的 MySQL 实例已运行 1000 秒,当前有 3 个活跃连接,你当前连接刚执行了 5 条 SQL,其中 1 条是慢查询。
show GLOBAL STATUS like 'Uptime';
show SESSION STATUS like 'Uptime';
show STATUS like 'Queries';
- 全局状态是 “集体数据”,反映整个数据库的负载;
- 会话状态是 “个人数据”,只反映你当前连接的操作;
show STATUS 就是偷懒写法,默认看 “个人数据”。
-
部分状态变量只有 “全局版”,没有会话版:
比如
Uptime(实例运行时长)、
Com_show_databases(全实例累计执行
show databases 的次数),执行
show SESSION STATUS like 'Uptime' 也能查到,但值是「当前连接的存活时长」(不是实例时长),用途不同。
-
会话状态的生命周期:
会话状态数据从连接建立时开始累计,断开连接后数据会重置(下次重连重新从 0 开始算);而全局状态数据从实例启动时开始累计,重启实例才会重置。
-
别把 “累计值” 当 “实时值”:
- 想查 “当前正在执行的 SQL 数”→ 用
show GLOBAL STATUS like 'Threads_running'(全局),不是 Queries(累计总数);
- 想查 “当前活跃连接数”→ 用
show GLOBAL STATUS like 'Threads_connected'(全局),不是 Threads_running(正在执行的连接数)。
-
权限要求:
普通用户默认能查
SESSION STATUS;查
GLOBAL STATUS 可能需要
PROCESS 权限(如果报错 “Access denied”,让管理员授予
GRANT PROCESS ON *.* TO '你的用户名'@'localhost';)。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/973553.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!