PostgreSQL veritabanı tablosunun son değişiklik tarihi


35

Masamın, bu cevapta açıklandığı şekilde dosya değiştirme tarihini kontrol ederek değiştirildiği zamanı almaya çalışıyorum . Ancak sonuç her zaman doğru değildir. Masamı güncelledikten sonra birkaç dakika içerisinde dosya değiştirme tarihi güncelleniyor. Doğru davranış mı? PostgreSQL tablo değişikliklerini bazı önbellekte saklar ve ardından sabit sürücüye kaydeder mi?

Öyleyse, bir tablonun doğru son değişiklik tarihini nasıl alabilirim (otomatik vakum değişikliklerinin de iyi olduğunu varsayalım)?

Linux Centos 6.2 x64 altında PostgreSQL 9.2 kullanıyorum.


4
Dosya değiştirme zamanının güvenilir olduğunu sanmıyorum. Otovakuum nedeniyle de değişebilir. Tek güvenilir yol, bir tetikleyici tarafından tutulan bir değişiklik zaman damgasını tablonuzda saklamaktır.
a_horse_with_no_name

Bir fikir, WAL dosyalarında saklanan bilgilerin, işlemden bir süre sonra (daha kısa veya daha uzun) veri dosyalarına yazılmasıdır. İsterseniz, buna bir önbellek diyebilirsiniz :) Aksi halde, ben ne @ a_horse_with_no_name dedi.
dezso,

Yanıtlar:


35

Bir tablonun son değiştirilme zamanının güvenilir ve yetkili bir kaydı yoktur. Relfilenode kullanımı birçok nedenden dolayı yanlıştır:

  • Yazma başlangıçta yazma kafası günlüğüne (WAL), ardından tembel olarak yığına (tablo dosyaları) kaydedilir. Kayıt WAL'a girdiğinde, Pg yığına yazmak için acele etmez ve bir sonraki sistem kontrol noktasına kadar yazılmayabilir;

  • Daha büyük tablolarda birden fazla çatal bulunur, tüm çatalları kontrol etmeniz ve en yeni zaman damgasını seçmeniz gerekir;

  • Bir basit SELECTipucu-bit ayarı nedeniyle alttaki tabloya yazma etkinliği üretebilir;

  • autovaccum ve kullanıcının görünür verilerini değiştirmeyen diğer bakımlar hala ilişki dosyalarını değiştirir;

  • Gibi bazı işlemler vaccum fullrelfilenode yerini alacak. Uygun bir kilit almadan aynı anda bakmaya çalışıyorsanız, beklediğiniz yerde olmayabilir.

Birkaç seçenek

Güvenilirliğe ihtiyacınız yoksa, pg_stat_databaseve içindeki bilgileri potansiyel olarak kullanabilirsiniz pg_stat_all_tables. Bunlar, son istatistiklerin sıfırlanmasının zamanını ve son istatistiklerin sıfırlanmasından bu yana etkinlik istatistiklerini verebilir . En son etkinliğin ne zaman olduğunu, yalnızca son istatistiklerin sıfırlanmasından bu yana olduğunu söylemez ve bu istatistiklerin sıfırlanmasından önce ne olduğu hakkında hiçbir bilgi yoktur. Bu yüzden sınırlı, ama zaten orada.

Güvenilir bir şekilde yapmak için bir seçenek, her bir tablo için en son değiştirilen süreleri içeren bir tabloyu güncellemek için bir tetikleyici kullanmaktır. Bunu yapmanın , tüm yazıları masaya serileştirip eşzamanlılığı yok edeceğini unutmayın . Ayrıca, her işlem için bir miktar ek yük ekler. Tavsiye etmiyorum.

Biraz daha az kötü alternatif kullanmaktır LISTENve NOTIFY. PostgreSQL'e ve LISTENetkinlikler için harici bir daemon sürecinin bağlanmasını sağlayın . Bir tablo değiştiğinde tabloları bildirmek ON INSERT OR UPDATE OR DELETEiçin tetikleyicileri kullanın NOTIFY; tablo, bildirim yükü olarak verilir. İşlem tamamlandığında bunlar gönderilir. Arka planınız değişiklik bildirimleri toplayabilir ve bunları tembel olarak veritabanındaki bir tabloya geri yazabilir. Sistem çökerse, en son değişikliklerin kaydını kaybedersiniz, ancak sorun değil, yalnızca bir çökmeden sonra başlarsanız tüm tabloları değiştirilmiş olarak kabul edersiniz.

Eşzamanlılık sorunlarının en kötüsünü önlemek için, bunun yerine bir before insert or update or delete or truncate on tablename for each statement executeilişki parametresi olarak almak üzere genelleştirilmiş bir tetikleyici kullanarak değişiklik zaman damgalarını günlüğe kaydedebilirsiniz . Bu, (relation_oid, timestamp)bir değişiklik günlüğü tablosuna bir çift ekler . Daha sonra ayrı bir bağlantıda veya uygulamanız tarafından periyodik olarak adlandırılan bir yardımcı işlem görürsünüz, bu tabloyu en son bilgiler için toplar, en son değişikliklerin bir özet tablosunda birleştirir ve günlük tablosunu kesersiniz. Bunun dinleme / bildirim yaklaşımına göre tek avantajı kaza ile ilgili bilgileri kaybetmemesidir - ancak bu daha az verimlidir.

