Mengindeks kondisi indeks parsial di Postgres
Saya mencoba menjelaskan tentang bagaimana indeks parsial Postgres disimpan di dalam Postgres. Misalkan saya membuat indeks seperti ini
CREATE INDEX orders_unbilled_index ON orders (order_nr)
WHERE billed is not true
untuk menjalankan kueri seperti
SELECT *
FROM orders
WHERE billed is not true AND order_nr > 1000000
Postgres jelas menyimpan indeks yang order_nrdibangun di atas subset orderstabel seperti yang didefinisikan oleh ekspresi kondisional billed is not true. Namun, saya punya beberapa pertanyaan terkait dengan ini:
- Apakah Postgres menyimpan indeks lain secara internal
billed is not trueuntuk segera menemukan baris yang terkait dengan indeks parsial? - Jika (1) tidak terjadi, apakah itu akan membuat kueri di atas berjalan lebih cepat jika saya membuat indeks terpisah di
billed is not true? (dengan asumsi tabel besar dan beberapa baris denganbilled is true)
EDIT: Contoh kueri saya berdasarkan dokumen bukanlah yang terbaik karena bagaimana indeks boolean jarang digunakan , tetapi harap pertimbangkan pertanyaan saya dalam konteks ekspresi bersyarat apa pun.
Jawaban
Indeks b-tree dapat dianggap sebagai daftar entri indeks yang berurutan, masing-masing dengan penunjuk ke baris dalam tabel.
Dalam indeks parsial, daftarnya hanya lebih kecil: hanya ada entri indeks untuk baris yang memenuhi syarat.
Jika Anda memiliki kondisi indeks dalam WHEREklausa Anda , PostgreSQL tahu itu dapat menggunakan indeks dan tidak perlu memeriksa kondisi indeks, karena akan terpenuhi secara otomatis.
Begitu:
Tidak, setiap baris yang ditemukan melalui indeks akan secara otomatis memenuhi ketentuan indeks, jadi menggunakan indeks sudah cukup untuk memastikannya terpenuhi.
Tidak, indeks pada kolom boolean tidak akan digunakan, karena tidak akan lebih murah dari indeks parsial ini, dan indeks parsial juga dapat digunakan untuk memeriksa kondisi
order_nr.Sebenarnya yang terjadi adalah sebaliknya: indeks parsial dapat digunakan untuk query yang hanya memiliki
booleankolom dalamWHEREkondisi tersebut, jika ada beberapa baris yang cukup yang memenuhi kondisi tersebut.
Menurut pemahaman saya, Postgres hanya akan membangun indeks yang hanya dapat digunakan untuk mencari catatan yang billeddianggap tidak benar. Artinya, B-tree yang dihasilkan akan diindeks oleh order_nr, tetapi hanya akan menautkan kembali ke tabel asli jika billedsalah.
Jika Anda terus membaca dokumentasi , segera setelah apa yang Anda kutip, Anda akan menemukan kueri berikut sebagai contoh:
SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;
Dalam kasus ini, Postgres bahkan mungkin memilih untuk menggunakan indeks yang Anda tentukan pada kueri di atas. Itu dapat menggunakan indeks Anda untuk memenuhi kueri ini dengan memindai seluruh indeks. Jika ada sejumlah kecil pesanan yang belum ditagih, maka memindai indeks order_nrmungkin masih lebih disukai daripada melakukan pemindaian tabel lengkap.
Jadi, jawaban untuk pertanyaan Anda # 1 adalah tidak, tidak ada indeks terpisah untuk billed, melainkan indeks order_nrhanya dapat digunakan untuk rekaman yang billeddisetel ke salah. Dan untuk # 2, ya, indeks kedua di billed is not truedapat digunakan dengan asumsi beberapa rekaman tidak ditagih. Namun, bahkan indeks Anda saat ini bahkan dapat digunakan apa adanya.