Mendapatkan tanggal modifikasi terakhir dari tabel database PostgreSQL

35

Saya mencoba untuk mendapatkan ketika tabel saya dimodifikasi dengan memeriksa tanggal modifikasi file seperti yang dijelaskan dalam jawaban ini . Tetapi hasilnya tidak selalu benar. Tanggal modifikasi file diperbarui dalam beberapa menit setelah saya memperbarui tabel saya. Apakah itu perilaku yang benar? Apakah PostgreSQL menyimpan modifikasi tabel dalam beberapa cache dan kemudian memindahkannya ke hard drive?

Jadi, bagaimana saya mendapatkan tanggal modifikasi terakhir yang benar dari sebuah tabel (mari kita asumsikan bahwa modifikasi vakum otomatis juga ok)?

Saya menggunakan PostgreSQL 9.2 di Linux Centos 6.2 x64.

gulungan
sumber
4
Saya rasa waktu modifikasi file tidak dapat diandalkan. Bisa juga berubah karena autovacuum. Satu-satunya cara yang dapat diandalkan adalah dengan menyimpan cap waktu modifikasi di meja Anda, dikelola oleh pemicu.
a_horse_with_no_name
Satu ide adalah bahwa informasi yang disimpan dalam file WAL ditulis ke file data beberapa waktu (lebih pendek atau lebih lama) setelah melakukan transaksi. Jika mau, Anda bisa menyebutnya sebagai cache :) Jika tidak, saya akan mengatakan apa yang dikatakan @a_horse_with_no_name.
dezso

Jawaban:

35

Tidak ada catatan yang dapat diandalkan dan otoritatif dari waktu tabel yang dimodifikasi terakhir. Menggunakan relfilenode salah karena banyak alasan:

  • Menulis awalnya dicatat ke log kepala-tulis (WAL), kemudian malas ke tumpukan (file tabel). Setelah catatan di WAL, Pg tidak terburu-buru untuk menulisnya ke heap, dan bahkan mungkin tidak ditulis sampai pos pemeriksaan sistem berikutnya;

  • Tabel yang lebih besar memiliki beberapa garpu, Anda harus memeriksa semua garpu dan memilih cap waktu terbaru;

  • Sederhana SELECTdapat menghasilkan aktivitas menulis ke tabel di bawahnya karena pengaturan hint-bit;

  • autovaccum dan pemeliharaan lain yang tidak mengubah data yang terlihat pengguna masih memodifikasi file relasi;

  • beberapa operasi, seperti vaccum full, akan menggantikan relfilenode. Mungkin tidak di tempat yang Anda harapkan jika Anda mencoba melihatnya bersamaan tanpa mengambil kunci yang sesuai.

Beberapa pilihan

Jika Anda tidak memerlukan keandalan, Anda dapat berpotensi menggunakan informasi dalam pg_stat_databasedan pg_stat_all_tables. Ini dapat memberi Anda waktu reset statistik terakhir, dan statistik aktivitas sejak statistik terakhir direset. Itu tidak memberi tahu Anda ketika aktivitas terbaru adalah, hanya itu sejak statistik terakhir di-reset, dan tidak ada informasi tentang apa yang terjadi sebelum statistik itu di-reset. Jadi itu terbatas, tetapi sudah ada di sana.

Salah satu opsi untuk melakukannya dengan andal adalah menggunakan pemicu untuk memperbarui tabel yang berisi waktu terakhir yang dimodifikasi untuk setiap tabel. Ketahuilah bahwa melakukan hal itu akan membuat serial semua tulisan ke meja , menghancurkan konkurensi. Itu juga akan menambahkan sedikit overhead yang adil untuk setiap transaksi. Saya tidak merekomendasikannya.

Alternatif yang sedikit kurang mengerikan adalah menggunakan LISTENdan NOTIFY. Minta proses daemon eksternal terhubung ke PostgreSQL dan LISTENuntuk acara. Gunakan ON INSERT OR UPDATE OR DELETEpemicu untuk mengirim NOTIFYketika tabel berubah, dengan tabel yang ditampilkan sebagai pemberitahuan muatan. Ini dikirim ketika transaksi dilakukan. Daemon Anda dapat mengakumulasikan notifikasi perubahan dan dengan malas menulisnya kembali ke tabel di database. Jika sistem macet, Anda kehilangan catatan modifikasi terbaru, tapi tidak apa-apa, Anda hanya memperlakukan semua tabel sebagai hanya dimodifikasi jika Anda memulai setelah crash.

Untuk menghindari masalah konkurensi yang paling buruk, Anda bisa mencatat perubahan cap waktu menggunakan before insert or update or delete or truncate on tablename for each statement executepemicu, digeneralisasi untuk mengambil relasi oid sebagai parameter. Ini akan menyisipkan (relation_oid, timestamp)pasangan ke dalam tabel logging perubahan. Anda kemudian memiliki proses bantuan pada koneksi terpisah, atau dipanggil secara berkala oleh aplikasi Anda, mengagregasi tabel itu untuk info terbaru, menggabungkannya ke dalam tabel ringkasan perubahan terbaru, dan memotong tabel log. Satu-satunya keuntungan dari ini daripada pendekatan mendengarkan / memberi tahu adalah tidak kehilangan informasi saat macet - tetapi itu juga kurang efisien.

