新特性解读 | MySQL 8.0 字段信息统计机制

本文以案例详细介绍 MySQL 8.0 字段信息统计机制。阐述表信息更新基本逻辑,即默认从系统表检索缓存值,缓存过期则从存储引擎获取。介绍核心参数,其决定统计信息收集间隔。通过测试展示设置实时更新效果,最后提及 SQLE 这款 SQL 审核工具。

作者通过一个案例详细说明了 MySQL 8.0 字段信息统计机制的相关参数和使用方式。

作者:杨奇龙

网名“北在南方”,资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优、故障诊断。

本文来源:原创投稿

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

背景

前几天有同事在咨询一个问题:某个业务基于 INFORMATION_SCHEMA 统计表的信息(比如最大值)向表里面插入数据。

请问 INFORMATION_SCHEMA.TABLES 中的 AUTO_INCREMENT 会不会及时的更新呢?

先说结论:可以!

这里涉及到 信息统计机制 或者说频率问题,主要由参数information_schema_stats_expiry 控制。

表信息更新的基本逻辑

默认情况下,MySQL 会高效的从 系统表 mysql.index_statsmysql.table_stats 中检索这些列的缓存值,而不是直接从存储引擎中获取统计信息。如果缓存的统计信息不可用或已过期,MySQL 将从存储引擎中检索最新的统计信息,并将其统计信息更新并缓存在 mysql.index_statsmysql.table_stats 字典表中。后续查询将检索缓存的统计信息,直到缓存的统计数据过期。

值得注意的是:MySQL 重新启动或第一次打开 mysql.index_statsmysql.table_stats 表不会自动更新缓存的统计信息。

核心参数

核心参数 information_schema_stats_expiry 默认是 86400 秒。也就是说每隔一天自动收集一次相关统计信息到 information_schema 中的如下表字段中:

STATISTICS.CARDINALITY
TABLES.AUTO_INCREMENT
TABLES.AVG_ROW_LENGTH
TABLES.CHECKSUM
TABLES.CHECK_TIME
TABLES.CREATE_TIME
TABLES.DATA_FREE
TABLES.DATA_LENGTH
TABLES.INDEX_LENGTH
TABLES.MAX_DATA_LENGTH
TABLES.TABLE_ROWS
TABLES.UPDATE_TIME

参数 information_schema_stats_expiry 的值决定再次收集表的统计信息的时间间隔,默认 86400 秒。如果设置为 0 ,则表示实时更新统计信息,当然势必会影响一部分性能。

在以下情况中,查询统计信息列不会在 mysql.index_statsmysql.table_stats 字典表中存储或更新统计信息:

  1. 缓存的统计信息尚未过期时。
  2. information_schema_stas_expiry 设置为 0 时。
  3. 当 MySQL server 处于只读、超级只读、事务只读或 innodb_read_only 模式时。
  4. 查询还获取 Performance Schema 的数据时。

information_schema_stas_experity 支持全局和会话级别,每个会话都可以定义自己的过期值。从存储引擎中检索并由一个会话缓存的统计信息可用于其他会话。

测试

本文以 MySQL 8.0.30 为例,进行分析。

2.1 测试准备

  CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB ;

2.2 测试

查看 information_schema.tablessbtest1 的当前信息,最大值 1200006,表结构定义中自增最大值也是 1200006。

master [localhost:22031] {msandbox} (test) > show variables like 'information_schema_stats_expiry' ;
+-----------------------------------------+---------+
| Variable_name                   | Value |
+-----------------------------------------+---------+
| information_schema_stats_expiry | 86400 |
+-----------------------------------------+---------+
1 row in set (0.02 sec)

master [localhost:22031] {msandbox} (test) > select  table_name, AUTO_INCREMENT  from information_schema.tables where  table_name='sbtest1';
+---------------+--------------------+
| TABLE_NAME | AUTO_INCREMENT |
+---------------+--------------------+
| sbtest1    |        1200006 |
+---------------+--------------------+
1 row in set (0.01 sec)

