Kinerja adalah salah satu tugas paling penting dan paling kompleks saat mengelola database. Itu dapat dipengaruhi oleh konfigurasi, perangkat keras atau bahkan desain sistem. Secara default, PostgreSQL dikonfigurasi dengan mempertimbangkan kompatibilitas dan stabilitas, karena kinerjanya sangat bergantung pada perangkat keras dan pada sistem kami sendiri. Kita dapat memiliki sistem dengan banyak data yang dibaca tetapi informasinya tidak sering berubah. Atau kita dapat memiliki sistem yang menulis terus menerus. Karena alasan ini, tidak mungkin untuk menentukan konfigurasi default yang berfungsi untuk semua jenis beban kerja.
Di blog ini, kita akan melihat bagaimana cara menganalisis beban kerja, atau kueri, yang sedang berjalan. Kami kemudian akan meninjau beberapa parameter konfigurasi dasar untuk meningkatkan kinerja database PostgreSQL kami. Seperti yang kami sebutkan, kami hanya akan melihat beberapa parameter. Daftar parameter PostgreSQL sangat luas, kami hanya akan menyentuh beberapa yang utama. Namun, seseorang selalu dapat berkonsultasi dengan dokumentasi resmi untuk mempelajari parameter dan konfigurasi yang tampaknya paling penting atau berguna di lingkungan kita.
Jelaskan
Salah satu langkah awal yang dapat kita lakukan untuk memahami bagaimana meningkatkan kinerja database kita adalah dengan menganalisis query yang dibuat.
PostgreSQL menyusun rencana kueri untuk setiap kueri yang diterimanya. Untuk melihat rencana ini, kita akan menggunakan EXPLAIN.
Struktur rencana kueri adalah pohon simpul rencana. Node di tingkat yang lebih rendah dari pohon adalah scan node. Mereka mengembalikan baris mentah dari sebuah tabel. Ada berbagai jenis node pemindaian untuk metode yang berbeda dalam mengakses tabel. Keluaran EXPLAIN memiliki garis untuk setiap simpul di pohon rencana.
world=# EXPLAIN SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
QUERY PLAN
--------------------------------------------------------------------------
Nested Loop (cost=0.00..734.81 rows=50662 width=144)
-> Seq Scan on city t1 (cost=0.00..93.19 rows=347 width=31)
Filter: ((id > 100) AND (population > 700000))
-> Materialize (cost=0.00..8.72 rows=146 width=113)
-> Seq Scan on country t2 (cost=0.00..7.99 rows=146 width=113)
Filter: (population < 7000000)
(6 rows)
Perintah ini menunjukkan bagaimana tabel dalam kueri kita akan dipindai. Mari kita lihat apa yang sesuai dengan nilai-nilai ini yang dapat kita amati di EXPLAIN kita.
- Parameter pertama menunjukkan operasi yang dilakukan mesin pada data dalam langkah ini.
- Perkiraan biaya awal. Ini adalah waktu yang dihabiskan sebelum fase keluaran dapat dimulai.
- Perkiraan total biaya. Hal ini dinyatakan dengan asumsi bahwa node rencana dijalankan sampai selesai. Dalam praktiknya, node induk sebuah node mungkin berhenti membaca semua baris yang tersedia.
- Perkiraan jumlah baris yang dihasilkan oleh node rencana ini. Sekali lagi, node diasumsikan dijalankan sampai selesai.
- Perkiraan lebar rata-rata keluaran baris oleh simpul rencana ini.
Bagian paling penting dari tampilan adalah perkiraan biaya eksekusi pernyataan, yang merupakan perkiraan perencana berapa lama waktu yang dibutuhkan untuk menjalankan pernyataan. Saat membandingkan seberapa efektif satu kueri dengan kueri lainnya, dalam praktiknya kami akan membandingkan nilai biayanya.
Penting untuk dipahami bahwa biaya node tingkat atas mencakup biaya semua node turunannya. Penting juga untuk menyadari bahwa biaya hanya mencerminkan hal-hal yang diperhatikan oleh perencana. Secara khusus, biaya tidak mempertimbangkan waktu yang dihabiskan untuk mentransmisikan baris hasil ke klien, yang dapat menjadi faktor penting dalam waktu yang telah berlalu secara nyata; tetapi perencana mengabaikannya karena tidak dapat mengubahnya dengan mengubah rencana.
Biaya diukur dalam unit arbitrer yang ditentukan oleh parameter biaya perencana. Praktik tradisional adalah mengukur biaya dalam unit pengambilan halaman disk; yaitu, seq_page_cost secara konvensional disetel ke 1.0 dan parameter biaya lainnya disetel relatif terhadap itu.
Jelaskan ANALISIS
Dengan opsi ini, EXPLAIN mengeksekusi kueri, lalu menampilkan jumlah baris yang sebenarnya dan waktu proses sebenarnya yang terakumulasi dalam setiap node rencana, bersama dengan perkiraan yang sama yang ditunjukkan oleh EXPLAIN biasa.
Mari kita lihat contoh penggunaan alat ini.
world=# EXPLAIN ANALYZE SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..734.81 rows=50662 width=144) (actual time=0.081..22.066 rows=51100 loops=1)
-> Seq Scan on city t1 (cost=0.00..93.19 rows=347 width=31) (actual time=0.069..0.618 rows=350 loops=1)
Filter: ((id > 100) AND (population > 700000))
Rows Removed by Filter: 3729
-> Materialize (cost=0.00..8.72 rows=146 width=113) (actual time=0.000..0.011 rows=146 loops=350)
-> Seq Scan on country t2 (cost=0.00..7.99 rows=146 width=113) (actual time=0.007..0.058 rows=146 loops=1)
Filter: (population < 7000000)
Rows Removed by Filter: 93
Planning time: 0.136 ms
Execution time: 24.627 ms
(10 rows)
Jika kami tidak menemukan alasan mengapa kueri kami memakan waktu lebih lama dari yang seharusnya, kami dapat memeriksa blog ini untuk informasi lebih lanjut.
VAKUUM
Proses VACUUM bertanggung jawab untuk beberapa tugas pemeliharaan dalam database, salah satunya memulihkan penyimpanan yang ditempati oleh tupel mati. Dalam operasi normal PostgreSQL, tupel yang dihapus atau usang oleh pembaruan tidak dihapus secara fisik dari tabelnya; mereka tetap hadir sampai VACUUM dilakukan. Oleh karena itu, perlu dilakukan VACUUM secara berkala terutama pada tabel yang sering diupdate.
Jika VACUUM menghabiskan terlalu banyak waktu atau sumber daya, itu berarti kita harus melakukannya lebih sering, sehingga setiap operasi memiliki lebih sedikit waktu untuk dibersihkan.
Bagaimanapun, Anda mungkin perlu menonaktifkan VACUUM, misalnya saat memuat data dalam jumlah besar.
VACUUM hanya memulihkan ruang dan membuatnya tersedia untuk digunakan kembali. Bentuk perintah ini dapat beroperasi secara paralel dengan pembacaan dan penulisan tabel yang normal, karena kunci eksklusif tidak diperoleh. Namun, ruang tambahan tidak dikembalikan ke sistem operasi (dalam banyak kasus); itu hanya tersedia untuk digunakan kembali dalam tabel yang sama.
VACUUM FULL menulis ulang semua isi tabel dalam file disk baru tanpa ruang tambahan, yang memungkinkan ruang yang tidak terpakai untuk kembali ke sistem operasi. Formulir ini jauh lebih lambat dan memerlukan kunci eksklusif di setiap tabel saat memproses.
VACUUM ANALYZE melakukan VACUUM dan kemudian ANALYZE untuk setiap tabel yang dipilih. Ini adalah cara praktis untuk menggabungkan skrip pemeliharaan rutin.
ANALYZE mengumpulkan statistik tentang isi tabel dalam database dan menyimpan hasilnya di pg_statistic. Selanjutnya, perencana kueri menggunakan statistik ini untuk membantu menentukan rencana eksekusi kueri yang paling efisien.
Unduh Whitepaper Hari Ini Pengelolaan &Otomatisasi PostgreSQL dengan ClusterControlPelajari tentang apa yang perlu Anda ketahui untuk menerapkan, memantau, mengelola, dan menskalakan PostgreSQLUnduh WhitepaperParameter konfigurasi
Untuk memodifikasi parameter tersebut kita harus mengedit file $PGDATA /postgresql.conf. Kita harus ingat bahwa beberapa dari mereka memerlukan restart database kita.
koneksi_maks
Menentukan jumlah maksimum koneksi simultan ke database kami. Ada sumber daya memori yang dapat dikonfigurasi per klien, oleh karena itu, jumlah maksimum klien dapat menyarankan jumlah maksimum memori yang digunakan.
koneksi_pengguna_super
Jika mencapai batas max_connection, koneksi ini dicadangkan untuk superuser.
shared_buffers
Menetapkan jumlah memori yang digunakan server database untuk buffer memori bersama. Jika Anda memiliki server database khusus dengan RAM 1 GB atau lebih, nilai awal yang masuk akal untuk shared_buffers adalah 25% dari memori sistem Anda. Konfigurasi yang lebih besar untuk shared_buffers umumnya memerlukan peningkatan max_wal_size yang sesuai, untuk memperpanjang proses penulisan data baru atau yang dimodifikasi dalam jumlah besar dalam jangka waktu yang lebih lama.
temp_buffers
Menetapkan jumlah maksimum buffer sementara yang digunakan untuk setiap sesi. Ini adalah buffer sesi lokal yang digunakan hanya untuk mengakses tabel sementara. Sesi akan menetapkan buffer sementara sesuai kebutuhan hingga batas yang diberikan oleh temp_buffers.
work_mem
Menentukan jumlah memori yang akan digunakan oleh operasi internal tabel ORDER BY, DISTINCT, JOIN, dan hash sebelum menulis ke file sementara pada disk. Saat mengonfigurasi nilai ini, kita harus memperhitungkan bahwa beberapa sesi menjalankan operasi ini secara bersamaan dan setiap operasi akan diizinkan untuk menggunakan memori sebanyak yang ditentukan oleh nilai ini sebelum mulai menulis data dalam file sementara.
Opsi ini disebut sort_mem di versi PostgreSQL yang lebih lama.
maintenance_work_mem
Menentukan jumlah maksimum memori yang akan digunakan operasi pemeliharaan, seperti VACUUM, CREATE INDEX, dan ALTER TABLE ADD FOREIGN KEY. Karena hanya satu dari operasi ini yang dapat dijalankan pada waktu yang sama oleh sebuah sesi, dan instalasi biasanya tidak memiliki banyak operasi yang berjalan secara bersamaan, itu bisa lebih besar dari work_mem. Konfigurasi yang lebih besar dapat meningkatkan kinerja untuk VACUUM dan pemulihan database.
Saat autovacuum dijalankan, memori ini dapat ditetapkan berapa kali parameter autovacuum_max_workers dikonfigurasi, jadi kita harus memperhitungkannya, atau sebaliknya, konfigurasikan parameter autovacuum_work_mem untuk mengelola ini secara terpisah.
fsinkron
Jika fsync diaktifkan, PostgreSQL akan mencoba memastikan bahwa pembaruan secara fisik ditulis ke disk. Ini memastikan bahwa klaster database dapat dipulihkan ke status yang konsisten setelah sistem operasi atau perangkat keras mogok.
Meskipun menonaktifkan fsync umumnya meningkatkan kinerja, ini dapat menyebabkan hilangnya data jika terjadi kegagalan daya atau sistem crash. Oleh karena itu, disarankan untuk menonaktifkan fsync hanya jika Anda dapat dengan mudah membuat ulang seluruh basis data dari data eksternal.
checkpoint_segments (PostgreSQL <9.5)
Jumlah maksimum segmen file rekaman antara titik kontrol WAL otomatis (setiap segmen biasanya 16 megabita). Meningkatkan parameter ini dapat meningkatkan jumlah waktu yang dibutuhkan untuk memulihkan kesalahan. Dalam sistem dengan banyak lalu lintas, dapat mempengaruhi kinerja jika diatur ke nilai yang sangat rendah. Direkomendasikan untuk meningkatkan nilai checkpoint_segments pada sistem dengan banyak modifikasi data.
Selain itu, praktik yang baik adalah menyimpan file WAL pada disk selain PGDATA. Ini berguna untuk menyeimbangkan penulisan dan untuk keamanan jika terjadi kegagalan perangkat keras.
Pada PostgreSQL 9.5 variabel konfigurasi "checkpoint_segments" telah dihapus, dan digantikan oleh "max_wal_size" dan "min_wal_size"
max_wal_size (PostgreSQL>=9.5)
Ukuran maksimum WAL diperbolehkan untuk tumbuh di antara titik kontrol. Ukuran WAL dapat melebihi max_wal_size dalam keadaan khusus. Meningkatkan parameter ini dapat meningkatkan jumlah waktu yang dibutuhkan untuk memulihkan kesalahan.
min_wal_size (PostgreSQL>=9.5)
Saat file WAL disimpan di bawah nilai ini, file tersebut akan didaur ulang untuk digunakan di masa mendatang di pos pemeriksaan, alih-alih dihapus. Ini dapat digunakan untuk memastikan bahwa cukup ruang WAL dicadangkan untuk menangani lonjakan penggunaan WAL, misalnya saat menjalankan tugas batch besar.
wal_sync_method
Metode yang digunakan untuk memaksa pembaruan WAL ke disk. Jika fsync dinonaktifkan, pengaturan ini tidak akan berpengaruh.
wal_buffers
Jumlah memori bersama yang digunakan untuk data WAL yang belum ditulis ke disk. Pengaturan default adalah sekitar 3% dari shared_buffers, tidak kurang dari 64KB atau lebih dari ukuran segmen WAL (biasanya 16MB). Menyetel nilai ini ke setidaknya beberapa MB dapat meningkatkan kinerja penulisan di server dengan banyak transaksi bersamaan.
efektif_cache_size
Nilai ini digunakan oleh perencana kueri untuk memperhitungkan rencana akun yang mungkin atau mungkin tidak sesuai dengan memori. Ini diperhitungkan dalam perkiraan biaya menggunakan indeks; nilai yang tinggi membuat pemindaian indeks lebih mungkin digunakan dan nilai yang rendah membuat pemindaian berurutan lebih mungkin digunakan. Nilai yang wajar adalah 50% dari RAM.
default_statistics_target
PostgreSQL mengumpulkan statistik dari setiap tabel dalam databasenya untuk memutuskan bagaimana kueri akan dieksekusi pada tabel tersebut. Secara default, tidak mengumpulkan terlalu banyak informasi, dan jika Anda tidak mendapatkan rencana eksekusi yang baik, Anda harus meningkatkan nilai ini dan kemudian menjalankan ANALYZE dalam database lagi (atau menunggu AUTOVACUUM).
synchronous_commit
Menentukan apakah komit transaksi akan menunggu catatan WAL ditulis ke disk sebelum perintah mengembalikan indikasi "berhasil" ke klien. Nilai yang mungkin adalah:"on", "remote_apply", "remote_write", "local" dan "off". Pengaturan default adalah "aktif". Saat dinonaktifkan, mungkin ada penundaan antara waktu klien kembali, dan saat transaksi dijamin aman terhadap kunci server. Tidak seperti fsync, menonaktifkan parameter ini tidak menimbulkan risiko inkonsistensi basis data:kerusakan sistem operasi atau basis data dapat mengakibatkan hilangnya beberapa transaksi terbaru yang diduga dilakukan, tetapi status basis data akan sama persis seperti jika transaksi tersebut telah dibatalkan dengan bersih. Oleh karena itu, menonaktifkan synchronous_commit dapat menjadi alternatif yang berguna ketika kinerja lebih penting daripada kepastian yang tepat tentang ketahanan transaksi.
Log
Ada beberapa jenis data untuk dicatat yang mungkin berguna atau tidak. Mari kita lihat beberapa di antaranya:
- log_min_error_statement:Menyetel tingkat pencatatan minimum.
- log_min_duration_statement:Digunakan untuk merekam kueri lambat dalam sistem.
- log_line_prefix:Mematuhi informasi di awal setiap baris log.
- log_statement:Anda dapat memilih antara NONE, DDL, MOD, ALL. Menggunakan "semua" dapat menyebabkan masalah kinerja.
Desain
Dalam banyak kasus, desain database kami dapat memengaruhi kinerja. Kami harus berhati-hati dalam desain kami, menormalkan skema kami dan menghindari data yang berlebihan. Dalam banyak kasus, lebih mudah untuk memiliki beberapa meja kecil daripada satu meja besar. Tapi seperti yang kami katakan sebelumnya, semuanya tergantung pada sistem kami dan tidak ada satu solusi pun yang mungkin.
Kita juga harus menggunakan indeks secara bertanggung jawab. Kami tidak boleh membuat indeks untuk setiap bidang atau kombinasi bidang, karena, meskipun kami tidak harus menjelajahi seluruh tabel, kami menggunakan ruang disk dan menambahkan overhead untuk menulis operasi.
Alat lain yang sangat berguna adalah pengelolaan kumpulan koneksi. Jika kita memiliki sistem dengan banyak beban, kita dapat menggunakan ini untuk menghindari kejenuhan koneksi dalam database dan untuk dapat menggunakannya kembali.
Perangkat Keras
Seperti yang kami sebutkan di awal blog ini, perangkat keras adalah salah satu faktor penting yang secara langsung mempengaruhi kinerja database kami. Mari kita lihat beberapa poin yang perlu diingat.
- Memori:Semakin banyak RAM yang kita miliki, semakin banyak data memori yang dapat kita tangani, dan itu berarti kinerja yang lebih baik. Kecepatan menulis dan membaca di disk jauh lebih lambat daripada di memori, oleh karena itu, semakin banyak informasi yang kita miliki di memori, semakin baik kinerja yang kita miliki.
- CPU:Mungkin tidak masuk akal untuk mengatakan ini, tetapi semakin banyak CPU yang kita miliki, semakin baik. Bagaimanapun itu bukan yang terpenting dalam hal perangkat keras, tetapi jika kita dapat memiliki CPU yang baik, kapasitas pemrosesan kita akan meningkat dan itu berdampak langsung pada database kita.
- Hard disk:Kami memiliki beberapa jenis disk yang dapat kami gunakan, SCSI, SATA, SAS, IDE. Kami juga memiliki disk solid state. Kita harus membandingkan kualitas / harga, yang harus kita gunakan untuk membandingkan kecepatannya. Tetapi jenis disk bukan satu-satunya hal yang perlu dipertimbangkan, kita juga harus melihat cara mengkonfigurasinya. Jika kita menginginkan kinerja yang baik, kita dapat menggunakan RAID10, menyimpan WAL di disk lain di luar RAID. Tidak disarankan untuk menggunakan RAID5 karena kinerja RAID jenis ini untuk database tidak baik.
Kesimpulan
Setelah mempertimbangkan poin-poin yang disebutkan di blog ini, kami dapat melakukan benchmark untuk memverifikasi perilaku database.
Penting juga untuk memiliki basis data kami yang dipantau untuk menentukan apakah kami menghadapi masalah kinerja dan untuk dapat menyelesaikannya sesegera mungkin. Untuk tugas ini ada beberapa alat seperti Nagios, ClusterControl atau Zabbix, antara lain, yang memungkinkan kita tidak hanya untuk memantau, tetapi dengan beberapa di antaranya, memungkinkan kita untuk mengambil tindakan proaktif sebelum masalah terjadi. Dengan ClusterControl, selain pemantauan, administrasi, dan beberapa utilitas lainnya, kami dapat menerima rekomendasi tentang tindakan apa yang dapat kami ambil saat menerima peringatan kinerja. Hal ini memungkinkan kami untuk memiliki gagasan tentang cara memecahkan masalah potensial.
Blog ini tidak dimaksudkan sebagai panduan lengkap tentang cara meningkatkan kinerja basis data. Semoga memberikan gambaran yang lebih jelas tentang hal-hal apa saja yang dapat menjadi penting dan beberapa parameter dasar yang dapat dikonfigurasi. Jangan ragu untuk memberi tahu kami jika kami melewatkan satu hal penting.