Отримання останньої дати модифікації таблиці баз даних PostgreSQL


35

Я намагаюся дізнатися, коли моя таблиця була змінена, перевіряючи дату зміни файлу, як це описано в цій відповіді . Але результат не завжди правильний. Дата модифікації файлу оновлюється через кілька хвилин після оновлення таблиці. Це правильна поведінка? Чи PostgreSQL зберігає зміни таблиці в кеші, а потім передає їх на жорсткий диск?

Отже, як я можу отримати правильну дату останньої модифікації таблиці (припустимо, що автоматичні зміни вакууму також у порядку)?

Я використовую PostgreSQL 9.2 під Linux Centos 6.2 x64.


4
Я не думаю, що час зміни файлу є надійним. Це також може змінитися через аутовакуум. Єдиний надійний спосіб - збереження часової позначки модифікації у вашій таблиці, що підтримується тригером.
a_horse_with_no_name

Однією з думок було б те, що інформація, що зберігається у файлах WAL, записується у файли даних через деякий (коротший чи довший) час після здійснення транзакції. Якщо ви хочете, ви можете назвати це кешем :) В іншому випадку я дружу те, що сказав @a_horse_with_no_name.
dezso

Відповіді:


35

Немає достовірних, авторських записів останнього зміненого часу таблиці. Використання релфіленода неправильно з багатьох причин:

  • Записи спочатку записуються в журнал запису голови (WAL), потім ліниво кучу (файли таблиці). Після того, як запис знаходиться в WAL, Pg не поспішає записувати його в купу, і він може навіть не записатись до наступної контрольної точки системи;

  • Більші таблиці мають декілька виделок, вам доведеться перевірити всі вилки та вибрати найновішу часову позначку;

  • Простий SELECTможе генерувати активність запису до базової таблиці завдяки налаштуванням бітових підказок;

  • autovaccum та інше обслуговування, яке не змінює видимі для користувача дані, все ще змінює файли відношень;

  • деякі операції, як-от vaccum full, замінять релфіленод. Можливо, ви не будете там, де ви очікуєте, якщо ви намагаєтесь поглянути на це одночасно, не взявши відповідний замок.

Кілька варіантів

Якщо вам не потрібна надійність, ви потенційно можете використовувати інформацію в pg_stat_databaseі pg_stat_all_tables. Вони можуть дати тобі час останнього скидання статистики та статистику активності після останнього скидання статистики. Це не говорить вам про те, коли була остання активність, лише про те, що це було з моменту останнього скидання статистики, і немає інформації про те, що сталося до цього скидання. Так що це обмежено, але воно вже є.

Одним із варіантів надійної роботи є використання тригера для оновлення таблиці, що містить останні змінені часи для кожної таблиці. Будьте в курсі, що це буде серіалізувати всі записи в стіл , знищуючи одночасність. Це також додасть неабиякі накладні витрати до кожної транзакції. Я не рекомендую.

Трохи менш жахливою альтернативою є використання LISTENта NOTIFY. Запропонуйте зовнішній процес демон підключитися до PostgreSQL та LISTENдля подій. Використовуйте ON INSERT OR UPDATE OR DELETEтригери для надсилання NOTIFYs, коли таблиця змінюється, при цьому таблиця є oid як корисне навантаження сповіщення. Вони надсилаються, коли транзакція вчиняється. Ваш демон може накопичувати сповіщення про зміни і ліниво записувати їх назад до таблиці в базі даних. Якщо система виходить з ладу, ви втрачаєте запис останніх модифікацій, але це нормально, ви просто ставитесь до всіх таблиць як щойно змінених, якщо ви запускаєтесь після аварії.

Щоб уникнути найгірших проблем з паралельністю, ви можете замість цього записувати часові позначки змін за допомогою 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для приблизного останнього зміненого часу. Це лише наближення, тому що якщо видалено останні останні рядки, вони не будуть зараховані.

Крім того, записи часових міток фіксації зберігаються лише обмежений час. Отже, якщо ви хочете сказати, коли таблиця, яка не дуже модифікована, модифікована, відповідь фактично буде "давно, час тому".


17

PostgreSQL 9.5 дозволить нам відстежувати останню змінену комітку.

  1. Перевірити чи виконувати фіксацію треку ввімкнено або вимкнено за допомогою наступного запиту

    show track_commit_timestamp;
  2. Якщо він повернеться "ON", перейдіть до кроку 3, інше змініть postgresql.conf

    cd /etc/postgresql/9.5/main/
    vi postgresql.conf

    Зміна

    track_commit_timestamp = off

    до

    track_commit_timestamp = on

    Перезавантажте систему

    Повторіть крок 1.

  3. Використовуйте наступний запит для відстеження останньої фіксації

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;

1
Вам не потрібно перезавантажувати систему на кроці 2. просто перезапустіть процес. напр sudo service postgresql restart.
ijoseph

3

Так, можна очікувати поведінки - дані про зміни зберігаються в журналі транзакцій негайно. Файли даних можна оновлювати із затримкою checkpoint_timeout (за замовчуванням - 5 хвилин). Postgres не зберігається постійно, коли ви запитуєте.


Я не впевнений, що розумію, як це відповідає на питання. Так, дані зберігаються в журналі транзакцій, але це не означає, що можна легко отримати час модифікації для певної таблиці ( якщо цей вміст все ще знаходиться в журналі, можна проаналізувати журнал, але все буде відновлено швидко).
Чарльз Даффі

Звичайно, ви можете отримати всю необхідну інформацію з журналу, але питання були спрямовані на mtime файлів даних - актуалізація файлів даних може бути досить випадковою - кілька секунд - кілька хвилин (максимум 1 годину) після фіксації.
Павло Стехуле

Власна спроба ОП була переглядом файлів, але їх справжній намір явно отримати таблицю mtime. Але так, я розумію, звідки ти йдеш (пояснюючи, чому те, що вони робили, не працювало) зараз.
Чарльз Даффі

2

У мене майже однакова вимога, щоб підтримувати кеш деяких таблиць у клієнтській програмі. Я майже кажу , тому що мені дійсно не потрібно знати час останньої модифікації, а лише виявити, чи щось змінилося з останнього разу, коли кеш синхронізувався.

Ось мій підхід:

Якщо у кожної таблиці є стовпець id(PK), created_on(часова мітка вставки) та updated_on(часова мітка оновлення, може бути NULL), ви можете

SELECT id,greatest(created_on,updated_on) FROM %s ORDER BY greatest(created_on,updated_on) DESC LIMIT 1;

Якщо ви сформулюєте це і додаєте кількість рядків, ви можете створити тег версії, який виглядає так count:id#timestamp, і він буде унікальним для кожної версії даних у таблиці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.