如何得知MySQL表的最后更新时间?


176

在页面的页脚中,我想添加诸如“最后更新xx / xx / 200x”之类的内容,该日期为最后一次更新某些mySQL表的时间。

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


Answers:


276

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

SELECT UPDATE_TIME
FROM   information_schema.tables
WHERE  TABLE_SCHEMA = 'dbname'
   AND TABLE_NAME = 'tabname'

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


另一种选择是每当更新MySQL表时“触摸”特定文件:

关于数据库更新:

  • O_RDRW模式下打开您的时间戳文件
  • close 再来一次

或者

  • 使用功能touch()等效的PHP utimes()来更改文件时间戳。

在页面上显示:

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

9
有关InnoDB限制的详细信息,请参见dev.mysql.com/doc/refman/5.5/en/show-table-status.htmlshow table status使用information_schema.tables
KCD 2012年

11
UPDATE_TIME方法和以下show table status方法仅适用于MyISAM引擎,不适用于InnoDB。尽管这被列为bug,但在MySQL 5.5 Reference中已提及,该参考书还指出该file_per_table模式是修改时间的不可靠指标。
idoimaging 2012年

5
再说一次,在InnoDB上不起作用,因为mysql是越野车:bugs.mysql.com/bug.php?id=14374
TMS

7
对于MySQL 5.7.2+,它也适用于InnoDB:“从MySQL 5.7.2开始,UPDATE_TIME显示对未分区的InnoDB表执行的最后一次UPDATE,INSERT或DELETE的时间戳值。以前,UPDATE_TIME显示NULL值用于InnoDB表。”
Peter V.Mørch2015年

2
对于我来说,这似乎并不会在重新启动(在5.7.11版本上)上持续存在。

58

我没有使用MySQL 4.1.16版的information_schema数据库,因此在这种情况下,您可以查询以下内容:

SHOW TABLE STATUS FROM your_database LIKE 'your_table';

它将返回以下列:

| 姓名| 引擎| 版本| 行格式| 行| Avg_row_length 
| 数据长度| 最大数据长度| 索引长度| 无数据| 自动递增
| 创建时间| 更新时间 | 检查时间| 整理
| 校验和 Create_options | 评论|

如您所见,有一列称为“ Update_time ”,它显示了your_table的最后更新时间。


2
它还比SELECT语句执行得更快(4倍)
jmav 2013年

1
实际上,大多数这样的SHOW命令只是在内部简单地映射到Information_schema查询,因此,此答案给出的数据与上面Alnitak给出的答案完全相同。而且ajacian81是正确的-它不适用于MySQL的默认存储引擎InnoDB。
比尔·卡温

55

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

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;

即使我们在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 |
+----+------+---------------------+

现在您可以查询MAX()了:

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

诚然,这需要更多的存储空间(TIMESTAMP每行4个字节)。
但这不适用于MySQL 5.7.15之前的InnoDB表INFORMATION_SCHEMA.TABLES.UPDATE_TIME事实并非如此。


10
+1就我而言,这是对这个问题的唯一正确答案。这个问题确实想知道何时更新相关数据,而不是何时出于某种原因而更改或不更改表(与用户无关)。
siride

23
但是,如果删除更新时间较短的记录,则MAX(updated_at)将不起作用。
Ammamon 2014年

3
@Ammamon,是的,如果您还需要考虑删除操作,则此解决方案无法反映这一点。触发更新汇总表的触发器可能是唯一的综合解决方案,但这会造成瓶颈。
Bill Karwin 2014年

2
在大多数情况下,知道删除就不那么重要了,许多更高级别的aps并不能真正从许多表中删除,而只是取消设置等效项的标志。
塞缪尔·富尔曼

1
@Pavan,没有区别,您只是依赖默认行为,而我的示例明确说明了该选项。但是该选项与默认行为相同。
比尔·卡温

13

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

cd /var/lib/mysql/<mydatabase>
ls -lhtr *.ibd

这应该为您提供所有表的列表以及该表的最早修改时间(最早的时间)。


在我的情况(MariaDb)中,所有表的UPDATE_TIME为NULL时,这确实是个很好的答案
Alexander Vasiljev,

ibd文件仅存储表结构。缺省情况下,数据存储在ibdata1中,因此当表中的数据更改时,ibd文件时间戳将不会更新。https://dev.mysql.com/doc/refman/8.0/zh-CN/show-table-status.html
堆栈下溢

