Я пытаюсь узнать, когда моя таблица была изменена, проверив дату изменения файла, как описано в этом ответе . Но результат не всегда правильный. Дата изменения файла обновляется через несколько минут после обновления таблицы. Это правильное поведение? Сохраняет ли PostgreSQL модификации таблиц в некотором кеше, а затем записывает их на жесткий диск?
Итак, как мне получить правильную дату последней модификации таблицы (давайте предположим, что автоматические вакуумные модификации тоже подходят)?
Я использую PostgreSQL 9.2 под Linux Centos 6.2 x64.
postgresql
моток
источник
источник
Ответы:
Не существует надежной, авторской записи последнего измененного времени таблицы. Использование relfilenode неправильно по многим причинам:
Записи сначала записываются в журнал головки записи (WAL), затем лениво в кучу (файлы таблиц). Когда запись находится в WAL, Pg не спешит записывать ее в кучу, и она может даже не записаться до следующей системной контрольной точки;
Большие столы имеют несколько вилок, вам нужно будет проверить все вилки и выбрать новейшую временную метку;
Простой
SELECT
может генерировать операции записи в базовую таблицу из-за установки подсказки;autovaccum и другое обслуживание, которое не изменяет видимые пользователю данные, все еще изменяет файлы отношения;
некоторые операции, например
vaccum full
, заменят relfilenode. Это может быть не там, где вы ожидаете, если вы пытаетесь смотреть на него одновременно, не взяв соответствующую блокировку.Несколько вариантов
Если вам не нужна надежность, вы можете использовать информацию в
pg_stat_database
иpg_stat_all_tables
. Они могут дать вам время последнего сброса статистики и статистику активности с момента последнего сброса статистики. Он не сообщает вам, когда было последнее действие, только то, что это было с момента последнего сброса статистики, и нет никакой информации о том, что произошло до сброса этой статистики. Так что это ограничено, но это уже там.Один из способов сделать это надежно - использовать триггер для обновления таблицы, содержащей время последнего изменения для каждой таблицы. Имейте в виду , что при этом будут сериализованы все записи в таблицу , что разрушит параллелизм. Это также добавит немало накладных расходов к каждой транзакции. Я не рекомендую это.
Немного менее ужасной альтернативой является использование
LISTEN
иNOTIFY
. Подключите внешний процесс-демон к PostgreSQL иLISTEN
для событий. ИспользуйтеON INSERT OR UPDATE OR DELETE
триггеры для отправкиNOTIFY
s при изменении таблицы с таблицей oid в качестве полезной нагрузки notify. Они отправляются при фиксации транзакции. Ваш демон может накапливать уведомления об изменениях и лениво записывать их обратно в таблицу в базе данных. Если происходит сбой системы, вы теряете записи о последних изменениях, но это нормально, вы просто рассматриваете все таблицы как только что измененные, если запускаете после сбоя.Чтобы избежать худшего из проблем параллелизма, вы могли бы вместо этого регистрировать временные метки изменения, используя
before insert or update or delete or truncate on tablename for each statement execute
триггер, обобщенный, чтобы принять отношение oid в качестве параметра. Это добавит(relation_oid, timestamp)
пару в таблицу регистрации изменений. Затем у вас есть вспомогательный процесс на отдельном соединении или периодически вызываемый вашим приложением, объединяющий эту таблицу для получения последней информации, объединяющий ее в сводную таблицу самых последних изменений и усекающую таблицу журнала. Единственное преимущество этого подхода по сравнению с прослушиванием / уведомлением состоит в том, что он не теряет информацию о сбое - но он еще менее эффективен.Другой подход может написать функцию расширения C , который использует (например)
ProcessUtility_hook
,ExecutorRun_hook
и т.д. , чтобы изменения таблицы ловушки и Лениво статистик обновлений. Я не смотрел, чтобы увидеть, насколько это будет практично; взгляните на различные опции _hook в источниках.Лучшим способом было бы исправить код статистики для записи этой информации и отправить исправление в PostgreSQL для включения в ядро. Не просто начните с написания кода; подними свою идею о хакерах, как только ты подумаешь об этом достаточно, чтобы иметь четко определенный способ сделать это (то есть начать с чтения кода, а не просто публиковать вопрос "как мне ..."). Возможно, было бы неплохо добавить время последнего обновления
pg_stat_...
, но вам нужно будет убедить сообщество в том, что оно того стоило, или предоставить способ сделать его отслеживаемым по желанию - и вам придется написать код, чтобы сохранить статистику и отправить патч , потому что только тот, кто хочет эту функцию, будет беспокоиться об этом.Как бы я это сделал
Если бы мне пришлось это сделать, и у меня не было времени написать патч, чтобы сделать это правильно, я бы, вероятно, использовал подход прослушивания / уведомления, описанный выше.
Обновление для временных отметок фиксации PostgreSQL 9.5
Обновление : PostgreSQL 9.5 имеет временные метки коммитов . Если вы включили их
postgresql.conf
(и делали это в прошлом), вы можете проверить метку времени фиксации для строки с наибольшим,xmin
чтобы приблизить время последнего изменения. Это только приблизительное значение, потому что, если самые последние строки были удалены, они не будут учитываться.Кроме того, записи отметок времени фиксации хранятся только в течение ограниченного времени. Так что, если вы хотите сказать, когда таблица, которая не была сильно изменена, будет изменена, ответ будет «не знаю, давно».
источник
PostgreSQL 9.5 позволяет отслеживать последний измененный коммит.
Проверьте, что фиксация трека включена или выключена с помощью следующего запроса
Если он возвращает «ON», перейдите к шагу 3, иначе измените postgresql.conf
+ Изменить
в
Перезагрузите систему
Повторите шаг 1.
Используйте следующий запрос для отслеживания последнего коммита
источник
sudo service postgresql restart
.Да, такое поведение можно ожидать - данные об изменениях немедленно сохраняются в журнале транзакций. Файлы данных могут быть обновлены с задержкой checkpoint_timeout (по умолчанию 5 минут). Postgres не хранится постоянно в любое время, когда вы запрашиваете.
источник
У меня почти такое же требование, чтобы поддерживать кеш некоторых таблиц в клиентском приложении. Я говорю почти , потому что мне на самом деле не нужно знать время последней модификации, а нужно лишь определить, изменилось ли что-то с момента последней синхронизации кеша.
Вот мой подход:
При условии, что в каждой таблице есть столбцы
id
(PK),created_on
(отметка времени вставки) иupdated_on
(отметка времени обновления, может быть NULL), вы можетеЕсли вы сопоставите это и добавите число строк, вы можете создать тег версии, который будет выглядеть так
count:id#timestamp
, и он будет уникальным для каждой версии данных в таблице.источник