master [localhost:22031] {msandbox} (test) > show create table  sbtest1 \G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1200006 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

插入新的数据,自增值加 1。

master [localhost:22031] {msandbox} (test) > insert into sbtest1(k,c,pad) values(1,'c','cc');
Query OK, 1 row affected (0.00 sec)

master [localhost:22031] {msandbox} (test) > show create table  sbtest1 \G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1200007 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

但是 information_schema.tables 中的值并未发生变化。

master [localhost:22031] {msandbox} (test) > select  table_name, AUTO_INCREMENT  from information_schema.tables where  table_name='sbtest1';
+------------+----------------+
| TABLE_NAME | AUTO_INCREMENT |
+------------+----------------+
| sbtest1    |        1200006 |
+------------+----------------+
1 row in set (0.00 sec)

设置为实时更新

修改information_schema_stats_expiry 为 0。

master [localhost:22031] {msandbox} (test) > set  information_schema_stats_expiry=0;
Query OK, 0 rows affected (0.00 sec)

master [localhost:22031] {msandbox} (test) > show variables like 'information_schema_stats_expiry' ;
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| information_schema_stats_expiry | 0     |
+---------------------------------+-------+
1 row in set (0.00 sec)

master [localhost:22031] {msandbox} (test) > select  table_name, AUTO_INCREMENT  from information_schema.tables where  table_name='sbtest1';
+------------+----------------+
| TABLE_NAME | AUTO_INCREMENT |
+------------+----------------+
| sbtest1    |        1200007 |
+------------+----------------+
1 row in set (0.00 sec)

master [localhost:22031] {msandbox} (test) > show create table  sbtest1 \G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1200007 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

插入数据自增加 1 ,查询 information_schema.tables 中的 自增列统计值 也是实时更新。

master [localhost:22031] {msandbox} (test) > insert into sbtest1(k,c,pad) values(1,'c','cc');
Query OK, 1 row affected (0.00 sec)

master [localhost:22031] {msandbox} (test) > select  table_name, AUTO_INCREMENT  from information_schema.tables where  table_name='sbtest1';
+------------+----------------+
| TABLE_NAME | AUTO_INCREMENT |
+------------+----------------+
| sbtest1    |        1200008 |
+------------+----------------+
1 row in set (0.00 sec)

master [localhost:22031] {msandbox} (test) > show create table  sbtest1 \G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `k` int NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1200008 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

手工修改自增列,也是可以实时更新。

master [localhost:22031] {msandbox} (test) > alter table sbtest1  AUTO_INCREMENT=1200010;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

master [localhost:22031] {msandbox} (test) > select  table_name, AUTO_INCREMENT  from information_schema.tables where  table_name='sbtest1';
+------------+----------------+
| TABLE_NAME | AUTO_INCREMENT |
+------------+----------------+
| sbtest1    |        1200010 |
+------------+----------------+
1 row in set (0.00 sec)

小结

MySQL 8.0 对于表字段的统计信息提供更多的技术特性来支持。统计有效性时长,字段本身的直方图,使用起来越来越便利。

