Как я могу узнать, когда таблица MySQL последний раз обновлялась?

176

В нижнем колонтитуле моей страницы я хотел бы добавить что-то вроде «последнее обновление xx / xx / 200x», причем эта дата является последним обновлением определенной таблицы mySQL.

Каков наилучший способ сделать это? Есть ли функция для получения последней обновленной даты? Должен ли я обращаться к базе данных каждый раз, когда мне нужно это значение?

раж
источник
Связанный: stackoverflow.com/questions/12563706/…
Пекка

Ответы:

277

В более поздних версиях 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.html ( show table statusиспользует information_schema.tables)
KCD
11
И UPDATE_TIMEметод, и show table statusметод ниже доступны только для движка MyISAM, но не для InnoDB. Хотя это перечислено как ошибка , это упомянуто в Справочнике MySQL 5.5 , который также говорит, что file_per_tableрежим - ненадежный индикатор времени модификации.
idoimaging
5
Опять же, не работает на InnoDB, потому что mysql f ** king глючит
TMS
7
Для MySQL 5.7.2+ это также работает для InnoDB : «Начиная с MySQL 5.7.2, UPDATE_TIME отображает значение метки времени для последних UPDATE, INSERT или DELETE, выполненных для таблиц InnoDB, которые не разбиты на разделы. Ранее UPDATE_TIME отображало значение NULL для таблиц InnoDB. "
Питер В. Мёрч
2
Похоже, это не сохраняется при перезапуске для меня (в версии 5.7.11).
58

У меня нет базы данных information_schema, использующей mysql версии 4.1.16, поэтому в этом случае вы можете запросить это:

SHOW TABLE STATUS FROM your_database LIKE 'your_table';

Он вернет эти столбцы:

| Имя | Двигатель | Версия | Row_format | Ряды | Avg_row_length 
| Длина_данных | Max_data_length | Index_length | Data_free | Авто_инкремент
| Create_time | Update_time | Check_time | Сопоставление
| Контрольная сумма | Create_options | Комментарий |

Как вы можете видеть, есть столбец с именем: « Update_time », который показывает время последнего обновления вашей_таблицы .

Раду Марис
источник
2
Он также работает быстрее (в 4 раза), чем оператор SELECT
jmav
1
Фактически, большинство таких команд SHOW просто сопоставляются с запросами Information_schema внутри, поэтому этот ответ дает те же данные, что и ответ от Alnitak выше. И ajacian81 верен - он не работает для механизма хранения по умолчанию MySQL, InnoDB.
Билл Карвин
56

Я удивлен, что никто не предложил отслеживать время последнего обновления в строке:

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;

Это обновляет метку времени, даже если мы не упомянули об этом в ОБНОВЛЕНИИ.

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 |
+---------------------+

Следует признать, что для этого требуется больше памяти (4 байта на строку для TIMESTAMP).
Но это работает для таблиц InnoDB до версии 5.7.15 MySQL, которая INFORMATION_SCHEMA.TABLES.UPDATE_TIMEне.

Билл Карвин
источник
10
+1 Насколько я понимаю, это единственный правильный ответ на этот вопрос. Вопрос действительно хочет знать, когда обновляются соответствующие данные, а не когда таблица (которая не имеет отношения к пользователю) может быть изменена или не изменена по какой-либо причине.
Сирида
23
Но если вы удалите запись с меньшим временем обновления, MAX (updated_at) не будет работать.
Аммамон
3
@ Ammamon, правда, если вам также необходимо учитывать удаления, это решение не отражает это. Триггер для обновления сводной таблицы может быть единственным комплексным решением, но это может создать узкое место.
Билл Карвин
2
в большинстве случаев знание удаления не было бы таким же актуальным, и многие высокоуровневые aps действительно не удаляют из многих таблиц, а просто снимают флаг для эквивалента.
Сэмюэл Фулман
1
@ Паван, разницы нет, вы просто полагаетесь на поведение по умолчанию, и в моем примере эта опция четко прописана. Но опция идентична поведению по умолчанию.
Билл Карвин
13

Простейшей вещью было бы проверить временную метку файлов таблицы на диске. Например, вы можете проверить в вашем каталоге данных

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

Это должно дать вам список всех таблиц с таблицей, когда она последний раз изменялась в самый старый раз.

user2654744
источник
Действительно хороший ответ, так как UPDATE_TIME равен NULL для всех таблиц в моем случае (MariaDb)
Александр Васильев
ibd файлы хранят только структуру таблицы. По умолчанию данные хранятся в ibdata1, поэтому временная метка файла ibd не будет обновляться при изменении данных в таблице. https://dev.mysql.com/doc/refman/8.0/en/show-table-status.html
Переполнение стека
@StackUnderflow, то, что вы сказали, не является точным. В файлах ibd хранятся данные и индексы для табличного пространства, которое содержит одну или несколько таблиц. Если данные хранятся в ibdata1, там не будет файла ibd. Хранение данных в одном файле для каждой таблицы было по умолчанию с MySQL 5.6 в 2013 году.
Билл Карвин
7

