Próbuję się dowiedzieć, kiedy moja tabela została zmodyfikowana, sprawdzając datę modyfikacji pliku, jak opisano w tej odpowiedzi . Ale wynik nie zawsze jest poprawny. Data modyfikacji pliku aktualizuje się w kilka minut po aktualizacji mojej tabeli. Czy to jest prawidłowe zachowanie? Czy PostgreSQL przechowuje modyfikacje tabeli w jakiejś pamięci podręcznej, a następnie opróżnia ją na dysk twardy?
Jak więc uzyskać poprawną datę ostatniej modyfikacji tabeli (załóżmy, że automatyczne modyfikacje próżni też są w porządku)?
Używam PostgreSQL 9.2 pod Linux Centos 6.2 x64.
postgresql
motek
źródło
źródło
Odpowiedzi:
Nie ma wiarygodnego, autorytatywnego zapisu czasu ostatniej modyfikacji tabeli. Korzystanie z relfilenode jest nieprawidłowe z wielu powodów:
Zapisy są początkowo zapisywane w dzienniku głowicy zapisu (WAL), a następnie leniwie na stosie (pliki tabel). Gdy rekord znajduje się w WAL, Pg nie spieszy się z zapisaniem go na stercie i może nawet nie zostać zapisany do następnego punktu kontrolnego systemu;
Większe tabele mają wiele widelców, należy sprawdzić wszystkie widelce i wybrać najnowszy znacznik czasu;
Prosty
SELECT
może generować działanie zapisu do podstawowej tabeli ze względu na ustawienie bitu podpowiedzi;autovaccum i inna konserwacja, która nie zmienia widocznych danych użytkownika, nadal modyfikuje pliki relacji;
niektóre operacje, na przykład
vaccum full
, zastąpią relfilenode. To może nie być to, czego oczekujesz, jeśli próbujesz spojrzeć na to jednocześnie bez odpowiedniej blokady.Kilka opcji
Jeśli nie potrzebujesz niezawodności, możesz potencjalnie wykorzystać informacje w
pg_stat_database
ipg_stat_all_tables
. Mogą dać ci czas ostatniego resetu statystyk oraz statystyki aktywności od czasu ostatniego resetowania statystyk. Nie mówi ci, kiedy była ostatnia aktywność, tyle że od ostatniego resetu statystyk i nie ma informacji o tym, co się stało przed zresetowaniem statystyk. Więc jest ograniczony, ale już tam jest.Jedną z opcji niezawodnego działania jest użycie wyzwalacza do aktualizacji tabeli zawierającej czasy ostatniej modyfikacji dla każdej tabeli. Pamiętaj, że spowoduje to szeregowanie wszystkich zapisów do tabeli , niszcząc współbieżność. Doda to również sporo kosztów ogólnych do każdej transakcji. Nie polecam tego
Nieco mniej okropną alternatywą jest użycie
LISTEN
iNOTIFY
. Niech zewnętrzny proces demona połączy się z PostgreSQL iLISTEN
dla zdarzeń. UżyjON INSERT OR UPDATE OR DELETE
wyzwalaczy, aby wysłaćNOTIFY
s, gdy zmienia się tabela, z oid tabeli jako ładunkiem powiadomienia. Są one wysyłane po zatwierdzeniu transakcji. Twój demon może gromadzić powiadomienia o zmianach i leniwie zapisywać je z powrotem do tabeli w bazie danych. Jeśli system ulegnie awarii, stracisz rejestr ostatnich modyfikacji, ale to jest ok, traktujesz wszystkie tabele jako właśnie zmodyfikowane, jeśli zaczynasz po awarii.Aby uniknąć najgorszych problemów z współbieżnością, zamiast tego można rejestrować znaczniki czasu zmiany za pomocą
before insert or update or delete or truncate on tablename for each statement execute
wyzwalacza, uogólnionego w celu uwzględnienia oid relacji jako parametru. Spowodowałoby to wstawienie(relation_oid, timestamp)
pary do tabeli rejestrowania zmian. Następnie masz proces pomocniczy na oddzielnym połączeniu lub wywoływany okresowo przez aplikację, agregujesz tę tabelę, aby uzyskać najnowsze informacje, scalasz ją z tabelą podsumowań najnowszych zmian i obcinasz tabelę dziennika. Jedyną zaletą tego rozwiązania w porównaniu z metodą nasłuchiwania / powiadamiania jest to, że nie traci informacji w przypadku awarii - ale jest jeszcze mniej wydajny.Innym rozwiązaniem może być napisać funkcję przedłużacza C, który używa (np)
ProcessUtility_hook
,ExecutorRun_hook
itp do zmian stołowych pułapkę i leniwie statystykach aktualizacji. Nie zastanawiałem się, czy byłoby to praktyczne; spójrz na różne opcje _hook w źródłach.Najlepszym sposobem byłoby załatanie kodu statystycznego, aby zapisać te informacje i przesłać łatkę do PostgreSQL w celu włączenia do rdzenia. Nie zaczynaj od pisania kodu; podnieś swój pomysł na -hakerów, gdy tylko pomyślisz o tym wystarczająco, aby mieć dobrze zdefiniowany sposób na zrobienie tego (tj. zacznij od przeczytania kodu, nie po prostu pytaj „jak mam ...”). Przydałoby się dodać czasy ostatniej aktualizacji
pg_stat_...
, ale musiałbyś przekonać społeczność, że warto było to narzucić, lub podać sposób opcjonalnego śledzenia - i musiałbyś napisać kod, aby zachować statystyki i prześlij łatkę , ponieważ tylko ktoś, kto chce tej funkcji, będzie się tym przejmował.Jak bym to zrobił
Gdybym musiał to zrobić i nie miałbym czasu, aby napisać łatkę, aby zrobić to poprawnie, prawdopodobnie skorzystałbym z metody słuchania / powiadamiania opisanej powyżej.
Aktualizacja znaczników czasu zatwierdzania PostgreSQL 9.5
Aktualizacja : PostgreSQL 9.5 ma znaczniki czasu zatwierdzenia . Jeśli masz je włączone w
postgresql.conf
(i robiłeś to również w przeszłości), możesz sprawdzić znacznik czasu zatwierdzenia dla wiersza z największym,xmin
aby przybliżać czas ostatniej modyfikacji. Jest to tylko przybliżenie, ponieważ jeśli najnowsze wiersze zostaną usunięte, nie zostaną zliczone.Ponadto zapisy datownika zatwierdzenia są przechowywane tylko przez ograniczony czas. Więc jeśli chcesz powiedzieć, kiedy tabela, która nie jest dużo zmodyfikowana, jest zmodyfikowana, odpowiedź będzie brzmiała „nie wiem, jakiś czas temu”.
źródło
PostgreSQL 9.5 pozwala nam śledzić ostatnio zmodyfikowane zatwierdzenie.
Sprawdź, czy zatwierdzenie ścieżki jest włączone lub wyłączone przy użyciu następującego zapytania
Jeśli zwróci „ON”, przejdź do kroku 3, w przeciwnym razie zmodyfikuj plik postgresql.conf
Zmiana
do
Uruchom ponownie system
Powtórz krok 1.
Użyj następującego zapytania, aby śledzić ostatnie zatwierdzenie
źródło
sudo service postgresql restart
.Tak, można się tego spodziewać - dane o zmianie są natychmiast zapisywane w dzienniku transakcji. Pliki danych można aktualizować z opóźnieniem checkpoint_timeout (domyślnie 5 minut). Postgres nie utrzymuje się na stałe za każdym razem, gdy o to poprosisz.
źródło
Mam prawie takie same wymagania, aby utrzymać pamięć podręczną niektórych tabel w aplikacji klienckiej. Mówię prawie , ponieważ tak naprawdę nie muszę znać czasu ostatniej modyfikacji, ale tylko po to, aby wykryć, czy coś się zmieniło od czasu ostatniej synchronizacji pamięci podręcznej.
Oto moje podejście:
Pod warunkiem, że masz kolumnę
id
(PK),created_on
(wstawianie znacznika czasu) iupdated_on
(aktualizuj znacznik czasu, może być NULL) w każdej tabeli, możeszJeśli połączysz to i dodasz liczbę wierszy, możesz zbudować znacznik wersji, który będzie wyglądał
count:id#timestamp
i będzie unikalny dla każdej wersji danych w tabeli.źródło