Bagaimana cara saya memaksa Postgres untuk menggunakan indeks yang sebaliknya akan bersikeras melakukan pemindaian berurutan?
sql
postgresql
indexing
mike
sumber
sumber
Jawaban:
Dengan asumsi Anda bertanya tentang fitur "petunjuk indeks" yang umum ditemukan di banyak database, PostgreSQL tidak menyediakan fitur seperti itu. Ini adalah keputusan sadar yang dibuat oleh tim PostgreSQL. Gambaran umum yang baik tentang mengapa dan apa yang dapat Anda lakukan dapat ditemukan di sini . Alasannya pada dasarnya karena ini adalah peretasan kinerja yang cenderung menyebabkan lebih banyak masalah di kemudian hari seiring dengan perubahan data Anda, sedangkan pengoptimal PostgreSQL dapat mengevaluasi ulang rencana berdasarkan statistik. Dengan kata lain, apa yang mungkin menjadi rencana kueri yang baik saat ini mungkin tidak akan menjadi rencana kueri yang baik untuk semua waktu, dan petunjuk indeks memaksa rencana kueri tertentu untuk sepanjang waktu.
Sebagai palu yang sangat tumpul, berguna untuk pengujian, Anda dapat menggunakan parameter
enable_seqscan
danenable_indexscan
. Lihat:enable_
parameterIni tidak cocok untuk penggunaan produksi yang berkelanjutan . Jika Anda memiliki masalah dengan pilihan paket kueri, Anda akan melihat dokumentasi untuk melacak masalah kinerja kueri . Jangan hanya mengatur
enable_
parameter dan pergi begitu saja.Kecuali Anda memiliki alasan yang sangat bagus untuk menggunakan indeks, Postgres mungkin membuat pilihan yang tepat. Mengapa?
Lihat juga posting grup berita lama ini .
sumber
Mungkin satu-satunya alasan yang valid untuk menggunakan
adalah saat Anda menulis kueri dan ingin segera melihat apa rencana kueri sebenarnya jika ada data dalam jumlah besar di tabel. Atau tentu saja jika Anda perlu segera mengonfirmasi bahwa kueri Anda tidak menggunakan indeks hanya karena kumpulan data terlalu kecil.
sumber
set enable_seqscan=false
, jalankan kueri Anda, lalu jalankan dengan cepatset enable_seqscan=true
untuk mengembalikan postgresql ke perilaku yang semestinya (dan jelas jangan lakukan ini dalam produksi, hanya dalam pengembangan!)SET SESSION enable_seqscan=false
untuk hanya mempengaruhi diri sendiriTerkadang PostgreSQL gagal membuat pilihan indeks terbaik untuk kondisi tertentu. Sebagai contoh, misalkan ada tabel transaksi dengan beberapa juta baris, yang jumlahnya beberapa ratus untuk hari tertentu, dan tabel tersebut memiliki empat indeks: transaction_id, client_id, date, dan description. Anda ingin menjalankan kueri berikut:
PostgreSQL dapat memilih untuk menggunakan indeks transaction_description_idx daripada transaction_date_idx, yang dapat menyebabkan kueri membutuhkan waktu beberapa menit alih-alih kurang dari satu detik. Jika demikian, Anda dapat memaksa menggunakan indeks pada tanggal dengan memalsukan kondisi seperti ini:
sumber
your_wanted_index
, bisa jadi mesin postgresql hanya akan melakukan pemindaian urutan / kunci primer saja. Kesimpulan - tidak ada metode yang 100% dapat diandalkan untuk memaksa beberapa penggunaan indeks untuk server PostgreSql.where
kondisi kecuali dua tabel atau bergabung dan Postgres gagal mengambil indeks.Jawaban singkat
Masalah ini biasanya terjadi ketika perkiraan biaya pemindaian indeks terlalu tinggi dan tidak mencerminkan kenyataan dengan benar. Anda mungkin perlu menurunkan
random_page_cost
parameter konfigurasi untuk memperbaikinya. Dari dokumentasi Postgres :Anda dapat memeriksa apakah nilai yang lebih rendah benar-benar akan membuat Postgres menggunakan indeks (tetapi gunakan ini hanya untuk pengujian ):
Anda dapat mengembalikan nilai default dengan
SET random_page_cost = DEFAULT;
lagi.Latar Belakang
Pemindaian indeks memerlukan pengambilan halaman disk yang tidak berurutan. Postgres menggunakan
random_page_cost
untuk memperkirakan biaya pengambilan tidak berurutan dalam kaitannya dengan pengambilan berurutan. Nilai defaultnya adalah4.0
, dengan demikian mengasumsikan faktor biaya rata - rata 4 dibandingkan dengan pengambilan berurutan (dengan mempertimbangkan efek cache).Namun masalahnya adalah bahwa nilai default ini tidak sesuai dalam skenario penting kehidupan nyata berikut ini:
1) Drive solid-state
Seperti yang diakui dalam dokumentasi:
Menurut poin terakhir slide ini dari pidato di PostgresConf 2018,
random_page_cost
harus diatur ke sesuatu antara1.0
dan2.0
untuk solid-state drive.2) Data cache
Jika data indeks yang diperlukan sudah disimpan dalam cache dalam RAM, pemindaian indeks akan selalu jauh lebih cepat daripada pemindaian sekuensial. Dokumentasinya mengatakan:
Masalahnya adalah Anda tentu tidak dapat dengan mudah mengetahui apakah data yang relevan sudah di-cache. Namun, jika indeks tertentu sering ditanyakan, dan jika sistem memiliki RAM yang memadai, maka data kemungkinan besar akan di-cache, dan
random_page_cost
harus disetel ke nilai yang lebih rendah. Anda harus bereksperimen dengan nilai yang berbeda dan melihat mana yang berhasil untuk Anda.Anda mungkin juga ingin menggunakan ekstensi pg_prewarm untuk cache data eksplisit.
sumber
Pertanyaan itu sendiri sangat tidak valid. Memaksa (dengan melakukan enable_seqscan = off misalnya) adalah ide yang sangat buruk. Mungkin berguna untuk memeriksa apakah itu akan lebih cepat, tetapi kode produksi tidak boleh menggunakan trik seperti itu.
Sebagai gantinya - jelaskan analisis kueri Anda, baca, dan cari tahu mengapa PostgreSQL memilih paket yang buruk (menurut pendapat Anda).
Ada alat di web yang membantu membaca menjelaskan hasil analisis - salah satunya adalah menjelaskan.depesz.com - yang ditulis oleh saya.
Pilihan lainnya adalah bergabung dengan saluran #postgresql di jaringan irc freenode , dan berbicara dengan orang-orang di sana untuk membantu Anda - karena mengoptimalkan kueri bukanlah masalah "ajukan pertanyaan, dapatkan jawaban dengan senang hati". Ini lebih seperti percakapan, dengan banyak hal untuk diperiksa, banyak hal untuk dipelajari.
sumber
Ada trik untuk mendorong postgres agar lebih memilih seqscan yang menambahkan a
OFFSET 0
di subqueryIni berguna untuk mengoptimalkan permintaan yang menautkan tabel besar / besar ketika yang Anda butuhkan hanyalah n elemen pertama / terakhir.
Katakanlah Anda mencari 20 elemen pertama / terakhir yang melibatkan banyak tabel yang memiliki 100k (atau lebih) entri, tidak ada gunanya membangun / menghubungkan semua kueri di semua data ketika apa yang akan Anda cari ada di 100 atau 1000 pertama entri. Dalam skenario ini misalnya, ternyata lebih dari 10x lebih cepat untuk melakukan pemindaian berurutan.
lihat Bagaimana cara mencegah Postgres agar tidak menyejajarkan subquery?
sumber