Для получения списка последних изменений таблицы используйте это:

SELECT UPDATE_TIME, TABLE_SCHEMA, TABLE_NAME
FROM information_schema.tables
ORDER BY UPDATE_TIME DESC, TABLE_SCHEMA, TABLE_NAME
Франсуа Буржуа
источник
3
Почему все мои UPDATE_TIMEнулевые? Любая идея?
Метафаниель
5
Ваш UPDATE_TIME является нулевым, потому что вы используете InnoDB вместо MyISAM. InnoDB, как правило, лучший выбор, но он не поддерживает UPDATE_TIME.
Xaraxia
5

Я бы создал триггер, который ловит все обновления / вставки / удаления и записывает метку времени в пользовательскую таблицу, что-то вроде tablename | отметка времени

Просто потому, что мне не нравится идея читать внутренние системные таблицы сервера БД напрямую

Михаил
источник
1
Это похоже на хорошее решение для MS SQL, потому что нет UPDATE_TIMEколонки, как в MySQL.
Дарси
3

Хотя есть принятый ответ, я не чувствую, что он правильный. Это самый простой способ достичь того, что нужно, но даже если он уже включен в InnoDB (на самом деле документы говорят вам, что вы все равно должны получить NULL ...), если вы читаете документы MySQL , даже в текущей версии (8.0) использование UPDATE_TIME не правильный вариант, потому что:

Метки времени не сохраняются при перезапуске сервера или при удалении таблицы из кэша словаря данных InnoDB.

Если я правильно понимаю (не могу проверить это на сервере прямо сейчас), метка времени сбрасывается после перезапуска сервера.

Что же касается реальных (и, ну, дорогих) решений, у вас есть Билл Karwin в решении с CURRENT_TIMESTAMP , и я хотел бы предложить другую, которая основана на триггерах (я использую это один).

Вы начинаете с создания отдельной таблицы (или, может быть, у вас есть какая-то другая таблица, которая может быть использована для этой цели), которая будет работать как хранилище для глобальных переменных (здесь отметки времени). Вам нужно сохранить два поля - имя таблицы (или любое другое значение, которое вы хотите сохранить здесь в качестве идентификатора таблицы) и метку времени. После того, как он у вас есть, вы должны инициализировать его с этим идентификатором таблицы + дата начала (NOW () - хороший выбор :)).

Теперь вы перемещаетесь в таблицы, которые хотите наблюдать, и добавляете триггеры ПОСЛЕ ВСТАВКИ / ОБНОВЛЕНИЯ / УДАЛЕНИЯ с помощью этой или аналогичной процедуры:

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
выглядит как очень непереносимый хак, стандартный способ, который работал бы везде, был бы лучше
Tejesh Alimilli
0

Если вы работаете в Linux, вы можете использовать inotify для просмотра таблицы или каталога базы данных. inotify доступен из PHP, node.js, perl и я подозреваю большинство других языков. Конечно, вы должны были установить inotify или ваш провайдер установил его. Много провайдеров не будет.

bartonlp
источник
2
Проверки файловой системы бесполезны, если ваша база данных работает на отдельном сервере
Сэм Дюфель
0

Не уверен, что это будет интересно. Использование mysqlproxy между mysql и клиентами и использование сценария lua для обновления значения ключа в memcached в соответствии с интересными изменениями в таблице UPDATE, DELETE, INSERT было решением, которое я сделал совсем недавно. Если оболочка поддерживает хуки или триггеры в php, это может быть eaiser. Ни одна из обёрток на данный момент не делает этого.

Джиджу Томас Мэтью
источник
0

я сделал столбец по имени: update-at в phpMyAdmin и получил текущее время от метода Date () в моем коде (nodejs). при каждом изменении таблицы в этом столбце хранится время изменений.

Saeed
источник
1
Добро пожаловать в StackOverflow! Пожалуйста, измените свой ответ, включив в него часть кода, который вы использовали, а также объяснение, почему вы решили сделать это таким образом. Этому вопросу почти одиннадцать лет , и у него уже есть принятый, хорошо проголосованный ответ. Ваш ответ без какого-либо кода или объяснения, скорее всего, будет опущен или удален. Редактирование, чтобы включить эти вещи, поможет оправдать свое место в этом посте.
Das_Geek
0

а) он покажет вам все таблицы и там даты последнего обновления

SHOW TABLE STATUS FROM db_name;

затем вы можете запросить конкретную таблицу:

SHOW TABLE STATUS FROM db_name like 'table_name';

б) Как и в приведенных выше примерах, вы не можете использовать сортировку по «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';
justnajm
источник
-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> устарел.
Сирида
-9

Кэшируйте запрос в глобальной переменной, когда он недоступен.

Создайте веб-страницу для принудительной перезагрузки кэша при его обновлении.

Добавьте вызов на страницу перезагрузки в ваши сценарии развертывания.

Kieveli
источник
2
Вы не можете «кэшировать» переменные между независимыми вызовами страницы PHP без посторонней помощи.
Альнитак