1、需求背景

获取MySQL中某张表的最后更新时间。

2、相关答案及存在的问题

在网上查找了很多资料,中英文的都有,一种比较常见的解决思路是,执行以下语句:

select update_time from information_schema.tables where table_name='mytab' and table_schema='mydb'

如果MySQL的版本相对较低(比如说,5.7.30),上述语句是没有问题的,可以轻易进行验证。

但是,这种写法在我本机(macOS)的MySQL(版本8.0.21)实例上是有问题的,返回的值是NULL

  • Update_time
    When the data file was last updated. For some storage engines, this value is NULL. For example, InnoDB stores multiple tables in its system tablespace and the data file timestamp does not apply. Even with file-per-table mode with each InnoDB table in a separate .ibd file, change buffering can delay the write to the data file, so the file modification time is different from the time of the last insert, update, or delete. For MyISAM, the data file timestamp is used; however, on Windows the timestamp is not updated by updates, so the value is inaccurate.
    Update_time displays a timestamp value for the last UPDATE, INSERT, or DELETE performed on InnoDB tables that are not partitioned. For MVCC, the timestamp value reflects the COMMIT time, which is considered the last update time. Timestamps are not persisted when the server is restarted or when the table is evicted from the InnoDB data dictionary cache.

大概意思是,对于使用了某些存储引擎的表,其update_time的值为NULL。例如,InnoDB在系统表空间中会存储多张表,因此,数据文件的时间戳不会同步到information_schema.tables中去。即使使用了InnoDBfile-per-table模式——每张表单独存储成一个.ibd文件——change buffering仍会延迟将更新时间写入数据文件中,所以,information_schema.tables中记录的更新时间会和实际的更新时间不同。对于MyISAM存储引擎,数据文件的时间戳被用来作为update_time的值。

按照上述说法,之所以在我的机器上更新了目标表而查询到的值为NULL,可能得原因有两个:1,使用了InnoDB存储引擎,并且没有使用file-per-table模式;2,使用了file-per-table模式,而更新时间会有延迟,所以无法马上查询到。

我查找相关资料后发现,从5.6开始,MySQL的InnoDB引擎默认是使用file-per-table模式的,通过查找磁盘上的数据表文件也发现,确实每张表会存储成一个单独的.idb文件。

那么,问题就应该出在更新时间延迟这里。根据官方文档中对全局变量change buffering的解释,可以将该变量的值设置为‘null’,表示不缓存任何插入、删除、更新操作。按照我的理解,这样设置之后,虽然I/O开销会增加,但是应该就可以立即将更新时间同步写到information_schema.tables中了。于是,我执行了以下操作:

set global innodb_change_buffering = 'none'  -- 更改全局变量innodb_change_buffering的值

show global variables like 'innodb_change_buffering' -- 查询一下,确定更改生效

然后我再次对目标表执行了插入、更新、删除操作后,利用一开始的sql查询update_time,发现依然是空。

至此,我没有任何办法了。我在Stack Overflow上提了相关问题,有一些人提供了一些想法,可以点击这里进行交流。

3、其他方案

其实在默认的InnoDB存储引擎下,每一张表都是一个单独的文件,那么对表进行任何更改操作的话,对应文件的修改时间肯定发生了变化,因此,如果可以定位到表对应磁盘上的文件,直接获取文件的最新更新时间即可。

而且这似乎也是update_time中值的填充方式。

手动狗头。