Di dunia Postgres, indeks sangat penting untuk menavigasi repositori basis data secara efisien (disebut heap, heap). Postgres tidak mendukung pengelompokan untuk itu, dan arsitektur MVCC menyebabkan Anda mengumpulkan banyak versi dari tuple yang sama. Oleh karena itu, sangat penting untuk dapat membuat dan memelihara indeks yang efektif untuk mendukung aplikasi.
Berikut adalah beberapa kiat untuk mengoptimalkan dan meningkatkan penggunaan indeks.
Catatan: kueri yang ditampilkan di bawah ini berfungsi pada database sampel pagila yang tidak dimodifikasi.Menggunakan Covering Indexes
Mari kita tinjau permintaan untuk mengambil alamat email untuk pengguna yang tidak aktif. Tabel
customer
memiliki kolom
active
, dan permintaannya sederhana:
pagila=
Permintaan meminta urutan lengkap pemindaian tabel
customer
. Mari kita buat indeks untuk kolom
active
:
pagila=
Ini membantu, pemindaian selanjutnya berubah menjadi "
index scan
". Ini berarti Postgres akan memindai indeks
idx_cust1
, dan kemudian melanjutkan mencari tumpukan tabel untuk membaca nilai-nilai kolom lain (dalam hal ini, kolom
email
) yang dibutuhkan oleh kueri.
PostgreSQL 11 diperkenalkan meliputi indeks. Mereka memungkinkan Anda untuk memasukkan satu atau lebih kolom tambahan dalam indeks itu sendiri - nilainya disimpan dalam penyimpanan data indeks.
Jika kami menggunakan fitur ini dan menambahkan nilai email di dalam indeks, maka Postgres tidak perlu mencari nilai
email
di tumpukan tabel. Mari kita lihat apakah ini bekerja:
pagila=
"
Index Only Scan
" memberi tahu kita bahwa permintaan sekarang hanya membutuhkan satu indeks, yang membantu menghindari semua disk I / O untuk membaca tumpukan tabel.
Hari ini, indeks penutupan hanya tersedia untuk pohon-B. Namun, dalam hal ini, upaya pengawalan akan lebih tinggi.
Menggunakan indeks parsial
Indeks parsial hanya mengindeks sebagian dari baris dalam tabel. Ini menghemat ukuran indeks dan pemindaian lebih cepat.
Misalkan kita perlu mendapatkan daftar alamat email dari pelanggan California kami. Permintaan akan seperti ini:
SELECT c.email FROM customer c JOIN address a ON c.address_id = a.address_id WHERE a.district = 'California'; which has a query plan that involves scanning both the tables that are joined: pagila=
Apa yang biasa diberikan indeks kepada kami:
pagila=
Pemindaian
address
digantikan oleh
idx_address1
indeks
idx_address1
, dan kemudian tumpukan
address
dipindai.
Karena ini adalah kueri yang sering dan perlu dioptimalkan, kami dapat menggunakan indeks parsial yang hanya mengindeks baris-baris dengan alamat di mana wilayah
'California'
:
pagila=
Sekarang permintaan hanya membaca
idx_address2
dan tidak menyentuh tabel
address
.
Menggunakan Indeks Multi-Nilai
Beberapa kolom yang perlu diindeks mungkin tidak mengandung tipe data skalar. Jenis
jsonb
seperti
jsonb
,
arrays
dan
tsvector
berisi beberapa nilai. Jika Anda perlu mengindeks kolom tersebut, Anda biasanya harus mencari semua nilai individual di kolom ini.
Mari kita coba menemukan nama-nama semua film yang berisi potongan dari pengambilan yang tidak berhasil. Tabel
film
memiliki kolom teks yang disebut
special_features
. Jika film memiliki "properti khusus" ini, maka kolom berisi elemen dalam bentuk array teks
Behind The Scenes
. Untuk mencari semua film semacam itu, kita perlu memilih semua baris dengan "Di Balik Layar" untuk nilai
apa pun dari array
special_features
:
SELECT title FROM film WHERE special_features @> '{"Behind The Scenes"}';
Operator kontainmen
@>
memeriksa untuk melihat apakah sisi kanan adalah subset dari sisi kiri.
Paket Permintaan:
pagila=
Yang meminta pemindaian tumpukan penuh dengan biaya 67.
Mari kita lihat apakah indeks B-tree reguler membantu kita:
pagila=
Indeks itu bahkan tidak dipertimbangkan. Indeks B-tree tidak menyadari keberadaan elemen individu dalam nilai yang diindeks.
Kami membutuhkan indeks GIN.
pagila=
GIN-index mendukung perbandingan nilai individu dengan nilai komposit terindeks, sebagai akibatnya, biaya rencana kueri berkurang lebih dari setengah.
Singkirkan indeks rangkap
Indeks terakumulasi dari waktu ke waktu, dan terkadang indeks baru mungkin berisi definisi yang sama dengan yang sebelumnya. Untuk mendapatkan definisi indeks yang dapat dibaca manusia, Anda dapat menggunakan
pg_indexes
tampilan katalog. Anda juga dapat dengan mudah menemukan definisi yang sama:
SELECT array_agg(indexname) AS indexes, replace(indexdef, indexname, '') AS defn FROM pg_indexes GROUP BY defn HAVING count(*) > 1; And here's the result when run on the stock pagila database: pagila=
Indeks Superset
Mungkin terjadi bahwa Anda mengumpulkan banyak indeks, salah satunya indeks bagian dari kolom yang indeks indeks lainnya. Ini bisa baik diinginkan atau tidak - superset hanya dapat memindai berdasarkan indeks, yang bagus, tetapi dapat memakan banyak ruang, atau permintaan yang superset ini dimaksudkan untuk dioptimalkan tidak lagi digunakan.
Jika Anda perlu mengotomatiskan definisi indeks tersebut, Anda bisa mulai dengan
pg_index dari tabel
pg_catalog
.
Indeks yang Tidak Digunakan
Saat aplikasi yang menggunakan basis data berkembang, demikian juga kueri yang mereka gunakan. Indeks yang ditambahkan sebelumnya mungkin tidak lagi digunakan oleh permintaan apa pun. Setiap kali indeks dipindai, itu ditandai oleh manajer statistik, dan dalam
pg_stat_user_indexes
katalog sistem
pg_stat_user_indexes
Anda dapat melihat nilai
idx_scan
, yang merupakan penghitung kumulatif. Melacak nilai ini selama periode waktu tertentu (katakanlah, sebulan) akan memberikan ide bagus tentang indeks mana yang tidak digunakan dan dapat dihapus.
Berikut adalah permintaan untuk mendapatkan jumlah pemindaian saat ini dari semua indeks dalam skema
'public'
:
SELECT relname, indexrelname, idx_scan FROM pg_catalog.pg_stat_user_indexes WHERE schemaname = 'public'; with output like this: pagila=
Buat kembali indeks dengan kunci lebih sedikit
Seringkali indeks harus dibuat ulang, misalnya ketika ukurannya digelembungkan, dan pembuatan ulang dapat mempercepat pemindaian. Juga, indeks mungkin rusak. Mengubah parameter indeks mungkin juga perlu membuatnya kembali.
Aktifkan pembuatan indeks paralel
Di PostgreSQL 11, membuat indeks B-Tree kompetitif. Untuk mempercepat proses pembuatan, beberapa pekerja paralel dapat digunakan. Namun, pastikan bahwa parameter konfigurasi ini diatur dengan benar:
SET max_parallel_workers = 32; SET max_parallel_maintenance_workers = 16;
Nilai default terlalu kecil. Idealnya, angka-angka ini harus ditambah seiring dengan jumlah inti prosesor. Baca
dokumentasi untuk lebih jelasnya.
Pembuatan Indeks Latar Belakang
Anda dapat membuat indeks di latar belakang menggunakan parameter
CONCURRENTLY
dari perintah
CREATE INDEX
:
pagila=
Prosedur pembuatan indeks ini berbeda dari yang biasa karena tidak memerlukan penguncian tabel, dan karenanya tidak memblokir operasi penulisan. Di sisi lain, dibutuhkan lebih banyak waktu dan menghabiskan lebih banyak sumber daya.
Postgres menyediakan banyak opsi fleksibel untuk membuat indeks dan cara untuk menyelesaikan kasus tertentu, serta menyediakan cara untuk mengelola basis data jika terjadi ledakan pertumbuhan aplikasi Anda. Kami harap tips ini akan membantu Anda membuat kueri Anda lebih cepat dan database Anda siap untuk ditingkatkan.