37

I want to find out which tables have been modified in the last hour in a MySQL database. How can I do this?

Vaishali
  • 431
  • 1
  • 4
  • 17
agente_secreto
  • 7,959
  • 16
  • 57
  • 83
  • 1
    Do your tables have a timestamp column when data was changed? – TomTom Mar 22 '10 at 12:13
  • I think most of them, if not all, have a "created" field. I am not sure if that answers your question; the database is from a website which I did not develop but have to mantain, so I am a little lost. – agente_secreto Mar 22 '10 at 12:21
  • can you describe the usecase? there might be a better solution to what you want to achieve – neal aise Jul 05 '10 at 15:58
  • To clarify the bounty: the `UPDATE_TIME` feature / trick needs to work on an extant InnoDB database that we have **read** access to, not one that we are starting from scratch. Therefore triggers or simply adding an `updated` field are not feasible. – dotancohen Jun 23 '13 at 05:16
  • @dotancohen Are you using innodb_file_per_table ? – RolandoMySQLDBA Jun 24 '13 at 19:59
  • @dotancohen Another question : What version of MySQL are you using ??? – RolandoMySQLDBA Jun 24 '13 at 20:11
  • See [this related question](http://dba.stackexchange.com/questions/9569/fastest-way-to-check-if-innodb-table-has-changed) for Rolando's past answer on the topic, and a plug for Percona server. – Erin Schoonover Jun 24 '13 at 22:18
  • Hi Rolando! The project where this is important is on MySQL 5.5, but I was hoping for a version-agnostic solution, such as your answer as linked by Ian. That may be a good solution. Also, it appears that MySQL 5.7 will have `UPDATE_TIME` enabled for InnoDB, but the value won't persist across resets of `mysqld`! – dotancohen Jun 25 '13 at 07:47
  • @RolandoMySQLDBA: Can you please post an answer with a link to your post on dba.SE, as that does seem to be the best answer and I would like to accept it. Thanks! – dotancohen Jun 27 '13 at 07:17
  • @dotancohen I added my answer 12 minutes ago with a slight update. – RolandoMySQLDBA Jun 27 '13 at 11:10

5 Answers5

63

MySQL 5.x can do this via the INFORMATION_SCHEMA database. This database contains information about tables, views, columns, etc.

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

Returns all tables that have been updated (UPDATE_TIME) in the last hour. You can also filter by database name (TABLE_SCHEMA column).

An example query:

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';
Meloman
  • 3,558
  • 3
  • 41
  • 51
rjh
  • 49,276
  • 4
  • 56
  • 63
  • 27
    Be aware that this approach only works for MyISAM tables, not InnoDB. – Ike Walker Mar 22 '10 at 20:23
  • 1
    For InnoDB I'm hard-pressed to find an alternative. Maybe triggers on insert and delete operations. – rjh Jan 25 '13 at 11:07
  • As Ike Walker mentioned above, it is not working with InnoDB. The UPDATE_TIME column in information_schema.TABLES is never updated. Hence the query mentioned would fail. – RRM Nov 25 '14 at 05:32
  • 3
    For mysql 5.7.15 the request is working for InnoDB tables just fine. – Zur13 Oct 21 '16 at 13:58
  • Yes, I confirm @Zur13 info, my MySQL server in **5.7.19** has both **myISAM and InnoDB** tables in different databases and it **works fine** for all. – Meloman Oct 13 '17 at 09:21
  • I am looking for a Postgres-friendly way, this does not work. Please guide me to the correct Q&As. – computingfreak Sep 12 '18 at 09:23
5

For each table you want to detect change, you need to have a column that holds the last change's timestamp.

For every insert or update in the table, you need to update that column with the current date and time.

Alternatively, you can set up a trigger which updates the column automatically on each insert or modify. That way you don't have to modify all of your query.

Once this works, to find out if rows from a table have been modified in the last hour, perform the query

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

Repeat for every table you want to check.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
David V.
  • 5,708
  • 3
  • 27
  • 27
4

InnoDB still currently lacks a native mechanism to retreive this information. In the related feature request at MySQL, someone advises to set AFTER [all events] triggers on each table to be monitored. The trigger would issue a statement such as

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

in a table like this:

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

Alternatively, if a slight inaccuracy in this data (in the range of one second) is acceptable, and if you have read access to the MySQL data files, you could switch to a setting where inndb_files_per_table = ON (recommended in any case) and check the last modification time of the underlying data files.

These files are found under /var/lib/mysql/[database_name]/*.ibd in most default installations.

Please note, if you decide to take this route, you need to recreate existing tables for the new setting to apply.

RandomSeed
  • 29,301
  • 6
  • 52
  • 87
  • You may want to use the TIMESTAMP datatype instead of DATETIME. Define it as " `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP " ...and it will automatically be set when inserting data if omitted. – DustWolf Apr 04 '15 at 19:40
4

I have answered a question like this in the DBA StackExchange about 1.5 years ago: Fastest way to check if InnoDB table has changed.

Based on that old answer, I recommend the following

Flushing Writes to Disk

This is a one-time setup. You need to set innodb_max_dirty_pages_pct to 0.

First, add this to /etc/my.cnf

[mysqld]
innodb_max_dirty_pages_pct=0

Then, run this to avoid having to restart mysql:

mysql> SET GLOBAL innodb_max_dirty_pages_pct = 0;

Get Timestamp of InnoDB table's .ibd file

ls has the option to retrieve the UNIX timestamp in Seconds. For an InnoDB table mydb.mytable

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

You can then compute UNIX_TIMESTAMP(NOW()) - (timestamp of the .ibd file) and see if it is 3600 or less.

Give it a Try !!!

Community
  • 1
  • 1
RolandoMySQLDBA
  • 43,883
  • 16
  • 91
  • 132
0
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'
user1140237
  • 5,015
  • 1
  • 28
  • 56