Diğer bir yaklaşım, bir C uzatma işlevi yazmak olabileceğini kullandığı (örn) ProcessUtility_hook, ExecutorRun_hooktuzak masa değişiklikleri ve tembel güncelleme istatistiklerine vb. Bunun ne kadar pratik olacağını görmedim; Kaynaklardaki çeşitli _hook seçeneklerine bir göz atın.

Bu bilgiyi kaydetmek için istatistik kodunu yamalamak ve çekirdeğe dahil edilmek üzere PostgreSQL'e bir yama göndermek en iyi yoldur. Sadece kod yazarak başlamayın; Bunu yapmak için iyi tanımlanmış bir yol için yeterli olduğunu düşündüğünüzde, bilgisayar korsanlarına dair fikrinizi yükseltin (örneğin, kodu okuyarak başlayın, sadece "nasıl yaparım ..." diye soran göndermeyin). Adresine en son güncellenen süreleri eklemek güzel olabilir pg_stat_..., ancak toplumu genel giderlere değdiğine ikna etmeniz veya isteğe bağlı olarak izlenmesi için bir yol sağlamanız gerekir - istatistikleri korumak için kodu da yazmanız gerekir. Bir düzeltme eki gönder , çünkü yalnızca bu özelliği isteyen biri bununla uğraşacak.

Nasıl yaparım

Bunu yapmak zorunda olsaydım ve düzgün bir şekilde yapmak için bir yama yazmak için vaktim olmadıysa, muhtemelen yukarıda belirtilen dinleme / bildirim yaklaşımını kullanırdım.

PostgreSQL 9.5 güncelleme zaman damgası güncellemesi

Güncelleme : PostgreSQL 9.5'in zaman damgaları var . Eğer varsa onları etkinleştirilmiş postgresql.conf, sen en ile satır için zaman damgası işlemek kontrol edebilirsiniz (ve de geçmişte öyle yaptım) xminiçin tahmin son değiştirilme zamanı. Bu sadece bir yaklaşım çünkü en son satırlar silindiyse sayılmayacak.

Ayrıca, kesin zaman damgası kayıtları yalnızca sınırlı bir süre için saklanır. Bu nedenle, çok fazla değiştirilmemiş bir masanın ne zaman değiştirildiğini anlatmak istiyorsanız, cevap etkili bir şekilde "bir süre önce" dunno olacaktır.


17

PostgreSQL 9.5, son değiştirilen işlemi izlememize izin verir.

  1. Aşağıdaki sorgu kullanılarak iz takibinin açık olup olmadığını kontrol edin

    show track_commit_timestamp;
  2. Eğer "ON" döndürürse 3. adıma gidin, postgresql.conf dosyasını değiştirin

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

    Değişiklik

    track_commit_timestamp = off

    için

    track_commit_timestamp = on

    Sistemi yeniden başlat

    1. adımı tekrarlayın.

  3. Son işlemi izlemek için aşağıdaki sorguyu kullanın

    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. adımda sistemi yeniden başlatmanız gerekmez. İşlemi yeniden başlatmanız yeterlidir. örn sudo service postgresql restart.
ijoseph

3

Evet, bu davranması beklenebilir - değişiklikle ilgili veriler hemen işlem günlüğüne kaydedilir. Veri dosyaları checkpoint_timeout gecikmesi ile güncellenebilir (varsayılan 5 dakikadır). Postgres, istediğiniz herhangi bir zamanda kalıcı olarak kalmaz.


Bunun soruyu nasıl cevapladığını anladığımdan emin değilim. Evet, veri işlem günlüğüne saklanır, ama bu bir (kolayca belirli bir tablo için bir modifikasyon süresi alabilirsiniz anlamına gelmez eğer bu içerik günlüğünü ayrıştırabilir günlük birinde hala, ama işler yerine dışarı tekrarlattırılır olsun hızlı bir şekilde).
Charles Duffy

Elbette, gerekli tüm bilgileri logdan alabilirsiniz, ancak sorular veri dosyalarının tam zamanıdır - veri dosyalarının gerçekleştirilmesi oldukça rastgele olabilir - birkaç saniye - işlemden sonra birkaç dakika (en fazla 1 saat).
Pavel Stehule

OP'nin kendi girişimi dosyalara bakmaktı , ancak asıl amaçları açıkça masa saati bulmaktı. Ama evet, buradan nereden geldiğini anlıyorum (neden yaptıklarını açıklamadı).
Charles Duffy

2

İstemci uygulamasında bazı tabloların önbelleğini korumak için neredeyse aynı gereksinim var . Neredeyse söylüyorum , çünkü son değişikliğin zamanını gerçekten bilmek zorunda değilim, ancak yalnızca önbelleğin en son senkronize edildiğinden bu yana bir şeylerin değişip değişmediğini tespit etmek için.

İşte benim yaklaşımım:

Her tabloda bir id(PK), created_on(ekleme zaman damgası) ve updated_on(güncelleme zaman damgası, NULL olabilir) sütunu varsa,

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

Bunu birleştirip satır sayısını hazırlarsanız, benzeyen bir sürüm etiketi oluşturabilirsiniz count:id#timestampve bu tablodaki verilerin her sürümü için benzersiz olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.