【问题标题】:Query to find tables modified in the last hour查询过去一小时内修改过的表
【发布时间】:2011-01-30 07:50:12
【问题描述】:

我想找出 MySQL 数据库中在过去一小时内修改了哪些表。我该怎么做?

【问题讨论】:

  • 您的表在数据更改时是否有时间戳列?
  • 我认为他们中的大多数(如果不是全部的话)都有一个“创建”字段。我不确定这是否能回答您的问题;该数据库来自一个我没有开发但必须维护的网站,所以我有点迷茫。
  • 你能描述一下用例吗?您想要实现的目标可能有更好的解决方案
  • 澄清赏金:UPDATE_TIME 功能/技巧需要在我们有 read 访问权限的现有 InnoDB 数据库上工作,而不是我们从头开始的数据库.因此,触发器或简单地添加一个updated 字段是不可行的。
  • @dotancohen 你在使用 innodb_file_per_table 吗?

标签: mysql database


【解决方案1】:

MySQL 5.x 可以通过 INFORMATION_SCHEMA 数据库做到这一点。该数据库包含有关表、视图、列等的信息。

SELECT * 
FROM `INFORMATION_SCHEMA`.`TABLES`
WHERE 
    DATE_SUB(NOW(), INTERVAL 1 HOUR) < `UPDATE_TIME`

返回过去一小时内已更新 (UPDATE_TIME) 的所有表。您还可以按数据库名称(TABLE_SCHEMA 列)进行过滤。

一个示例查询:

SELECT 
    CONCAT(`TABLE_SCHEMA`, '.', `TABLE_NAME`) AS `Table`, 
    UPDATE_TIME AS `Updated`
FROM `INFORMATION_SCHEMA`.`TABLES`
WHERE
    DATE_SUB(NOW(), INTERVAL 3 DAY) < `UPDATE_TIME`
    AND `TABLE_SCHEMA` != 'INFORMATION_SCHEMA'
    AND `TABLE_TYPE` = 'BASE TABLE';

【讨论】:

  • 谢谢!这正是我所需要的
  • 请注意,这种方法仅适用于 MyISAM 表,不适用于 InnoDB。
  • 对于 InnoDB,我很难找到替代方案。可能会触发插入和删除操作。
  • 正如 Ike Walker 上面提到的,它不适用于 InnoDB。 information_schema.TABLES 中的 UPDATE_TIME 列永远不会更新。因此,提到的查询将失败。
  • 对于 mysql 5.7.15,该请求适用于 InnoDB 表就好了。
【解决方案2】:

对于您要检测更改的每个表,您需要有一列保存上次更改的时间戳。

对于表中的每次插入或更新,您需要使用当前日期和时间更新该列。

或者,您可以设置trigger,它会在每次插入或修改时自动更新列。这样您就不必修改所有查询。

一旦成功,要查明表中的行是否在过去一小时内被修改过,请执行查询

select count(*) from mytable where datemod>subtime(now(),'1:0:0')

对您要检查的每个表重复。

【讨论】:

    【解决方案3】:

    InnoDB 目前仍缺乏检索此信息的本机机制。在related feature request at MySQL中,有人建议在每个要监控的表上设置AFTER [all events]触发器。触发器会发出一条语句,例如

    INSERT INTO last_update VALUE ('current_table_name', NOW())
    ON DUPLICATE KEY UPDATE update_time = NOW();
    

    在这样的表格中:

    CREATE TABLE last_update (
        table_name VARCHAR(64) PRIMARY KEY,
        update_time DATETIME
    ) ENGINE = MyISAM; -- no need for transactions here
    

    或者,如果此数据中的轻微不准确(在一秒范围内)是可以接受的,并且如果您对 MySQL 数据文件具有读取权限,则可以切换到 inndb_files_per_table = ON 的设置(在任何情况下都建议) 并检查底层数据文件的最后修改时间。

    在大多数默认安装中,这些文件位于 /var/lib/mysql/[database_name]/*.ibd 下。

    请注意,如果您决定采用此路线,则需要recreate existing tables 以应用新设置。

    【讨论】:

    • 您可能希望使用 TIMESTAMP 数据类型而不是 DATETIME。定义为“update_timeTIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP”……如果省略,插入数据时会自动设置。
    【解决方案4】:

    大约 1.5 年前,我在 DBA StackExchange 中回答了这样一个问题:Fastest way to check if InnoDB table has changed

    基于那个旧答案,我推荐以下内容

    刷新写入磁盘

    这是一次性设置。您需要将innodb_max_dirty_pages_pct 设置为 0。

    首先,将其添加到 /etc/my.cnf

    [mysqld]
    innodb_max_dirty_pages_pct=0
    

    然后,运行此命令以避免重新启动 mysql:

    mysql> SET GLOBAL innodb_max_dirty_pages_pct = 0;
    

    获取 InnoDB 表 .ibd file 的时间戳

    ls 可以选择以秒为单位检索 UNIX 时间戳。对于 InnoDB 表mydb.mytable

    $ cd /var/lib/mysql/mydb
    $ ls -l --time-style="+%s" mytable.ibd | awk '{print $6}'
    

    然后您可以计算 UNIX_TIMESTAMP(NOW()) - (timestamp of the .ibd file) 并查看它是否为 3600 或更低。

    试试看!!!

    【讨论】:

      【解决方案5】:
      SELECT *
      FROM  information_schema.tables
      WHERE UPDATE_TIME >= SYSDATE() - INTERVAL 1 DAY  && TABLE_TYPE != 'SYSTEM VIEW'
      
      SELECT * 
      FROM information_schema.tables
      WHERE UPDATE_TIME >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) && TABLE_TYPE != 'SYSTEM VIEW'
      

      【讨论】:

        猜你喜欢
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 2011-05-02
        • 2018-06-22
        • 1970-01-01
        • 1970-01-01
        • 2011-03-15
        相关资源
        最近更新 更多