回过头来看这个需求,其实如果是业务监控或者数据库监控信息比如监控表的主键最大值是否溢出,比较实际的建议还是查询具体的表的最大 id 值,比较实际,查询频率看可控。

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
<think>好的,用户想了解MySQL 8.0中查看死锁信息的SQL语句,特别是关于innodb_locks和deadlocks的。首先,我需要回忆一下MySQL 8.0的变化。记得在8.0版本之后,一些系统表被替换了,比如原来的INNODB_LOCKS和INNODB_LOCK_WAITS被移除了,改用了performance_schema中的data_locks和data_lock_waits。用户提到的innodb_locks可能是指旧版本的表,现在需要更新到新的表结构。 接下来,用户可能需要具体的查询语句。根据引用5,应该使用SELECT * FROM performance_schema.data_locks;和SELECT * FROM performance_schema.data_lock_waits;这两个语句来获取当前的锁信息和锁等待情况。同时,错误日志也是一个重要的信息来源,需要开启innodb_print_all_deadlocks来记录所有死锁事件,而不仅仅是最近的,这样可以帮助用户更全面地分析问题。 另外,用户可能还想知道如何查看事务的加锁情况,引用3提到可以使用INNODB_TRX表来查看当前运行的事务信息。虽然这个表本身不直接显示锁,但结合data_locks可以更详细地了解每个事务持有的锁。还有SHOW ENGINE INNODB STATUS命令,这个命令能提供最近的死锁信息,但需要及时查看,因为只保留最后一次的死锁详情。 需要注意的是,用户可能需要调整配置,比如启用innodb_print_all_deadlocks,并且在调试完成后记得关闭,避免日志过大。同时,引用4提到设置innodb_status_output_locks=1可以在SHOW ENGINE INNODB STATUS中显示更多锁的详细信息,这对诊断死锁有帮助。 用户的问题可能还涉及到如何分析这些锁信息,需要解释各个字段的含义,比如LOCK_TYPE、LOCK_MODE等,帮助他们理解输出结果。此外,要提醒用户处理完死锁后,及时关闭调试选项,避免影响性能。 总结一下,用户需要的是具体的SQL语句、配置方法以及如何解读结果。需要确保回答准确,并且考虑到用户可能对旧版本和新版本的区别不太清楚,需要明确说明MySQL 8.0的变化,避免混淆。</think>### MySQL 8.0查看死锁信息的SQL语句及方法 #### 1. 通过`performance_schema`系统表查询 MySQL 8.0移除了早期版本的`INNODB_LOCKS`和`INNODB_LOCK_WAITS`表,改用以下两个视图: ```sql -- 查看当前持有的锁信息 SELECT * FROM performance_schema.data_locks; -- 查看锁等待关系 SELECT * FROM performance_schema.data_lock_waits; ``` 这两个表提供了事务ID、锁类型、锁模式、锁定索引等详细信息[^5]。 #### 2. 通过错误日志记录死锁 启用`innodb_print_all_deadlocks`配置选项后,所有死锁事件会记录到MySQL错误日志: ```sql -- 临时启用全局死锁日志记录 SET GLOBAL innodb_print_all_deadlocks = 1; -- 查看错误日志路径 SHOW VARIABLES LIKE 'log_error'; ``` 调试完成后需手动关闭此选项以避免日志膨胀[^1]。 #### 3. 使用`SHOW ENGINE INNODB STATUS` 该命令会输出最后一次死锁的详细分析: ```sql SHOW ENGINE INNODB STATUS\G ``` 在输出结果的`LATEST DETECTED DEADLOCK`段中可查看事务操作语句、等待资源、回滚状态等信息[^4]。 #### 4. 结合事务信息分析 通过`information_schema.innodb_trx`查看活跃事务: ```sql SELECT * FROM information_schema.innodb_trx; ``` 该表包含事务ID、状态、锁等待时间等字段,可与`data_locks`关联分析[^3]。 --- ### 字段说明示例(data_locks表) | 字段 | 说明 | |----------------|-----------------------------| | ENGINE_LOCK_ID | 锁的唯一标识符 | | LOCK_TYPE | 锁类型(TABLE/RECORD) | | LOCK_MODE | 锁模式(X/S等) | | INDEX_NAME | 被锁定的索引名称 | | LOCK_DATA | 锁定记录的主键或唯一键值 | --- ### 注意事项 1. **锁检测限制**:若涉及非InnoDB引擎的表锁,需通过`innodb_lock_wait_timeout`处理[^2] 2. **调试开关**:`innodb_status_output_locks=1`可增强锁信息输出[^4] 3. **实时性要求**:`SHOW ENGINE`仅保留最后一次死锁信息,需及时捕获 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值