如何判断MySQL表的上次更新时间?

RaG*_*aGE 169 mysql sql

在我页面的页脚中,我想添加类似"上次更新xx/xx/200x"的内容,此日期是某个mySQL表最后一次更新的日期.

最好的方法是什么?是否有检索上次更新日期的功能?我每次需要这个值时都应该访问数据库吗?

Aln*_*tak 265

在MySQL的更高版本中,您可以使用information_schema数据库告诉您何时更新了另一个表:

SELECT UPDATE_TIME
FROM   information_schema.tables
WHERE  TABLE_SCHEMA = 'dbname'
   AND TABLE_NAME = 'tabname'
Run Code Online (Sandbox Code Playgroud)

这当然意味着打开与数据库的连接.


另一种选择是在MySQL表更新时"触摸"特定文件:

在数据库更新:

  • O_RDRW模式下打开时间戳文件
  • close 它再次

或者

  • 使用函数touch()的PHP等价物utimes()来更改文件时间戳.

在页面显示:

  • 用于stat()回读文件修改时间.

  • 下面的`UPDATE_TIME`方法和`show table status`方法仅适用于MyISAM引擎,而不适用于InnoDB.虽然这被列为[bug](http://bugs.mysql.com/bug.php?id=15438),但在[MySQL 5.5 Reference](http://dev.mysql.com/)中提到了它. doc/refman/5.5/en/show-table-status.html),它还说`file_per_table`模式是修改时间的不可靠指标. (10认同)
  • 有关InnoDB限制的详细信息,请参阅http://dev.mysql.com/doc/refman/5.5/en/show-table-status.html(`show table status`使用`information_schema.tables`) (8认同)
  • 对于MySQL 5.7.2+,它[适用于InnoDB](https://dev.mysql.com/doc/refman/5.7/en/tables-table.html):"从MySQL 5.7.2开始,UPDATE_TIME显示一个在未分区的InnoDB表上执行的最后一次UPDATE,INSERT或DELETE的时间戳值.以前,UPDATE_TIME为InnoDB表显示NULL值. (7认同)
  • 再次,不能在InnoDB上工作,因为mysql是f**王车:http://bugs.mysql.com/bug.php?id = 14374 (5认同)
  • 对我来说这似乎不会持续重启(在5.7.11版本上). (2认同)
  • 有没有办法在2018年获取InnoDB表的信息? (2认同)

Rad*_*ris 55

我没有使用mysql 4.1.16版本的information_schema数据库,所以在这种情况下你可以查询:

SHOW TABLE STATUS FROM your_database LIKE 'your_table';
Run Code Online (Sandbox Code Playgroud)

它将返回以下列:

| Name      | Engine | Version | Row_format | Rows | Avg_row_length 
| Data_length | Max_data_length | Index_length | Data_free | Auto_increment
| Create_time | Update_time | Check_time | Collation
| Checksum | Create_options | Comment |

正如你可以看到有一个名为列:" UPDATE_TIME ",显示你最后更新时间your_table.

  • 它还执行更快(4x)然后SELECT语句 (2认同)

Bil*_*win 48

我很惊讶没有人建议跟踪每行的最后更新时间:

mysql> CREATE TABLE foo (
  id INT PRIMARY KEY
  x INT,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 
                     ON UPDATE CURRENT_TIMESTAMP,
  KEY (updated_at)
);

mysql> INSERT INTO foo VALUES (1, NOW() - INTERVAL 3 DAY), (2, NOW());

mysql> SELECT * FROM foo;
+----+------+---------------------+
| id | x    | updated_at          |
+----+------+---------------------+
|  1 | NULL | 2013-08-18 03:26:28 |
|  2 | NULL | 2013-08-21 03:26:28 |
+----+------+---------------------+

mysql> UPDATE foo SET x = 1234 WHERE id = 1;
Run Code Online (Sandbox Code Playgroud)

这会更新时间戳,即使我们没有在UPDATE中提及它.

mysql> SELECT * FROM foo;
+----+------+---------------------+
| id | x    | updated_at          |
+----+------+---------------------+
|  1 | 1235 | 2013-08-21 03:30:20 | <-- this row has been updated
|  2 | NULL | 2013-08-21 03:26:28 |
+----+------+---------------------+
Run Code Online (Sandbox Code Playgroud)

现在您可以查询MAX():

mysql> SELECT MAX(updated_at) FROM foo;
+---------------------+
| MAX(updated_at)     |
+---------------------+
| 2013-08-21 03:30:20 |
+---------------------+
Run Code Online (Sandbox Code Playgroud)

不可否认,这需要更多存储空间(TIMESTAMP每行4个字节).
但这适用于 5.7.15版MySQL之前的InnoDB表,INFORMATION_SCHEMA.TABLES.UPDATE_TIME但没有.

  • 但是如果删除更新时间较短的记录,MAX(updated_at)将无效. (20认同)
  • +1 就我而言,这是这个问题的唯一正确答案。问题真正想知道何时更新相关数据,而不是何时更新表(与用户无关)可能会或可能不会因任何原因而更改。 (9认同)
  • @Ammamon,是的,如果你还需要考虑删除,这个解决方案并没有反映出来.更新摘要表的触发器可能是唯一全面的解决方案,但这会产生瓶颈. (2认同)
  • 对于大多数情况,知道删除不是那么相关,并且许多更高级别的aps并没有真正从许多表中删除,而只是取消设置等效的标志. (2认同)

小智 11

最简单的方法是检查磁盘上表文件的时间戳.例如,您可以在数据目录下查看

cd /var/lib/mysql/<mydatabase>
ls -lhtr *.ibd
Run Code Online (Sandbox Code Playgroud)

这应该为您提供所有表的列表,其中包含表在上次修改时的最早时间,第一个.


Fra*_*ois 7

有关最近表更改的列表,请使用以下命令:

SELECT UPDATE_TIME, TABLE_SCHEMA, TABLE_NAME
FROM information_schema.tables
ORDER BY UPDATE_TIME DESC, TABLE_SCHEMA, TABLE_NAME
Run Code Online (Sandbox Code Playgroud)

  • 您的UPDATE_TIME为空,因为您使用的是InnoDB而不是MyISAM.InnoDB通常是更好的选择,但它不支持UPDATE_TIME. (5认同)
  • 为什么我的所有`UPDATE_TIME`都为空?任何的想法? (3认同)

Mik*_*ail 5

我会创建一个触发器来捕获所有更新/插入/删除并在自定义表中写入时间戳,类似于tablename | 时间戳

仅仅因为我不喜欢直接读取db server的内部系统表的想法


Sou*_*ver 5

尽管有一个公认的答案,但我不认为这是正确的。这是实现所需功能的最简单方法,但即使已经在 InnoDB 中启用(实际上文档告诉你你仍然应该得到 NULL ...),如果你阅读 MySQL文档,即使在当前版本(8.0)中使用 UPDATE_TIME 也是如此这不是正确的选择,因为:

当服务器重新启动或从 InnoDB 数据字典缓存中逐出表时,时间戳不会保留。

如果我理解正确(现在无法在服务器上验证它),时间戳会在服务器重新启动后重置。

至于真正的(而且,昂贵的)解决方案,您可以使用 Bill Karwin 的CURRENT_TIMESTAMP解决方案,我想提出一种基于触发器的不同解决方案(我正在使用那个)。

首先创建一个单独的表(或者也许您有其他一些可用于此目的的表),它将像全局变量(此处为时间戳)的存储一样工作。您需要存储两个字段 - 表名称(或您希望在此处保留为表 id 的任何值)和时间戳。获得后,您应该使用此表 id + 开始日期对其进行初始化(NOW() 是一个不错的选择:))。

现在,您可以移动到要观察的表,并使用以下过程或类似过程在 INSERT/UPDATE/DELETE 后添加触发器:

CREATE PROCEDURE `timestamp_update` ()
BEGIN
    UPDATE `SCHEMA_NAME`.`TIMESTAMPS_TABLE_NAME`
    SET `timestamp_column`=DATE_FORMAT(NOW(), '%Y-%m-%d %T')
    WHERE `table_name_column`='TABLE_NAME';
END
Run Code Online (Sandbox Code Playgroud)