PostgreSQL adalah salah satu database open-source paling populer di dunia dan memiliki implementasi yang sukses di beberapa lingkungan mission-critical di berbagai domain, menggunakan aplikasi OLTP high-end real-time yang melakukan jutaan dan miliaran transaksi per hari. PostgreSQL I/O cukup andal, stabil, dan berkinerja di hampir semua perangkat keras, termasuk bahkan cloud.
Untuk memastikan bahwa database tampil pada skala yang diharapkan dengan waktu respons yang diharapkan, ada kebutuhan untuk beberapa rekayasa kinerja. Nah, pencapaian kinerja database yang baik tergantung pada berbagai faktor. Kinerja basis data dapat menjadi buruk karena berbagai alasan seperti dimensi infrastruktur, strategi pemeliharaan basis data yang tidak efisien, kode SQL yang buruk, atau proses basis data yang dikonfigurasi dengan buruk yang gagal memanfaatkan semua sumber daya yang tersedia - CPU, memori, bandwidth jaringan, dan I/O disk.
Apa yang Dapat Menyebabkan Kinerja Basis Data Turun?
- Kueri yang ditulis dengan buruk dengan gabungan yang buruk, logika, dll. yang menghabiskan banyak CPU dan memori
- Kueri yang melakukan pemindaian tabel penuh pada tabel besar karena Pengindeksan yang tidak tepat
- Pemeliharaan database yang buruk tanpa statistik yang tepat
- Perencanaan kapasitas yang tidak efisien yang mengakibatkan infrastruktur berdimensi tidak memadai
- Desain logis dan fisik yang tidak tepat
- Tidak ada penyatuan koneksi, yang menyebabkan aplikasi membuat sejumlah besar koneksi dengan cara yang tidak terkendali
Jadi itu banyak area potensial yang dapat menyebabkan masalah kinerja. Salah satu area penting yang ingin saya fokuskan di blog ini adalah bagaimana menyetel kinerja PostgreSQL I/O (Input/Output). Menyetel operasi Input / Output PostgreSQL sangat penting, terutama di lingkungan transaksional tinggi seperti OLTP atau di lingkungan Data warehousing dengan analisis data kompleks pada kumpulan data ukuran besar.
Sebagian besar waktu, masalah kinerja database disebabkan terutama karena I/O yang tinggi. Ini berarti, proses database menghabiskan lebih banyak waktu untuk menulis atau membaca dari disk. Setiap operasi data real-time terikat I/O, sangat penting untuk memastikan database disetel I/O. Di blog ini, saya akan berfokus pada masalah I/O umum yang dapat dihadapi database PostgreSQL dalam lingkungan produksi waktu nyata.
Menyetel PostgreSQL I/O
Menyetel PostgreSQL I/O sangat penting untuk membangun arsitektur database yang berkinerja tinggi dan skalabel. Mari kita lihat berbagai faktor yang memengaruhi kinerja I/O:
- Pengindeksan
- Mempartisi
- Pos pemeriksaan
- VACUUM, ANALISIS (dengan FILLFACTOR)
- Masalah I/O lainnya
- I/O PostgreSQL di Cloud
- Alat
Pengindeksan
Pengindeksan adalah salah satu teknik penyetelan inti yang memainkan peran penting dalam meningkatkan kinerja I/O basis data. Ini benar-benar berlaku untuk basis data apa pun. PostgreSQL mendukung berbagai jenis indeks yang dapat mempercepat operasi membaca sampai batas tertentu, menghasilkan peningkatan skalabilitas untuk aplikasi. Sementara membuat indeks cukup sederhana dan lugas, penting bagi DBA dan pengembang untuk memiliki pengetahuan tentang jenis indeks yang akan dipilih, dan kolom apa. Yang terakhir ini didasarkan pada berbagai faktor seperti kompleksitas kueri, tipe data, kardinalitas data, volume penulisan, ukuran data, arsitektur disk, infrastruktur (cloud publik, cloud pribadi atau lokal), dll.
Sementara pengindeksan dapat secara dramatis meningkatkan kinerja membaca kueri, itu juga dapat memperlambat penulisan yang mengenai kolom yang diindeks. Mari kita lihat sebuah contoh:
Dampak Indeks pada operasi READ
Sebuah tabel bernama emp dengan sekitar 1 juta baris.
BACA Performa tanpa Indeks
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
-----+---------------+--------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 70.020 ms => took about 70+ milli-seconds to respond with on row
BACA Performa dengan Indeks
Mari kita taruh indeks di kolom lebaran dan lihat perbedaannya
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
------+-------------+-------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 0.454 ms => 0.4+ milli-seconds!!! thats a huge difference - isn’t it?
Jadi, Pengindeksan itu penting.
Dampak Indeks pada operasi MENULIS
Indeks memperlambat kinerja penulisan. Sementara Indeks berdampak pada semua jenis operasi tulis, mari kita lihat beberapa analisis tentang dampak Indeks pada INSERT
Memasukkan 1 juta baris ke dalam Tabel tanpa indeks
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 4818.470 ms (00:04.818) => Takes about 4.8 seconds
Memasukkan 1 juta baris yang sama dengan Indeks
Mari kita buat Indeks dulu
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 7825.494 ms (00:07.825) => Takes about 7.8 seconds
Jadi, seperti yang dapat kita amati, waktu INSERT meningkat sebesar 80% hanya dengan satu indeks dan dapat memakan waktu lebih lama untuk menyelesaikannya jika ada banyak indeks. Itu bisa menjadi lebih buruk ketika ada indeks berbasis fungsi. Itulah yang harus dijalani oleh DBA! Indeks akan meningkatkan kinerja penulisan. Ada beberapa cara untuk mengatasi masalah ini, yang bergantung pada arsitektur disk. Jika server database menggunakan beberapa sistem file disk, maka indeks dan tabel dapat ditempatkan di beberapa ruang tabel yang duduk di beberapa sistem file disk. Dengan cara ini, kinerja I/O yang lebih baik dapat dicapai.
TIPS pengelolaan indeks
- Pahami perlunya indeks. Pengindeksan cerdas adalah kuncinya.
- Hindari membuat banyak indeks, dan tentu saja tidak ada indeks yang tidak perlu, ini benar-benar dapat menurunkan kinerja penulisan.
- Pantau penggunaan indeks dan hapus indeks yang tidak digunakan.
- Saat kolom yang diindeks mengalami perubahan data, indeks juga membengkak. Jadi, atur ulang indeks secara teratur.
Mempartisi
Strategi partisi yang efektif dapat mengurangi sebagian besar masalah kinerja I/O. Tabel besar dapat dipartisi berdasarkan logika bisnis. PostgreSQL mendukung partisi tabel. Meskipun tidak sepenuhnya mendukung semua fitur saat ini, ini hanya dapat membantu beberapa kasus penggunaan waktu nyata. Di PostgreSQL, tabel anak yang dipartisi sepenuhnya individual untuk tabel master yang merupakan hambatan. Misalnya, Batasan yang dibuat pada tabel master tidak dapat diturunkan secara otomatis ke tabel turunan.
Namun, dari perspektif keseimbangan I/O, partisi dapat sangat membantu. Semua partisi anak dapat dibagi menjadi beberapa tablespace dan sistem file disk. Kueri dengan rentang tanggal dalam klausa “di mana” mengenai tabel, yang dipartisi berdasarkan rentang tanggal, dapat memperoleh manfaat dari mempartisi hanya dengan memindai satu atau dua partisi alih-alih tabel lengkap.
Pos pemeriksaan
Pos pemeriksaan menentukan keadaan database yang konsisten. Mereka sangat penting dan penting bahwa pos pemeriksaan terjadi cukup teratur untuk memastikan perubahan data disimpan secara permanen ke disk dan database berada pada keadaan yang konsisten sepanjang waktu. Karena itu, konfigurasi pos pemeriksaan yang tidak tepat dapat menyebabkan masalah kinerja I/O. DBA harus teliti dalam mengonfigurasi pos pemeriksaan untuk memastikan tidak ada lonjakan I/O dan juga ini tergantung pada seberapa bagus disk dan seberapa baik tata letak file data dirancang.
Apa fungsi pos pemeriksaan?
Secara sederhana, pos pemeriksaan akan memastikan:
- Semua data yang dikomit ditulis ke file data di disk.
- file clog diperbarui dengan status komit.
- File log transaksi di direktori pg_xlog (sekarang pg_wal) didaur ulang.
Itu menjelaskan bagaimana pos pemeriksaan intensif I/O. Ada parameter di postgresql.conf yang dapat dikonfigurasi / disetel untuk mengontrol perilaku pos pemeriksaan dan parameter tersebut adalah max_wal_size, min_wal_size, checkpoint_timeout dan checkpoint_completion_target. Parameter ini akan menentukan seberapa sering pos pemeriksaan harus dilakukan, dan berapa lama pos pemeriksaan harus diselesaikan.
Bagaimana memahami konfigurasi apa yang lebih baik untuk pos pemeriksaan? Bagaimana cara menyetelnya?
Berikut beberapa kiatnya:
- Mengevaluasi TPS database. Mengevaluasi total volume transaksi yang terjadi di database dalam satu hari kerja dan juga mengidentifikasi pada jam berapa jumlah transaksi tertinggi mencapai database.
- Diskusikan dengan pengembang aplikasi dan tim teknis lainnya secara berkala untuk memahami statistik tingkat transaksi basis data serta pertumbuhan transaksi di masa mendatang.
- Ini juga dapat dilakukan dari akhir basis data:
-
Memantau database dan mengevaluasi jumlah transaksi yang terjadi sepanjang hari. Ini dapat dilakukan dengan menanyakan tabel pgcatalog seperti pg_stat_user_tables.
-
Evaluasi jumlah file arsip wal yang dihasilkan per hari
-
Pantau untuk memahami bagaimana kinerja pos pemeriksaan dengan mengaktifkan parameter log_checkpoints
2018-06-06 15:03:16.446 IST [2111] LOG: checkpoint starting: xlog 2018-06-06 15:03:22.734 IST [2111] LOG: checkpoint complete: wrote 12112 buffers (73.9%); 0 WAL file(s) added, 0 removed, 25 recycled; write=6.058 s, sync=0.218 s, total=6.287 s; sync files=4, longest=0.178 s, average=0.054 s; distance=409706 kB, estimate=412479 kB
-
Pahami apakah konfigurasi pos pemeriksaan saat ini cukup baik untuk database. Konfigurasi parameter checkpoint_warning (secara default dikonfigurasi ke 30 detik) untuk melihat peringatan di bawah ini di file log postgres.
2018-06-06 15:02:42.295 IST [2111] LOG: checkpoints are occurring too frequently (11 seconds apart) 2018-06-06 15:02:42.295 IST [2111] HINT: Consider increasing the configuration parameter "max_wal_size".
-
Apa maksud dari peringatan di atas?
Pos pemeriksaan umumnya terjadi setiap kali max_wal_size (1 GB secara default yang berarti 64 file WAL) senilai file log diisi atau ketika checkpoint_timeout (setiap 5 menit setiap default) tercapai. Peringatan di atas berarti max_wal_size yang dikonfigurasi tidak memadai dan pos pemeriksaan terjadi setiap 11 detik, yang berarti 64 file WAL di direktori PG_WAL terisi hanya dalam 11 detik, yang terlalu sering. Dengan kata lain, jika frekuensi transaksinya lebih sedikit, maka checkpoint akan dilakukan setiap 5 menit. Jadi, seperti petunjuk yang disarankan, naikkan parameter max_wal_size ke nilai yang lebih tinggi, parameter max_min_size dapat ditingkatkan menjadi sama atau lebih kecil dari sebelumnya.
Parameter penting lainnya yang perlu dipertimbangkan dari perspektif kinerja I/O adalah checkpoint_completion_target yang secara default dikonfigurasi ke 0,5.
checkpoint_completion_target =0,5 x checkpoint_timeout =2,5 menit
Itu berarti, pos pemeriksaan punya waktu 2,5 menit untuk menyinkronkan blok kotor ke disk. Apakah 2,5 menit cukup? Itu perlu dievaluasi. Jika jumlah blok kotor yang akan ditulis sangat tinggi, maka 2,5 menit bisa terlihat sangat agresif dan saat itulah lonjakan I/O dapat diamati. Konfigurasi parameter complete_target harus dilakukan berdasarkan nilai max_wal_size dan checkpoint_timeout. Jika parameter ini dinaikkan ke nilai yang lebih tinggi, pertimbangkan untuk menaikkan checkpoint_completion_target yang sesuai.
VACUUM, ANALISIS (dengan FILLFACTOR)
VACUUM adalah salah satu fitur paling kuat dari PostgreSQL. Ini dapat digunakan untuk menghapus bloats (ruang terfragmentasi) di dalam tabel dan indeks, dan dihasilkan oleh transaksi. Basis data harus di-vakum secara teratur untuk memastikan pemeliharaan yang sehat dan kinerja yang lebih baik. Sekali lagi, tidak MENGHAPUS database secara teratur dapat menyebabkan masalah kinerja yang serius. ANALISIS harus dilakukan bersama dengan VACUUM (VACUUM ANALYZE) untuk memastikan statistik terkini untuk perencana kueri.
VACUUM ANALYZE dapat dilakukan dengan dua cara:manual, otomatis atau keduanya. Dalam lingkungan produksi real-time, umumnya keduanya. VACUUM otomatis diaktifkan oleh parameter "autovacuum" yang secara default dikonfigurasi ke "on". Dengan autovacuum diaktifkan, PostgreSQL secara otomatis mulai MENGHAPUS Tabel secara berkala. Tabel kandidat yang membutuhkan penyedotan debu diambil oleh proses vakum otomatis berdasarkan berbagai ambang batas yang ditetapkan oleh berbagai parameter vakum*, parameter ini dapat diubah / disetel untuk memastikan kembung tabel dibersihkan secara berkala. Mari kita lihat beberapa parameter dan penggunaannya -
Parameter vakum otomatis
autovacuum=on | Parameter ini digunakan untuk mengaktifkan / menonaktifkan autovacuum. Standarnya adalah “aktif”. |
log_autovacuum_min_duration =-1 | Mencatat durasi proses autovacuum. Ini penting untuk memahami berapa lama proses autovacuum berjalan. |
autovacuum_max_workers =3 | Jumlah proses autovacuum yang dibutuhkan. Ini bergantung pada seberapa agresif transaksi database, dan berapa banyak CPU yang dapat Anda tawarkan untuk proses autovacuum. |
autovacuum_naptime =1 menit | Waktu istirahat vakum otomatis di antara waktu vakum otomatis. |
Parameter yang menentukan ambang batas untuk memulai proses Autovacuum
Pekerjaan autovacuum dimulai ketika ambang batas tertentu tercapai. Di bawah ini adalah parameter yang dapat digunakan untuk menetapkan ambang tertentu, berdasarkan mana, proses autovacuum akan dimulai.
autovacuum_vacuum_threshold =50 | Tabel akan divakum jika minimal 50 baris akan diperbarui / dihapus dalam sebuah Tabel. |
autovacuum_analyze_threshold =50 | Tabel akan dianalisis ketika minimal 50 baris akan diperbarui / dihapus dalam sebuah Tabel. |
autovacuum_vacuum_scale_factor =0,2 | Tabel akan dikosongkan ketika minimal 20% dari baris diperbarui / dihapus dalam Tabel. |
autovacuum_analyze_scale_factor =0,1 | Tabel akan dikosongkan ketika minimal 10% dari baris diperbarui / dihapus dalam Tabel. |
Parameter ambang batas di atas dapat dimodifikasi berdasarkan perilaku basis data. DBA perlu menganalisis dan mengidentifikasi tabel panas dan memastikan tabel tersebut dikosongkan sesering mungkin untuk memastikan kinerja yang baik. Mencapai nilai tertentu untuk parameter ini dapat menjadi tantangan dalam lingkungan transaksi tinggi, di mana perubahan data terjadi setiap detik. Sering kali saya memperhatikan bahwa proses autovacuum membutuhkan waktu yang cukup lama untuk diselesaikan, yang pada akhirnya menghabiskan terlalu banyak sumber daya dalam sistem produksi.
Saya menyarankan untuk tidak bergantung sepenuhnya pada proses autovacuum, cara terbaik adalah menjadwalkan pekerjaan VACUUM ANALYZE setiap malam sehingga beban pada autovacuum berkurang. Untuk memulainya, pertimbangkan untuk MENGHAPUS tabel besar secara manual dengan tingkat transaksi tinggi.
VAKUM PENUH
VACUUM FULL membantu merebut kembali ruang yang membengkak di tabel dan indeks. Utilitas ini tidak dapat digunakan saat database online karena mengunci tabel. Tabel harus dikenakan VACUUM FULL hanya ketika aplikasi dimatikan. Indeks juga akan diatur ulang bersama dengan tabel selama VACUUM FULL.
Mari kita lihat dampak dari VACUUM ANALYZE
Kembung:Bagaimana cara mengidentifikasi kembung? Kapan kembung dibuat?
Berikut adalah beberapa pengujian:
Saya punya tabel ukuran 1 GB dengan 10 juta baris.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
----------------
1
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Mari kita lihat dampak dari kembung pada kueri sederhana:pilih * dari pgbench_accounts;
Di bawah ini adalah rencana penjelasan untuk kueri:
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.00 rows=10000000 width=97)
(actual time=0.033..1054.257 rows=10000000 loops=1)
Planning time: 0.255 ms
Execution time: 1494.448 ms
Sekarang, mari kita perbarui semua baris dalam tabel dan lihat dampak dari kueri SELECT di atas.
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Di bawah ini adalah RENCANA JELASKAN dari eksekusi permintaan pasca UPDATE.
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..527868.39 rows=19999939 width=97)
(actual time=404.474..1520.175 rows=10000000 loops=1)
Planning time: 0.051 ms
Execution time: 1958.532 ms
Ukuran tabel meningkat menjadi 2 GB setelah UPDATE
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
2
Jika Anda dapat mengamati dan membandingkan jumlah biaya dari EXPLAIN PLAN sebelumnya, ada perbedaan besar. Biaya telah meningkat dengan margin besar. Lebih penting lagi jika Anda mengamati dengan cermat, jumlah baris (lebih dari 19 juta) yang dipindai setelah UPDATE lebih tinggi yang hampir dua kali lipat dari baris yang ada sebenarnya (10 juta). Itu berarti, jumlah baris yang membengkak adalah 9+ juta dan waktu aktual juga meningkat dan waktu eksekusi meningkat dari 1,4 detik menjadi 1,9 detik.
Jadi, itulah dampak dari tidak MENGUMPULKAN TABEL setelah UPDATE. Angka EXPLAIN PLAN di atas justru berarti, tabel membengkak.
Bagaimana cara mengidentifikasi jika tabel kembung? Gunakan modul kontribusi pgstattuple:
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 9879891 | 1195466811 | 44.51 | 52096468 | 1.94
Angka di atas menunjukkan bahwa setengah dari tabel membengkak.
Mari kita MENGANALISIS VAKUM tabel dan melihat dampaknya sekarang:
postgres=# VACUUM ANALYZE pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..428189.05 rows=10032005 width=97)
(actual time=400.023..1472.118 rows=10000000 loops=1)
Planning time: 4.374 ms
Execution time: 1913.541 ms
Setelah VACUUM ANALYZE, jumlah biaya telah menurun. Sekarang, jumlah baris yang dipindai muncul hampir 10 juta, juga waktu aktual dan waktu eksekusi tidak banyak berubah. Itu karena, meskipun bloat di tabel sudah hilang, ukuran tabel yang akan dipindai tetap sama. Di bawah ini adalah output pgstattuple post VACUUM ANALYZE.
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 0 | 0 | 0 | 1316722516 | 49.02
Angka di atas menunjukkan bahwa semua kembung (tupel mati) telah hilang.
Mari kita lihat dampak VACUUM FULL ANALYZE dan lihat apa yang terjadi:
postgres=# vacuum full analyze pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.35 rows=10000035 width=97)
(actual time=0.015..1089.726 rows=10000000 loops=1)
Planning time: 0.148 ms
Execution time: 1532.596 ms
Jika Anda amati, waktu aktual dan angka waktu eksekusi mirip dengan angka sebelum UPDATE. Selain itu, ukuran tabel kini telah berkurang dari 2 GB menjadi 1 GB.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
1
Itulah dampak dari VACUUM FULL.
FAKTOR PENGISI
FILLFACTOR adalah atribut yang sangat penting yang dapat membuat perbedaan nyata pada strategi pemeliharaan database pada tabel dan level indeks. Nilai ini menunjukkan jumlah ruang yang akan digunakan oleh INSERT dalam blok data. Nilai FILLFACTOR default ke 100%, yang berarti, INSERT dapat memanfaatkan semua ruang yang tersedia di blok data. Ini juga berarti, tidak ada ruang yang tersedia untuk UPDATE. Nilai ini dapat diturunkan ke nilai tertentu untuk tabel yang sangat diperbarui.
Parameter ini dapat dikonfigurasi untuk setiap tabel dan indeks. Jika FILLFACTOR dikonfigurasi ke nilai optimal, Anda dapat melihat perbedaan nyata dalam kinerja VAKUM dan kinerja kueri juga. Singkatnya, nilai FILLFACTOR yang optimal memastikan jumlah blok yang tidak perlu tidak dialokasikan.
Mari kita lihat contoh yang sama di atas -
Tabel memiliki satu juta baris
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Sebelum update ukuran tabel adalah 1 GB
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
--------
1
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
Setelah pembaruan, ukuran tabel meningkat menjadi 2 GB setelah UPDATE
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
---------
2
Itu berarti, jumlah blok yang dialokasikan ke tabel telah meningkat 100%. Jika FILLFACTOR dikonfigurasi, ukuran tabel mungkin tidak bertambah sebesar margin tersebut.
Bagaimana cara mengetahui nilai apa yang harus dikonfigurasi ke FILLFACTOR?
Itu semua tergantung pada kolom apa yang sedang diperbarui dan ukuran kolom yang diperbarui. Secara umum, akan lebih baik untuk mengevaluasi nilai FILLFACTOR dengan mengujinya di Database UAT. Jika kolom yang diperbarui adalah 10% dari seluruh tabel, maka, pertimbangkan untuk mengonfigurasi fillfactor ke 90% atau 80%.
Catatan Penting:
Jika Anda mengubah nilai FILLFACTOR untuk tabel yang ada dengan data, Anda perlu melakukan VACUUM FULL atau penataan ulang tabel untuk memastikan nilai FILLFACTOR berlaku untuk data yang ada.
TIPS VAKUM
- Seperti yang disebutkan di atas, pertimbangkan untuk menjalankan tugas VACUUM ANALYZE secara manual setiap malam pada tabel yang sering digunakan bahkan saat autovacuum diaktifkan.
- Pertimbangkan untuk menjalankan VACUUM ANALYZE pada tabel setelah INSERT massal. Ini penting karena banyak yang percaya bahwa VACUUMing mungkin tidak diperlukan setelah INSERT.
- Pantau untuk memastikan tabel yang sangat aktif di-VACUUM secara teratur dengan menanyakan tabel pg_stat_user_tables.
- Gunakan modul pg_stattuple contrib untuk mengidentifikasi ukuran ruang yang membengkak dalam segmen tabel.
- Utilitas VACUUM FULL tidak dapat digunakan pada sistem basis data produksi. Pertimbangkan untuk menggunakan alat seperti pg_reorg atau pg_repack yang akan membantu mengatur ulang tabel dan indeks secara online tanpa kunci.
- Pastikan proses AUTOVACUUM berjalan lebih lama selama jam kerja (lalu lintas tinggi).
- Aktifkan parameter log_autovacuum_min_duration untuk mencatat waktu dan durasi proses AUTOVACUUM.
- Yang penting, pastikan FILLFACTOR dikonfigurasikan ke nilai optimal pada Tabel dan Indeks transaksi tinggi.
Masalah I/O lainnya
Penyortiran Disk
Kueri yang melakukan penyortiran adalah kejadian umum lainnya dalam basis data produksi waktu nyata dan sebagian besar dari ini tidak dapat dihindari. Kueri menggunakan klausa seperti GROUP BY, ORDER BY, DISTINCT, CREATE INDEX, VACUUM FULL dll. melakukan penyortiran dan penyortiran dapat dilakukan pada disk. Penyortiran terjadi di memori jika pemilihan dan pengurutan dilakukan berdasarkan kolom yang diindeks. Di sinilah indeks komposit memainkan peran kunci. Indeks secara agresif di-cache ke dalam memori. Jika tidak, jika ada kebutuhan untuk menyortir data pada disk, kinerjanya akan melambat secara drastis.
Untuk memastikan penyortiran terjadi di memori, parameter work_mem dapat digunakan. Parameter ini dapat dikonfigurasi ke nilai sedemikian rupa sehingga seluruh penyortiran dapat dilakukan dalam memori. Keuntungan inti dari parameter ini adalah, selain mengonfigurasinya di postgresql.conf, parameter ini juga dapat dikonfigurasi pada level sesi, level pengguna, atau level basis data. Berapa nilai work_mem yang seharusnya? Bagaimana cara mengetahui kueri mana yang melakukan penyortiran disk? Bagaimana cara memantau kueri yang melakukan penyortiran disk pada basis data produksi waktu nyata?
Jawabannya adalah - konfigurasikan parameter log_temp_files ke nilai tertentu. Nilainya dalam byte, nilai 0 mencatat semua file temp (bersama dengan ukurannya) yang dihasilkan pada disk karena penyortiran disk. Setelah parameter dikonfigurasi, Anda akan dapat melihat pesan berikut di file log
2018-06-07 22:48:02.358 IST [4219] LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp4219.0", size 200425472
2018-06-07 22:48:02.358 IST [4219] STATEMENT: create index bid_idx on pgbench_accounts(bid);
2018-06-07 22:48:02.366 IST [4219] LOG: duration: 6421.705 ms statement: create index bid_idx on pgbench_accounts(bid);
Pesan di atas berarti bahwa kueri CREATE INDEX sedang melakukan penyortiran disk dan telah menghasilkan file berukuran 200425472 byte yaitu 191+ MB. Artinya, parameter work_mem harus dikonfigurasi ke 191+ MB atau lebih untuk kueri khusus ini untuk melakukan pengurutan memori.
Nah, untuk query aplikasi, parameter work_mem hanya bisa dikonfigurasi di level pengguna. Sebelum melakukannya, waspadai jumlah koneksi yang dibuat pengguna ke database dan jumlah kueri pengurutan yang dijalankan oleh pengguna tersebut. Karena PostgreSQL mencoba mengalokasikan work_mem ke setiap proses (melakukan pengurutan) di setiap koneksi yang berpotensi membuat kehabisan memori di server database.
Tata letak sistem file database
Merancang tata letak sistem file database yang efisien dan kondusif adalah penting dari perspektif kinerja dan skalabilitas. Yang penting, ini tidak tergantung pada ukuran database. Secara umum, persepsi bahwa database ukuran besar akan membutuhkan arsitektur disk kinerja tinggi yang TIDAK benar. Bahkan jika ukuran database adalah 50 GB, Anda mungkin membutuhkan arsitektur disk yang baik. Dan ini tidak mungkin dilakukan tanpa menimbulkan biaya tambahan.
Berikut adalah beberapa TIPS untuk hal yang sama:
- Pastikan database memiliki beberapa tablespace, dengan tabel dan indeks yang dikelompokkan berdasarkan tarif transaksi.
- Ruang tabel harus ditempatkan di beberapa sistem file disk untuk I/O yang seimbang. Ini juga akan memastikan beberapa CPU ikut bermain untuk melakukan transaksi di beberapa disk.
- Pertimbangkan untuk menempatkan direktori pg_xlog atau pg_wal pada disk terpisah pada basis data transaksi tinggi.
- Pastikan *_parameter biaya dikonfigurasi berdasarkan infrastruktur
- Gunakan iostat, mpstat, dan alat pemantauan I/O lainnya untuk memahami statistik I/O di semua disk dan merancang/mengelola objek database yang sesuai.
PostgreSQL di Cloud
Infrastruktur sangat penting untuk kinerja database yang baik. Strategi rekayasa kinerja berbeda berdasarkan infrastruktur dan lingkungan. Perhatian khusus perlu diberikan untuk database PostgreSQL yang dihosting di cloud. Pembandingan kinerja untuk database yang dihosting di server barebone fisik di pusat data lokal bisa sangat berbeda dari database yang dihosting di cloud publik.
Secara umum, instance cloud bisa menjadi sedikit lebih lambat dan tolok ukur berbeda dengan margin yang cukup besar terutama dalam hal I/O. Selalu lakukan pemeriksaan latensi I/O sebelum memilih/membangun instans cloud. Yang mengejutkan saya, saya mengetahui bahwa kinerja instans cloud dapat bervariasi tergantung pada wilayah juga, meskipun mereka berasal dari penyedia cloud yang sama. Untuk menjelaskan hal ini lebih lanjut, instance cloud dengan spesifikasi yang sama yang dibuat di dua wilayah berbeda dapat memberikan hasil kinerja yang berbeda kepada Anda.
Pemuatan data massal
Operasi pemuatan data massal offline cukup umum di dunia database. Mereka dapat menghasilkan beban I/O yang signifikan, yang pada gilirannya memperlambat kinerja beban data. Saya telah menghadapi tantangan seperti itu dalam pengalaman saya sebagai DBA. Seringkali, pemuatan data menjadi sangat lambat dan harus disetel. Berikut adalah beberapa tips. Ingat, ini hanya berlaku untuk operasi pemuatan data offline dan tidak dapat dipertimbangkan untuk pemuatan data pada database produksi langsung.
- Karena sebagian besar operasi pemuatan data dilakukan di luar jam kerja, pastikan parameter berikut dikonfigurasi selama pemuatan data -
- Konfigurasikan nilai terkait pos pemeriksaan yang cukup besar sehingga pos pemeriksaan tidak menyebabkan masalah kinerja apa pun.
- Nonaktifkan full_page_write
- Nonaktifkan pengarsipan wal
- Konfigurasikan parameter synchronous_commit ke “nonaktif”
- Lepaskan batasan dan indeks untuk tabel yang dikenai beban data (Konstrain dan indeks dapat dibuat ulang setelah memuat data dengan nilai work_mem yang lebih besar)
- Jika Anda melakukan pemuatan data dari file CSV, maintenance_work_mem yang lebih besar dapat memberikan hasil yang baik untuk Anda.
- Meskipun akan ada manfaat kinerja yang signifikan, JANGAN matikan parameter fsync karena dapat menyebabkan kerusakan data.
TIPS untuk analisis kinerja cloud
- Lakukan uji latensi I/O menyeluruh menggunakan pgbench. Dalam pengalaman saya, saya mendapatkan hasil kinerja yang cukup biasa ketika melakukan pemeriksaan latensi disk sebagai bagian dari evaluasi TPS. Ada masalah dengan kinerja cache pada beberapa instance cloud publik. Ini akan membantu memilih spesifikasi yang sesuai untuk instance cloud yang dipilih untuk database.
- Instance cloud dapat bekerja secara berbeda dari satu wilayah ke wilayah lainnya. Instans cloud dengan spesifikasi tertentu di suatu wilayah dapat memberikan hasil kinerja yang berbeda dibandingkan dengan instans cloud dengan spesifikasi yang sama di wilayah lain. Tes pgbench saya yang dijalankan pada beberapa instance cloud (semua spesifikasi yang sama dengan vendor cloud yang sama) di berbagai wilayah memberi saya hasil yang berbeda pada beberapa di antaranya. Ini penting terutama saat Anda bermigrasi ke cloud.
- Kinerja kueri di cloud mungkin memerlukan pendekatan penyesuaian yang berbeda. DBA perlu menggunakan *_parameter biaya untuk memastikan rencana eksekusi kueri yang sehat dihasilkan.
Alat untuk Memantau Kinerja PostgreSQL
There are various tools to monitor PostgreSQL performance. Let me highlight some of those.
- pg_top is a GREAT tool to monitor PostgreSQL database dynamically. I would highly recommend this tool for DBAs for various reasons. This tool has numerous advantages, let me list them out:
- pg_top tool uses textual interface and is similar to Unix “top” utility.
- Will clearly list out the processes and the hardware resources utilized. What excites me with this tool is that it will clearly tell you if a particular process is currently on DISK or CPU - in my view that’s excellent. DBAs can clearly pick the process running for longer time on the disk.
- You can check the EXPLAIN PLAN of the top SQLs dynamically or instantly
- You can also find out what Tables or Indexes are being scanned instantly
- Nagios is a popular monitoring tool for PostgreSQL which has both open-source and commercial versions. Open source version should suffice for monitoring. Custom Perl scripts can be built and plugged into Nagios module.
- Pgbadger is a popular tool which can be used to analyze PostgreSQL log files and generate performance reports. This report can be used to analyze the performance of checkpoints, disk sorting.
- Zabbix is another popular tool used for PostgreSQL monitoring.
ClusterControl is an up-and-coming management platform for PostgreSQL. Apart from monitoring, it also has functionality to deploy replication setups with load balancers, automatic failover, backup management, among others.