Ini adalah bagian kedua dari blog saya “Ekstensi PostgreSQL Favorit Saya” di mana saya telah memperkenalkan kepada Anda dua ekstensi PostgreSQL, postgres_fdw dan pg_partman. Di bagian ini saya akan mengeksplorasi tiga lagi.
pgAudit
Perpanjangan minat PostgreSQL berikutnya adalah untuk tujuan memenuhi persyaratan audit oleh berbagai pemerintah, keuangan, dan badan sertifikasi lainnya seperti ISO, BSI, dan FISCAM, dll. Fasilitas logging standar yang ditawarkan PostgreSQL secara asli with log_statement =all berguna untuk pemantauan, tetapi tidak memberikan detail yang diperlukan untuk mematuhi atau menghadapi audit. Ekstensi pgAudit berfokus pada detail tentang apa yang terjadi di balik layar, sementara database memenuhi permintaan aplikasi.
Jejak audit atau log audit dibuat dan diperbarui oleh fasilitas logging standar yang disediakan oleh PostgreSQL, yang menyediakan logging sesi dan/atau objek audit terperinci. Jejak audit yang dibuat oleh pgAudit bisa sangat besar ukurannya tergantung pada pengaturan audit, jadi harus diperhatikan untuk memutuskan apa dan berapa banyak audit yang diperlukan sebelumnya. Demo singkat di bagian berikut menunjukkan bagaimana pgAudit dikonfigurasi dan digunakan.
Jejak log dibuat dalam log cluster database PostgreSQL yang ditemukan di lokasi PGDATA/log tetapi pesan log audit diawali dengan label “AUDIT:“ untuk membedakan antara pesan latar belakang database biasa dan log audit catatan.
Demo
Dokumentasi resmi pgAudit menjelaskan bahwa ada versi terpisah dari pgAudit untuk setiap versi utama PostgreSQL untuk mendukung fungsionalitas baru yang diperkenalkan di setiap rilis PostgreSQL. Versi PostgreSQL dalam demo ini adalah 11, jadi versi pgAudit akan berasal dari cabang 1.3.X. pgaudit.log adalah parameter dasar yang akan diatur yang mengontrol kelas pernyataan apa yang akan dicatat. Itu dapat diatur dengan SET untuk tingkat sesi atau di dalam file postgresql.conf untuk diterapkan secara global.
postgres=# set pgaudit.log = 'read, write, role, ddl, misc';
SET
cat $PGDATA/pgaudit.log
pgaudit.log = 'read, write, role, ddl, misc'
db_replica=# show pgaudit.log;
pgaudit.log
------------------------------
read, write, role, ddl, misc
(1 row)
2020-01-29 22:51:49.289 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,3,1,MISC,SHOW,,,show pgaudit.log;,<not logged>
db_replica=# create table t1 (f1 integer, f2 varchar);
CREATE TABLE
2020-01-29 22:52:08.327 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,4,1,DDL,CREATE TABLE,,,"create table t1 (f1 integer, f2 varchar);",<not logged>
db_replica=# insert into t1 values (1,'one');
INSERT 0 1
db_replica=# insert into t1 values (2,'two');
INSERT 0 1
db_replica=# insert into t1 values (3,'three');
INSERT 0 1
2020-01-29 22:52:19.261 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,5,1,WRITE,INSERT,,,"insert into t1 values (1,'one');",<not logged>
20-01-29 22:52:38.145 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,6,1,WRITE,INSERT,,,"insert into t1 values (2,'two');",<not logged>
2020-01-29 22:52:44.988 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,7,1,WRITE,INSERT,,,"insert into t1 values (3,'three');",<not logged>
db_replica=# select * from t1 where f1 >= 2;
f1 | f2
----+-------
2 | two
3 | three
(2 rows)
2020-01-29 22:53:09.161 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,9,1,READ,SELECT,,,select * from t1 where f1 >= 2;,<not logged>
db_replica=# grant select on t1 to usr_replica;
GRANT
2020-01-29 22:54:25.283 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,13,1,ROLE,GRANT,,,grant select on t1 to usr_replica;,<not logged>
db_replica=# alter table t1 add f3 date;
ALTER TABLE
2020-01-29 22:55:17.440 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,23,1,DDL,ALTER TABLE,,,alter table t1 add f3 date;,<not logged>
db_replica=# checkpoint;
CHECKPOINT
2020-01-29 22:55:50.349 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,33,1,MISC,CHECKPOINT,,,checkpoint;,<not logged>
db_replica=# vacuum t1;
VACUUM
2020-01-29 22:56:03.007 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,34,1,MISC,VACUUM,,,vacuum t1;,<not logged>
db_replica=# show log_statement;
log_statement
---------------
none
2020-01-29 22:56:14.740 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,36,1,MISC,SHOW,,,show log_statement;,<not logged>
Entri log, seperti yang ditunjukkan pada demo di atas, hanya ditulis ke file log latar belakang server ketika parameter log_statement disetel, namun dalam hal ini tidak dikonfigurasi tetapi pesan audit ditulis berdasarkan parameter pgaudit.log sebagaimana dibuktikan dalam demo. Ada opsi yang lebih kuat yang tersedia untuk memenuhi semua persyaratan audit database Anda dalam PostgreSQL, yang dapat dikonfigurasi dengan mengikuti dokumentasi resmi pgaudit di sini atau di repositori github.pg_repack
Ini adalah ekstensi favorit di antara banyak insinyur PostgreSQL yang terlibat langsung dalam mengelola dan menjaga kesehatan umum klaster PostgreSQL. Alasan untuk itu akan dibahas nanti, tetapi ekstensi ini menawarkan fungsionalitas untuk menghapus pengasapan basis data dalam basis data PostgreSQL, yang merupakan salah satu masalah yang mengganggu di antara klaster basis data PostgreSQL yang sangat besar yang memerlukan pengorganisasian ulang basis data.
Karena database PostgreSQL mengalami PENULISAN yang konstan dan berat (pembaruan &penghapusan), data lama ditandai sebagai dihapus saat versi baru dari baris dimasukkan, tetapi data lama tidak benar-benar dihapus dari blok data. Ini memerlukan operasi pemeliharaan berkala yang disebut penyedot debu, yang merupakan prosedur otomatis yang dijalankan di latar belakang yang menghapus semua baris yang "ditandai sebagai dihapus". Proses ini kadang-kadang disebut sebagai pengumpulan sampah dalam istilah sehari-hari.
Proses penyedotan debu biasanya memberi jalan bagi operasi basis data selama masa sibuk. Cara penyedot debu yang paling tidak membatasi yang mendukung operasi basis data menghasilkan sejumlah besar baris "ditandai sebagai dihapus" yang menyebabkan basis data tumbuh tidak proporsional yang disebut sebagai "penggembungan basis data". Ada proses penyedot debu yang kuat yang disebut VACUUM FULL, tetapi hal itu menghasilkan perolehan kunci eksklusif pada objek database yang sedang diproses, sehingga menghentikan operasi database pada objek tersebut.
pg_repack
Karena alasan inilah pg_repack menjadi hit di antara DBA dan insinyur PostgreSQL, karena ia melakukan pekerjaan proses penyedotan debu normal tetapi menawarkan efisiensi VACUUM FULL dengan tidak memperoleh kunci eksklusif pada database objek, singkatnya, ia bekerja secara online. Dokumentasi resmi di sini menjelaskan lebih lanjut tentang metode lain untuk mengatur ulang basis data tetapi demo cepat seperti di bawah ini akan menjelaskan hal-hal yang sesuai untuk pemahaman yang lebih baik. Ada persyaratan bahwa tabel target harus memiliki setidaknya satu kolom yang didefinisikan sebagai KUNCI UTAMA, yang merupakan norma umum di sebagian besar penyiapan basis data produksi.
Demo
Demo dasar menunjukkan penginstalan dan penggunaan pg_repack di lingkungan pengujian. Demo ini menggunakan pg_repack versi 1.4.5 yang merupakan versi terbaru dari ekstensi ini pada saat blog ini diterbitkan. Tabel demo t1 awalnya memiliki 80000 baris yang mengalami operasi penghapusan besar-besaran, yang menghapus setiap baris ke-5 dari tabel. Eksekusi pg_repack menunjukkan ukuran tabel sebelum dan sesudahnya.
mydb=# CREATE EXTENSION pg_repack;
CREATE EXTENSION
mydb=# create table t1 (no integer primary key, f_name VARCHAR(20), l_name VARCHAR(20), d_o_b date);
CREATE TABLE
mydb=# insert into t1 (select generate_series(1,1000000,1),'a'||
mydb(# generate_series(1,1000000,1),'a'||generate_series(1000000,1,-1),
mydb(# cast( now() - '1 year'::interval * random() as date ));
INSERT 0 1000000
mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));
pg_size_pretty
----------------
71 MB
(1 row)
mydb=# CREATE or replace FUNCTION delete5() RETURNS void AS $$
mydb$# declare
mydb$# counter integer := 0;
mydb$# BEGIN
mydb$#
mydb$# while counter <= 1000000
mydb$# loop
mydb$# delete from t1 where no=counter;
mydb$# counter := counter + 5;
mydb$# END LOOP;
mydb$# END;
mydb$# $$ LANGUAGE plpgsql;
CREATE FUNCTION
Fungsi delete5 menghapus 200000 baris dari tabel t1 menggunakan penghitung yang bertambah 5 hitungan
mydb=# select delete5();
delete5
------
(1 row)
mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));
pg_size_pretty
----------------
71 MB
(1 row)
$ pg_repack -t t1 -N -n -d mydb -p 5433
INFO: Dry run enabled, not executing repack
INFO: repacking table "public.t1"
$ pg_repack -t t1 -n -d mydb -p 5433
INFO: repacking table "public.t1"
mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));
pg_size_pretty
----------------
57 MB
(1 row)
Seperti yang ditunjukkan di atas, ukuran asli tabel tidak berubah setelah menjalankan fungsi delete5, yang menunjukkan bahwa baris masih ada dalam tabel. Eksekusi pg_repack menghapus baris 'ditandai sebagai dihapus' dari tabel t1 sehingga menurunkan ukuran tabel t1 menjadi 57 MB. Satu hal baik lainnya tentang pg_repack adalah opsi untuk menjalankan kering dengan flag -N, yang dengannya Anda dapat memeriksa apa yang akan dieksekusi selama proses yang sebenarnya.
HypoPG
Ekstensi menarik berikutnya identik dengan konsep populer yang disebut indeks tak terlihat di antara server basis data berpemilik. Ekstensi HypoPG memungkinkan DBA untuk melihat efek pengenalan indeks hipotetis (yang tidak ada) dan apakah itu akan meningkatkan kinerja satu atau lebih kueri, dan karenanya dinamai HypoPG.
Pembuatan indeks hipotetis tidak memerlukan sumber daya CPU atau disk apa pun, namun menggunakan memori pribadi koneksi. Karena indeks hipotetis tidak disimpan dalam tabel katalog database apa pun, jadi tidak ada dampak dari tabel mengasapi. Karena alasan inilah, indeks hipotetis tidak dapat digunakan dalam pernyataan EXPLAIN ANALYZE sementara EXPLAIN biasa adalah cara yang baik untuk menilai apakah indeks potensial akan digunakan oleh kueri bermasalah yang diberikan. Berikut adalah demo singkat untuk menjelaskan cara kerja HypoPG.
Demo
Saya akan membuat tabel yang berisi 100.000 baris menggunakan generate_series dan menjalankan beberapa kueri sederhana untuk menunjukkan perbedaan dalam perkiraan biaya dengan dan tanpa indeks hipotetis.
olap=# CREATE EXTENSION hypopg;
CREATE EXTENSION
olap=# CREATE TABLE stock (id integer, line text);
CREATE TABLE
olap=# INSERT INTO stock SELECT i, 'line ' || i FROM generate_series(1, 100000) i;
INSERT 0 100000
olap=# ANALYZE STOCK;
ANALYZE
olap=# EXPLAIN SELECT line FROM stock WHERE id = 1;
QUERY PLAN
---------------------------------------------------------
Seq Scan on stock (cost=0.00..1791.00 rows=1 width=10)
Filter: (id = 1)
(2 rows)
olap=# SELECT * FROM hypopg_create_index('CREATE INDEX ON stock (id)') ;
indexrelid | indexname
------------+-----------------------
25398 | <25398>btree_stock_id
(1 row)
olap=# EXPLAIN SELECT line FROM stock WHERE id = 1;
QUERY PLAN
------------------------------------------------------------------------------------
Index Scan using <25398>btree_stock_id on stock (cost=0.04..8.06 rows=1 width=10)
Index Cond: (id = 1)
(2 rows)
olap=# EXPLAIN ANALYZE SELECT line FROM stock WHERE id = 1;
QUERY PLAN
----------------------------------------------------------------------------------------------------
Seq Scan on stock (cost=0.00..1791.00 rows=1 width=10) (actual time=0.028..41.877 rows=1 loops=1)
Filter: (id = 1)
Rows Removed by Filter: 99999
Planning time: 0.057 ms
Execution time: 41.902 ms
(5 rows)
olap=# SELECT indexname, pg_size_pretty(hypopg_relation_size(indexrelid))
olap-# FROM hypopg_list_indexes() ;
indexname | pg_size_pretty
-----------------------+----------------
<25398>btree_stock_id | 2544 kB
(1 row)
olap=# SELECT pg_size_pretty(pg_relation_size('stock'));
pg_size_pretty
----------------
4328 kB
(1 row)
Pameran di atas menunjukkan bagaimana perkiraan biaya total dapat dikurangi dari 1791 menjadi 8,06 dengan menambahkan indeks ke bidang "id" tabel untuk mengoptimalkan kueri sederhana. Ini juga membuktikan bahwa indeks tidak benar-benar digunakan ketika kueri dijalankan dengan EXPLAIN ANALYZE yang mengeksekusi kueri secara real time. Ada juga cara untuk mengetahui kira-kira berapa banyak ruang disk yang ditempati indeks menggunakan fungsi hypopg_list_indexes dari ekstensi.
The HypoPG memiliki beberapa fungsi lain untuk mengelola indeks hipotetis dan selain itu, ia juga menawarkan cara untuk mengetahui apakah mempartisi tabel akan meningkatkan kinerja kueri yang mengambil kumpulan data besar. Ada opsi partisi hipotetis dari ekstensi HypoPG dan lebih banyak lagi yang dapat diikuti dengan merujuk ke dokumentasi resmi.
Kesimpulan
Seperti yang dinyatakan di bagian satu, PostgreSQL telah berkembang selama bertahun-tahun hanya menjadi lebih besar, lebih baik, dan lebih cepat dengan perkembangan pesat baik dalam kode sumber asli maupun ekstensi plug and play. Versi open source dari PostgreSQL baru dapat menjadi yang paling cocok untuk banyak toko IT yang menjalankan salah satu server database berpemilik utama, untuk mengurangi CAPEX dan OPEX IT mereka.
Ada banyak ekstensi PostgreSQL yang menawarkan fitur mulai dari pemantauan hingga ketersediaan tinggi dan dari penskalaan hingga membuang file data biner ke dalam format yang dapat dibaca manusia. Demonstrasi di atas diharapkan dapat menjelaskan potensi dan kekuatan maksimum database PostgreSQL.