Pendekatan lain mungkin untuk menulis fungsi C ekstensi yang menggunakan (misalnya) ProcessUtility_hook, ExecutorRun_hook, dll untuk perubahan meja menjebak dan malas memperbarui statistik. Saya belum melihat bagaimana praktisnya ini; lihat berbagai opsi _hook di sumber.

Cara terbaik adalah dengan menambal kode statistik untuk merekam informasi ini dan mengirimkan tambalan ke PostgreSQL untuk dimasukkan dalam inti. Jangan hanya mulai dengan menulis kode; tingkatkan ide Anda pada -hackers setelah Anda cukup memikirkannya untuk memiliki cara yang jelas untuk melakukannya (yaitu mulai dengan membaca kode, jangan hanya memposting bertanya "bagaimana saya ..."). Mungkin menyenangkan untuk menambahkan waktu yang terakhir diperbarui pg_stat_..., tetapi Anda harus meyakinkan komunitas bahwa itu sepadan dengan biaya overhead atau menyediakan cara untuk membuatnya dilacak secara opsional - dan Anda harus menulis kode untuk menjaga statistik dan kirimkan tambalan , karena hanya seseorang yang menginginkan fitur ini yang akan repot dengan itu.

Bagaimana saya melakukannya

Jika saya harus melakukan ini, dan tidak punya waktu untuk menulis tambalan untuk melakukannya dengan benar, saya mungkin akan menggunakan pendekatan mendengarkan / memberitahukan yang diuraikan di atas.

Pembaruan untuk cap waktu komitmen PostgreSQL 9.5

Pembaruan : PostgreSQL 9.5 memiliki cap waktu komit . Jika Anda mengaktifkannya di postgresql.conf(dan melakukannya di masa lalu juga), Anda dapat memeriksa stempel waktu komit untuk baris dengan yang terbesar xminuntuk memperkirakan waktu modifikasi terakhir. Ini hanya perkiraan karena jika baris terbaru telah dihapus mereka tidak akan dihitung.

Juga, catatan catatan waktu komit hanya disimpan untuk waktu yang terbatas. Jadi jika Anda ingin mengetahui kapan sebuah tabel yang tidak dimodifikasi banyak dimodifikasi, jawabannya secara efektif akan "tak tahu, beberapa saat yang lalu".

Craig Ringer
sumber
17

PostgreSQL 9.5 mari kita lacak komit terakhir yang dimodifikasi.

  1. Periksa komit trek aktif atau nonaktif menggunakan kueri berikut

    show track_commit_timestamp;
  2. Jika kembali "ON" lanjutkan ke langkah 3 lain memodifikasi postgresql.conf

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

    Perubahan

    track_commit_timestamp = off

    untuk

    track_commit_timestamp = on

    Mulai ulang sistem

    Ulangi langkah 1.

  3. Gunakan kueri berikut untuk melacak komit terakhir

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;
Thirumal
sumber
1
Anda tidak perlu me-reboot sistem pada langkah 2. cukup restart prosesnya. mis sudo service postgresql restart.
ijoseph
3

Ya, ini bisa diharapkan berperilaku - data tentang perubahan disimpan ke log transaksi segera. File data dapat diperbarui dengan penundaan checkpoint_timeout (standarnya adalah 5 menit). Postgres tidak tahan secara permanen kapan pun Anda minta.

Pavel Stehule
sumber
Saya tidak yakin saya mengerti bagaimana ini menjawab pertanyaan. Ya, data disimpan ke log transaksi, tetapi itu tidak berarti bahwa seseorang bisa mendapatkan waktu modifikasi untuk tabel tertentu dengan mudah ( jika konten itu masih dalam log, ia dapat mengurai log, tetapi hal-hal yang diputar ulang bukan segera).
Charles Duffy
yakin, Anda bisa mendapatkan semua informasi yang diperlukan dari log, tetapi pertanyaannya diarahkan ke waktu datafile - aktualisasi file data bisa sangat acak - beberapa detik - beberapa menit (maks 1 jam) setelah komit.
Pavel Stehule
Upaya OP sendiri adalah melalui melihat file, tetapi maksud sebenarnya mereka jelas untuk mendapatkan tabel mtime. Tapi ya, saya mengerti dari mana Anda datang dari sini (menjelaskan mengapa apa yang mereka lakukan tidak berhasil) sekarang.
Charles Duffy
2

Saya memiliki persyaratan yang hampir sama untuk menjaga cache dari beberapa tabel pada aplikasi klien. Saya katakan hampir , karena saya tidak benar-benar perlu tahu waktu modifikasi terakhir, tetapi hanya untuk mendeteksi jika ada sesuatu yang berubah sejak terakhir kali cache disinkronkan.

Inilah pendekatan saya:

Asalkan Anda memiliki kolom id(PK), created_on(timestamp penyisipan) dan updated_on(memperbarui timestamp, mungkin NULL) pada setiap tabel, Anda dapat

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

Jika Anda menyatukan ini dan menambahkan jumlah baris, Anda bisa membuat tag versi yang terlihat count:id#timestamp, dan itu akan unik untuk setiap versi data dalam tabel.

laurent
sumber