Apakah indeks komposit juga baik untuk kueri di bidang pertama?

86

Katakanlah saya punya tabel dengan bidang Adan B. Saya membuat kueri reguler pada A+ B, jadi saya membuat indeks gabungan pada (A,B). Apakah kueri hanya Ajuga akan sepenuhnya dioptimalkan oleh indeks komposit?

Selain itu, saya membuat indeks aktif A, tetapi Postgres masih menggunakan indeks komposit hanya untuk permintaan A. Jika jawaban sebelumnya positif, saya kira itu tidak terlalu penting, tetapi mengapa ia memilih indeks komposit secara default, jika Aindeks tunggal tersedia?

Luciano
sumber
Saya mencoba membuat tes kecil untuk ini. Namun, dalam kasus saya, indeks dua kolom hanya digunakan ketika saya menjatuhkan satu kolom, tidak terkait dengan yang pertama dibuat. Sangat menarik bahwa jika saya membuat indeks dua kolom terlebih dahulu, rencana awal menggunakan bitmap heap scan. Jika saya membuat indeks satu kolom, kemudian jalankan kueri (digunakan pemindaian indeks) dan menjatuhkan indeks yang baru dibuat, rencana yang melibatkan indeks dua kolom beralih ke pemindaian indeks. Lihat langkah-langkah di SQLFiddle
dezso
@dezso Menarik. Di mana biaya untuk setiap permintaan?
Luciano
Biaya pemindaian indeks Bitmap: 107,98, waktu eksekusi 43 ms. Pemindaian indeks satu kolom: biaya 8,69, dua kolom: 43,69. Waktu eksekusi tidak berbeda secara signifikan (fluktuasi lebih besar daripada perbedaan antara keduanya).
dezso
@Luciano Bisakah Anda menampilkan explain analyzedan teks kueri?
Craig Ringer

Jawaban:

88

Tentu saja. Kami membahasnya dengan sangat terperinci di bawah pertanyaan terkait ini:

Space dialokasikan dalam kelipatan MAXALIGN, yang biasanya 8 byte pada OS 64-bit atau (jauh lebih umum) 4 byte pada OS 32-bit. Jika Anda tidak yakin, periksa pg_controldata. Itu juga tergantung pada tipe data kolom yang diindeks (beberapa memerlukan pelurusan pelurusan) dan konten aktual.

Indeks pada, katakanlah, dua integerkolom (masing-masing 4 byte) biasanya berakhir persis sama dengan indeks hanya pada satu, di mana 4 byte lainnya hilang untuk bantalan pelurusan.

Dalam kasus seperti itu benar-benar tidak ada kerugian bagi perencana kueri untuk menggunakan indeks aktif (a,b)- dibandingkan dengan indeks hanya (a). Dan umumnya lebih disukai beberapa kueri untuk menggunakan indeks yang sama. Peluangnya (atau bagiannya) untuk berada dalam cache (cepat) tumbuh ketika dibagikan.

Jika Anda sudah mempertahankan indeks (a,b), maka tidak masuk akal untuk membuat indeks lain hanya (a)- kecuali secara substansial lebih kecil. Hal yang sama tidak berlaku untuk (b,a)vs (a). Ikuti tautan di baris pertama untuk informasi lebih lanjut.

Datang dari arah yang berlawanan, ketika Anda membutuhkan indeks tambahan seperti itu (a,b), maka pertimbangkan untuk menjatuhkan indeks yang ada hanya (a)- jika mungkin. Seringkali tidak mungkin karena itulah indeks PK atau UNIQUEkendala. Sejak Postgres 11 Anda mungkin lolos hanya dengan menambahkan bdefinisi kendala dengan INCLUDEklausa sebagai gantinya. Detail dalam manual.

Atau buat indeks baru pada (b,a)sebagai gantinya untuk menutupi permintaan hanya btambahan. Untuk kondisi kesetaraan saja urutan ekspresi indeks dalam indeks btree tidak masalah. Meskipun demikian, hal itu melibatkan kondisi jangkauan. Lihat:

Ada potensi kerugian untuk menyertakan kolom tambahan dalam indeks, bahkan jika itu hanya menggunakan ruang yang dinyatakan hilang untuk pelurusan pelurus:

  • Setiap kali kolom tambahan diperbarui, indeks sekarang juga membutuhkan pembaruan, yang mungkin menambah biaya untuk menulis operasi dan membuat lebih banyak indeks mengasapi.
  • Pembaruan HOT (Heap Only Tuple) di atas meja tidak dimungkinkan saat kolom indeks apa pun terlibat.

Lebih lanjut tentang pembaruan HOT:

Cara mengukur ukuran objek:

Erwin Brandstetter
sumber
1
Bisakah Anda memperluas ini untuk mengatakan bahwa, Jika saya memiliki Indeks pada kolom A, dan perlu muncul untuk menambahkan indeks gabungan (A, B), indeks A harus dijatuhkan? Jika menggunakan kembali indeks meningkatkan efisiensi cache, dan (A, B) sepenuhnya mengoptimalkan, A, maka sepertinya indeks tambahan pada A akan membuang-buang ruang dan berpotensi memperlambat segalanya
jvans
1
@ jvans: Secara umum benar - dengan pengecualian dan alternatif penting. Saya menambahkan paragraf ke alamat itu.
Erwin Brandstetter
2

Menurut pertanyaan Anda, Anda memiliki tabel dengan bidang A dan B. Jika Anda kueri Anda adalah:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

Pengoptimal akan memilih indeks Komposit untuk menghindari Ekstrak akses acak!

BongSey
sumber
-4

Ini ada dalam kasus jika Anda hanya menggunakan pertama dalam predikat.

Ini akan melakukan pemindaian jika Anda menggunakan kolom pertama dari kunci komposit dan kolom non-kunci dari kunci komposit.

Untuk mengelabui Anda, Anda bisa saja membuat dummy predikat seperti ini dan kemudian kolom non-kunci:

[A, B] adalah indeks Anda, [C] - kolom lain

Untuk menggunakan indeks Anda menulis sebagai:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

... mengapa ia memilih indeks komposit secara default, jika indeks A tunggal tersedia?

Ini akan menggunakan indeks hanya dalam kasus jika ada satu atau dua predikat [A] Atau [A], [B]. Itu tidak akan menggunakannya dalam urutan [B], [A] atau [A], [C]. Untuk dapat menggunakan indeks dengan kolom tambahan [C], Anda perlu menegakkan indeks dengan memesan predikat sebagai [A], [B] dan [C].

Farfarak
sumber
2
Apa yang sebenarnya Anda capai B=B? Saya pikir Anda tidak mencapai apa-apa jadi saya memilih tidak ada bukti apa pun ini tidak hanya diabaikan oleh pengoptimal
Jack Douglas
2
B=Bsecara efektif sama dengan B IS NOT NULL, yang tampaknya tidak pantas. Tentunya tidak perlu menggunakan indeks pada (a,b).
Erwin Brandstetter