Mengapa PostgreSQL melakukan pemindaian berurutan pada kolom yang diindeks?

150

Contoh yang sangat sederhana - satu tabel, satu indeks, satu permintaan:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

memberi saya:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

Mengapa TIDAK melakukan pemindaian indeks saja? Apa yang saya lewatkan?

Alex Vayda
sumber

Jawaban:

222

Jika SELECT mengembalikan lebih dari sekitar 5-10% dari semua baris dalam tabel, pemindaian berurutan jauh lebih cepat daripada pemindaian indeks.

Ini karena pemindaian indeks memerlukan beberapa operasi IO untuk setiap baris (lihat baris dalam indeks, lalu ambil baris dari heap). Sedangkan pemindaian berurutan hanya membutuhkan satu IO untuk setiap baris - atau bahkan kurang karena satu blok (halaman) pada disk berisi lebih dari satu baris, sehingga lebih dari satu baris dapat diambil dengan satu operasi IO.

Btw: ini juga berlaku untuk DBMS lain - beberapa optimasi sebagai "scan hanya indeks" disingkirkan (tetapi untuk SELECT * itu sangat tidak mungkin seperti DBMS akan pergi untuk "scan hanya indeks")

seekor kuda tanpa nama
sumber
12
5-10% tergantung pada beberapa pengaturan konfigurasi dan penyimpanan data juga. Itu bukan angka yang sulit.
Frank Heikens
6
@ Frank: itu sebabnya saya bilang "kira-kira" :) Tapi terima kasih sudah menunjukkannya
a_horse_with_no_name
5
Juga, pemindaian berurutan dapat meminta beberapa halaman dari tumpukan sekaligus, dan meminta kernel untuk mengambil potongan berikutnya ketika ia bekerja pada satu saat ini- pemindaian indeks mengambil satu halaman sekaligus. (Pemindaian bitmap melakukan kompromi di antara keduanya, Anda biasanya melihat bahwa muncul dalam rencana untuk kueri yang tidak cukup selektif untuk pemindaian indeks, tetapi masih tidak begitu tidak selektif sehingga layak untuk pemindaian tabel penuh)
araqnid
4
Pertanyaan yang menarik adalah bagaimana database tahu berapa banyak baris permintaan akan kembali tanpa melakukannya terlebih dahulu? Apakah itu menyimpan statistik seperti jumlah nilai yang berbeda vs ukuran tabel di suatu tempat?
Laurent Grégoire
7
@ LaurentGrégoire: ya, database menyimpan statistik tentang jumlah baris dan distribusi nilai. Lihat manual untuk detailnya: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name
13

Apakah Anda Menganalisis tabel / database? Dan bagaimana dengan statistik ? Ketika ada banyak catatan di mana tahun> 2009, pemindaian berurutan mungkin lebih cepat dari pemindaian indeks.

Frank Heikens
sumber
0

Dalam pemindaian indeks, baca kepala melompat dari satu baris ke baris lain yang 1000 kali lebih lambat daripada membaca blok fisik berikutnya (dalam pemindaian berurutan).

Jadi, jika (jumlah catatan yang akan diambil * 1000) kurang dari jumlah total catatan, pemindaian indeks akan berkinerja lebih baik.

Gaurav Neema
sumber
0

@a_horse_with_no_name menjelaskannya dengan cukup baik. Juga jika Anda benar-benar ingin menggunakan pemindaian indeks, Anda umumnya harus menggunakan rentang yang dibatasi di mana klausa. mis - tahun> 2019 dan tahun <2020.

Banyak kali statistik tidak diperbarui pada tabel dan itu tidak mungkin dilakukan karena kendala. Dalam hal ini, pengoptimal tidak akan tahu berapa banyak baris yang harus diambil pada tahun> 2019. Dengan demikian ia memilih pemindaian berurutan sebagai pengganti pengetahuan penuh. Partisi terikat akan menyelesaikan masalah sebagian besar waktu.

Shitij Goyal
sumber