7

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

SELECT UPDATE_TIME, TABLE_SCHEMA, TABLE_NAME
FROM information_schema.tables
ORDER BY UPDATE_TIME DESC, TABLE_SCHEMA, TABLE_NAME

3
为什么我所有的人UPDATE_TIME都不为空?任何想法?
Metafaniel

5
您的UPDATE_TIME为空,因为您使用的是InnoDB而不是MyISAM。通常,InnoDB是更好的选择,但它不支持UPDATE_TIME。
Xaraxia

5

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

只是因为我不喜欢直接读取db服务器的内部系统表的想法


1
对于MS SQL,这似乎是一个不错的解决方案,因为没有UPDATE_TIME像MySQL这样的列。
达西,

3

尽管有一个公认的答案,但我认为这不是正确的答案。这是实现所需功能的最简单方法,但是即使您在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

1

操作系统级别分析:

查找数据库在磁盘上的存储位置:

grep datadir /etc/my.cnf
datadir=/var/lib/mysql

检查最新修改

cd /var/lib/mysql/{db_name}
ls -lrt

应该适用于所有数据库类型。


0

只需获取从文件系统修改的文件日期即可。用我的语言是:

 tbl_updated = file.update_time(
        "C:\ProgramData\MySQL\MySQL Server 5.5\data\mydb\person.frm")

输出:

1/25/2013 06:04:10 AM

6
看起来是高度不可移植的
骇客

0

如果您运行的是Linux,则可以使用inotify查看表或数据库目录。inotify可从PHP,node.js,perl获得,我怀疑大多数其他语言。当然,您必须已经安装了inotify或由ISP安装了它。很多ISP不会。


2
如果您的数据库在单独的服务器上运行,则文件系统检查无用
Sam Dufel 2014年

0

不知道这是否会引起任何兴趣。我在最近使用的解决方案是在mysql和客户端之间使用mysqlproxy,并根据有趣的表更改使用lua脚本更新memcached中的键值。如果包装器支持php中的钩子或触发器,则可能更容易了。到目前为止,没有包装器执行此操作。


0

我按名称列出了一个列:phpMyAdmin中的update-at,并从我的代码(nodejs)中的Date()方法获取了当前时间。表格中的每次更改都会保留更改时间。


1
欢迎来到StackOverflow!请编辑您的答案以包括您使用的一些代码,并解释为什么选择这种方式。这个问题将近11年了,并且已经有了一个公认的,被广泛认可的答案。没有任何代码或解释的答案,很可能会被否决或删除。对其进行编辑以包括这些内容将有助于证明其在本文中的位置。
Das_Geek

0

a)它会显示所有表格以及最近的更新日期

SHOW TABLE STATUS FROM db_name;

然后,您可以进一步要求提供特定表格:

SHOW TABLE STATUS FROM db_name like 'table_name';

b)如上例所示,您不能在“ Update_time”上使用排序,但是使用SELECT可以:

SELECT * FROM information_schema.tables WHERE TABLE_SCHEMA='db_name' ORDER BY UPDATE_TIME DESC;

进一步询问特定的表:

SELECT * FROM information_schema.tables WHERE TABLE_SCHEMA='db_name' AND table_name='table_name' ORDER BY UPDATE_TIME DESC';

-1

这就是我所做的,希望对您有所帮助。

<?php
    mysql_connect("localhost", "USER", "PASSWORD") or die(mysql_error());
    mysql_select_db("information_schema") or die(mysql_error());
    $query1 = "SELECT `UPDATE_TIME` FROM `TABLES` WHERE
        `TABLE_SCHEMA` LIKE 'DataBaseName' AND `TABLE_NAME` LIKE 'TableName'";
    $result1 = mysql_query($query1) or die(mysql_error());
    while($row = mysql_fetch_array($result1)) {
        echo "<strong>1r tr.: </strong>".$row['UPDATE_TIME'];
    }
?>

2
您为什么要在这里使用?
凯尔·布​​什

3
@WesleyMurch:<font>标签已被弃用。
siride

-9

当查询不可用时,将查询缓存在全局变量中。

创建一个网页以强制在更新缓存时重新加载它。

将对重新加载页面的调用添加到部署脚本中。


2
如果没有外部帮助,您将无法在PHP页面的独立调用之间“缓存”变量。
Alnitak
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.