I want to find out which tables have been modified in the last hour in a MySQL database. How can I do this?
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';
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.
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.
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 !!!
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'
Related
I'm replicating from mysql 5.6.33 to 5.7.41. I have a table with a datetime field. If I understand correctly, between 5.6 and 5.7 the decreased the space a datetime field uses because it doesn't store timezone data. (but a timestamp does).
This query works on 5.7 (note the presence of the timezone field):
select count(*) from login_activities where date_created < '2023-01-15 04:00:15 -0800';
This delete statement does not work:
delete from login_activities where date_created < '2023-01-15 04:00:15 -0800'
ERROR:
Error 'Incorrect datetime value: '2023-01-15 04:00:15 -0800' for column 'date_created' at row 1' on query. Default database: 'sms'. Query: 'delete from login_activities where date_created < '2023-01-15 04:00:15 -0800''
How can I get the delete to work in the same way the select works? I've even removed sql_mode entries but still can't get it to work in 5.7
edit:
not sure if this matters, but the error with the delete statement is happining during replication (5.6 -> 5.7), but I'm running the select statement manually. I haven't tried running the delete statement manually because it will through off the replication.
I'm looking for a way to get datetime of last ALTER TABLE (structure edit) of a table. I'm currently using MySql 5.6. Checking information_schema db I can get only the last generic edit of the table (INSERT, UPDATE, etc.). Thanks in advance.
Try this
SELECT
create_time
FROM
INFORMATION_SCHEMA.TABLES
WHERE
table_schema = 'databasename'
AND table_name = 'tablename';
Above query gives the last table structure edited datetime.
I wonder if is it possible to get creation date of column in a table? I want to see the creation times of columns that added later.
So you can get this information for the table quite easily. You would query the information_schema for the create_time of the table.
For instance:
SELECT create_time FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema = 'your_schema'
AND table_name = 'your_table'
Check here for more information:
https://dev.mysql.com/doc/refman/5.7/en/tables-table.html
For a specific column this is not as simple because none of the system tables (that is, nothing in the INFORMATION_SCHEMA database) exist that has that kind of information recorded anywhere. In other words, there is no native mechanism to put any timestamps on column changes.
Any time that:
one or more columns change in any row
a new row is added
an old is deleted
an ALTER TABLE of any kind
the UPDATE_TIME column in INFORMATION_SCHEMA.TABLES is updated.
You could find all changes in the last hour (or your selected interval) quite simply though:
SELECT CONCAT(TABLE_SCHEMA, '.', TABLE_NAME) AS Table, UPDATE_TIME AS Updated
FROM INFORMATION_SCHEMA.TABLES
WHERE DATE_SUB(NOW(), INTERVAL 1 HOUR) < UPDATE_TIME
AND TABLE_SCHEMA != 'INFORMATION_SCHEMA'
AND TABLE_TYPE = 'BASE TABLE';
I hope this helps.
This question already has answers here:
Converting mysql column from INT to TIMESTAMP
(2 answers)
Closed 8 years ago.
I am still pretty new to databases in general.
I created one and had my application get the current time as a Unix timestamp and stored in in time_stamp int(11) NOT NULL.
Now I realize how dumb that was, but I don't want to lose my data.
Is there an UPDATE statement I can use in the MySql command box to change all those INTs to MySql TIMESTAMPs?
Alternatively, I have a dump of the database, so I guess I could also use PhpMyAdmin to redefine the column (which seems to set all my INTs to "00-00-0000 00:00:00") and then delete the table contents, global edit the SqlDump and import it.
But, if I do, how do I edit the dump? Here are a few lines of it ...
INSERT INTO `activity` (`badge_number`, `time_stamp`, `activity`, `bar_code`, `rfid_tag`)
VALUES (0, 1350388291, 'login', '', ''), (0,1350388433, 'logout', '', ''),
So,
UPDATE ACTIVITY SET time_stamp = <what?> WHERE <what?>
Thanks in advance for any help.
Try either
ALTER TABLE activity CHANGE time_stamp time_stamp VARCHAR(19);
UPDATE activity
SET time_stamp = FROM_UNIXTIME(time_stamp);
ALTER TABLE activity CHANGE time_stamp time_stamp TIMESTAMP;
Here is SQLFiddle demo
or
ALTER TABLE activity ADD COLUMN time_stamp2 TIMESTAMP;
UPDATE activity
SET time_stamp2 = FROM_UNIXTIME(time_stamp);
ALTER TABLE activity DROP COLUMN time_stamp;
ALTER TABLE activity CHANGE time_stamp2 time_stamp TIMESTAMP;
Here is SQLFiddle demo
Note: Before you proceed with update make sure that you have a solid backup of your table/database. Just in case.
Is there a way to tell the last access time of a mysql table? By access I mean any type of operation in that table including update, alter or even select or any other operation.
Thanks.
You can get the last update time of a table.
SELECT update_time FROM information_schema.tables WHERE table_name='tablename'
You can use the OS level stat command.
Locate the ibd file for that particular table and run the below command
stat file_location
If the Table is being queried by SELECT, You can find the timestamp of when it was accessed with under the Access field.
I don't know how to get the exact time after-the-fact, but you can start dumping logs, do something, and then stop dumping logs. Whichever tables show up in the logs are the ones that were accessed during that time.
If you care to dig through the log, the queries are shown with timestamps.
Tell mysql where to put the log file
Add this line to my.cnf (on some systems it will be mysql.conf.d/mysqld.cnf).
general_log_file = /path/to/query.log
Enable the general log
mysql> SET global general_log = 1;
(don't forget to turn this off, it can grow very quickly)
Do the thing
All mysql queries will be added to /path/to/query.log
Disable the general log
mysql> SET global general_log = 0;
See which tables appeared
If it's short, you can just scroll through query.log. If not, then you can filter the log for known table names, like so:
query_words=$(cat mysql_general.log | tr -s [:space:] \\n | tr -c -d '[a-zA-Z0-9][:space:][_\-]' | egrep -v '[0-9]' | sort | uniq)
table_names=$(mysql -uroot -ptest -Dmeta -e"show tables;" | sort | uniq)
comm -12 <(echo $table_names) <(echo $query_words)
From there, you can grep the log file for whatever showed up in table_names. There you will find timestammped queries.
See also, this utility, which I made.
For a more detailed (db name and table name) plus the period (range), try this query:
select table_schema as DatabaseName,
table_name as TableName,
update_time as LastAccessTime
from information_schema.tables
where update_time < 'yyyy-mm-dd'
group by table_schema
order by update_time asc
Use information_schema database to find which table of respective database was updated:
SELECT UPDATE_TIME
FROM information_schema.tables
WHERE TABLE_SCHEMA = 'dbname'
AND TABLE_NAME = 'tablename'
order by UPDATE_TIME DESC