Mungkinkah menyimpan jumlah maksimum catatan di postgresql?

9

Pada dasarnya bagian dari tabel Postgresql kami digunakan untuk menyimpan log akses server, dan karena itu kadang-kadang selama produksi ini bisa menjadi cukup besar. apakah ada cara pengaturan di postgresql untuk memiliki jumlah maksimum catatan yang dapat dimiliki tabel dan untuk mendorong catatan tertua?

Jharwood
sumber

Jawaban:

12

Anda dapat menentukan pemicu untuk mempertahankan nomor baris yang Anda inginkan:

CREATE OR REPLACE FUNCTION trf_keep_row_number_steady()
RETURNS TRIGGER AS
$body$
BEGIN
    -- delete only where are too many rows
    IF (SELECT count(id) FROM log_table) > rownum_limit
    THEN 
        -- I assume here that id is an auto-incremented value in log_table
        DELETE FROM log_table
        WHERE id = (SELECT min(id) FROM log_table);
    END IF;
END;
$body$
LANGUAGE plpgsql;

CREATE TRIGGER tr_keep_row_number_steady 
AFTER INSERT ON log_table
FOR EACH ROW EXECUTE PROCEDURE trf_keep_row_number_steady();

Ini mungkin bukan opsi berkinerja terbaik, tetapi begitu Anda mencapai batasnya, itu tidak akan pernah terlampaui. Jika ada ruang untuk berfluktuasi, maka Anda dapat memeriksa nomor baris secara berkala dan menghapus baris berlebih dari awal.

EDIT: Jika Anda memiliki log yang sangat besar (katakan satu juta per bulan) daripada mempartisi dapat menjadi solusi termudah. Anda kemudian dapat dengan mudah menjatuhkan tabel yang tidak perlu (katakan di manamax(timestamp) < CURRENT_DATE - 1 year). Anda dapat menggunakan stempel waktu (atau tanggal yang diturunkan) sebagai syarat untuk partisi rentang .

Tapi hati-hati sebelum membuang log lama. Apakah Anda yakin tidak akan pernah membutuhkannya?

dezso
sumber
kita dapat menjalankannya secara berkala, dan kami yakin kami tidak akan membutuhkannya begitu tabelnya cukup besar untuk membutuhkan ini, saya hanya berusaha mengotomatiskan pemeliharaan DB sebanyak mungkin :)
Jharwood
Saya juga berharap postgres dapat mengetahui mana yang lebih tua itu sendiri, tetapi jika tidak karena kami tidak memiliki ID, ia dapat menggunakan bidang timestamp tanggal kami buat "2012-06-22 17: 17: 52.692514"
Jharwood
@Jharwood - mengedit jawaban saya. Tolong beritahu saya jika Anda membutuhkan detail lebih lanjut.
dezso
2
+1 pada saran pemartisian. Jika Anda ingin menggunakan hitungan tanpa overhead ekstrem memindai tabel setiap kali, Anda bisa menggunakan pg_class.reltuples untuk aproksimasi atau Anda dapat menggunakan pemicu untuk mempertahankan hitungan dalam tabel "kontrol".
kgrittn
4

Saya membuat fungsi independen tabel yang lebih umum.

CREATE OR REPLACE FUNCTION keep_row_number_steady()
RETURNS TRIGGER AS
$body$
DECLARE
    tab text;
    keyfld text;
    nritems INTEGER;
    rnd DOUBLE PRECISION;
BEGIN
    tab := TG_ARGV[0];
    keyfld := TG_ARGV[1];
    nritems := TG_ARGV[2]; 
    rnd := TG_ARGV[3];

    IF random() < rnd
    THEN 
        EXECUTE(format('DELETE FROM %s WHERE %s < (SELECT %s FROM %s ORDER BY %s DESC LIMIT 1 OFFSET %s)', tab, keyfld, keyfld, tab, keyfld, nritems));
    END IF;
    RETURN NULL;
END;
$body$
LANGUAGE plpgsql;

CREATE TRIGGER log_table_keep_row_number_steady_trigger
AFTER INSERT ON log_table
FOR EACH STATEMENT EXECUTE PROCEDURE keep_row_number_steady('log_table', 'id', 1000, 0.1);

Fungsi ini mengambil 4 parameter:

  • tab: nama tabel
  • keyfld: bidang kunci numerik dan progresif
  • nritems: jumlah item yang akan disimpan
  • rnd: angka acak, dari 0 hingga 1; semakin besar, semakin sering tabel dibersihkan (0 = tidak pernah, 1 = selalu, 0,1 = 10% kali)

Dengan cara ini Anda dapat membuat berapa banyak pemicu yang Anda inginkan memanggil fungsi yang sama.

Semoga ini membantu.

Straps
sumber
0

Saya membuat proc ini dan menjalankannya dari PG Agent (atau windows job atau cron job tergantung). Saya dapat memiliki lebih banyak baris, ini membuat tabel log saya tidak terlalu besar. Menghemat overhead pemicu.

CREATE or replace FUNCTION activitylogcleanup(_MaxRows int) RETURNS void
    LANGUAGE plpgsql
    AS $$
DECLARE
   minid    int;
BEGIN
    SELECT logid into minid FROM activitylogapplication 
     order by logid desc limit 1 OFFSET _MaxRows;

    if not found then 
        return;
    END IF; 

    Delete from activitylogapplication where logid < minid;
END;
$$;
Ron H
sumber