PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Catatan tentang Indeks B-Tree PostgreSQL

PostgreSQL hadir dengan tidak kurang dari 6 jenis indeks yang berbeda, dengan B-Treeindex menjadi yang paling umum digunakan. Baca terus untuk mengetahui lebih lanjut tentang B-Treeindexes di PostgreSQL.

Jenis Indeks

Sebuah indeks di PostgreSQL, seperti yang dibuat untuk PRIMARY KEY dan UNIK dalam pernyataan aCREATE TABLE atau dibuat secara eksplisit dengan pernyataan CREATE INDEX, adalah "tipe" tertentu (walaupun secara teknis kita harus menyebutnya "metode akses indeks").

PostgreSQL hadir dengan tipe indeks bawaan ini:

  • B-Pohon
  • Hash
  • GIN – Indeks Terbalik Umum
  • BRIN – Indeks Rentang Blok (hanya di v9.5 ke atas)
  • GiST – Pohon Pencarian Terbalik Umum
  • SP-GiST – GiST yang Dipartisi Ruang

B-Tree adalah default dan tipe indeks yang paling umum digunakan. Menentukan kunci utama atau unik dalam pernyataan CREATE TABLE menyebabkan PostgreSQL membuat indeks B-Tree. Pernyataan CREATE INDEX tanpa klausa MENGGUNAKAN juga akan membuat indeks B-Tree:

-- the default index type is btree
CREATE INDEX ix_year ON movies (year);

-- equivalent, explicitly lists the index type
CREATE INDEX ix_year ON movies USING btree (year);

Memesan

Indeks B-Tree secara inheren dipesan. PostgreSQL dapat menggunakan urutan ini daripada mengurutkan pada ekspresi yang diindeks. Misalnya, mengurutkan semua judul film tahun 80-an berdasarkan judul akan memerlukan pengurutan:

idxdemo=# explain select title from movies where year between 1980 and 1989 order by title asc;
                                    QUERY PLAN
----------------------------------------------------------------------------------
 Sort  (cost=240.79..245.93 rows=2056 width=17)
   Sort Key: title
   ->  Index Scan using ix_year on movies  (cost=0.29..127.65 rows=2056 width=17)
         Index Cond: ((year >= 1980) AND (year <= 1989))
(4 rows)

Tetapi jika Anda mengurutkannya berdasarkan kolom yang diindeks (tahun), pengurutan tambahan tidak diperlukan.

idxdemo=# explain select title from movies where year between 1980 and 1989 order by year asc;
                                 QUERY PLAN
----------------------------------------------------------------------------
 Index Scan using ix_year on movies  (cost=0.29..127.65 rows=2056 width=21)
   Index Cond: ((year >= 1980) AND (year <= 1989))
(2 rows)

Faktor Isi

Untuk tabel yang tidak akan diperbarui, Anda dapat meningkatkan "faktor pengisian" dari default 90, yang akan memberi Anda indeks yang sedikit lebih kecil dan lebih cepat. Sebaliknya, jika tabel sering diperbarui yang melibatkan parameter yang diindeks, Anda dapat mengurangi faktor pengisian ke angka yang lebih kecil – ini akan memungkinkan penyisipan dan pembaruan yang lebih cepat, dengan biaya indeks yang sedikit lebih besar.

CREATE INDEX ix_smd ON silent_movies (director) WITH (fillfactor = 100);

Pengindeksan pada Teks

Indeks B-Tree dapat membantu dalam pencocokan awalan teks. Mari kita ambil kueri untuk membuat daftar semua film yang dimulai dengan huruf 'T':

idxdemo=> explain select title from movies where title like 'T%';
                         QUERY PLAN
-------------------------------------------------------------
 Seq Scan on movies  (cost=0.00..1106.94 rows=8405 width=17)
   Filter: (title ~~ 'T%'::text)
(2 rows)

Paket ini membutuhkan pemindaian berurutan penuh dari tabel. Apa yang terjadi jika kita menambahkan indeks B-Tree di film.title?

idxdemo=> create index ix_title on movies (title);
CREATE INDEX

idxdemo=> explain select title from movies where title like 'T%';
                         QUERY PLAN
-------------------------------------------------------------
 Seq Scan on movies  (cost=0.00..1106.94 rows=8405 width=17)
   Filter: (title ~~ 'T%'::text)
(2 rows)

Yah, itu tidak membantu sama sekali. Namun, ada bentuk debu peri ajaib yang bisa kita taburkan agar Postgres melakukan apa yang kita inginkan:

idxdemo=> create index ix_title2 on movies (title text_pattern_ops);
CREATE INDEX

idxdemo=> explain select title from movies where title like 'T%';
                                 QUERY PLAN
-----------------------------------------------------------------------------
 Bitmap Heap Scan on movies  (cost=236.08..1085.19 rows=8405 width=17)
   Filter: (title ~~ 'T%'::text)
   ->  Bitmap Index Scan on ix_title2  (cost=0.00..233.98 rows=8169 width=0)
         Index Cond: ((title ~>=~ 'T'::text) AND (title ~<~ 'U'::text))
(4 rows)

Rencananya sekarang menggunakan indeks, dan biayanya telah berkurang. Keajaiban di sini adalah "text_pattern_ops" yang memungkinkan indeks B-Tree di atas ekspresi "teks" digunakan untuk operator pola (LIKE dan ekspresi reguler). “text_pattern_ops” disebut OperatorClass.

Perhatikan bahwa ini hanya akan berfungsi untuk pola dengan awalan teks tetap, jadi“%Angry%” atau “%Men” tidak akan berfungsi. Gunakan pencarian teks lengkap PostgreSQL untuk kueri teks lanjutan.

Meliputi Indeks

Indeks penutup ditambahkan ke PostgreSQL di v11. Menutupi indeks memungkinkan Anda memasukkan nilai dari satu atau lebih ekspresi bersama dengan ekspresi yang diindeks di dalam indeks.

Mari kita coba kueri untuk semua judul film, diurutkan berdasarkan tahun rilis:

idxdemo=# explain select title from movies order by year asc;
                             QUERY PLAN
--------------------------------------------------------------------
 Sort  (cost=3167.73..3239.72 rows=28795 width=21)
   Sort Key: year
   ->  Seq Scan on movies  (cost=0.00..1034.95 rows=28795 width=21)
(3 rows)

Ini melibatkan pemindaian berurutan penuh dari tabel, diikuti oleh semacam kolom yang diproyeksikan. Pertama-tama mari kita tambahkan indeks reguler di film.tahun:

idxdemo=# create index ix_year on movies (year);
CREATE INDEX

idxdemo=# explain select title from movies order by year asc;
                                  QUERY PLAN
------------------------------------------------------------------------------
 Index Scan using ix_year on movies  (cost=0.29..1510.22 rows=28795 width=21)
(1 row)

Sekarang Postgres memutuskan untuk menggunakan indeks untuk mengeluarkan entri dari tabel secara langsung dalam urutan yang diinginkan. Tabel perlu dicari karena indeks hanya berisi nilai 'tahun' dan referensi ke tupel dalam tabel.

Jika kita memasukkan nilai 'judul' juga di dalam indeks, pencarian tabel dapat dihindari sama sekali. Mari kita gunakan sintaks baru untuk membuat indeks seperti itu:

idxdemo=# create index ix_year_cov on movies (year) include (title);
CREATE INDEX
Time: 92.618 ms

idxdemo=# drop index ix_year;
DROP INDEX

idxdemo=# explain select title from movies order by year asc;
                                      QUERY PLAN
---------------------------------------------------------------------------------------
 Index Only Scan using ix_year_cov on movies  (cost=0.29..2751.59 rows=28795 width=21)
(1 row)

Postgres sekarang menggunakan Index OnlyScan, yang berarti tablelookup benar-benar dihindari. Perhatikan bahwa kami harus menghapus indeks lama, karena Postgres tidak memilih ix_year_cov daripada ix_year untuk kueri ini.

Pengelompokan

PostgreSQL terkenal tidak mendukung pengurutan fisik otomatis baris dalam tabel, tidak seperti "indeks berkerumun" di RDBMS lainnya. Jika sebagian besar kueri Anda akan menarik sebagian besar baris tabel yang sebagian besar statis dalam urutan tetap, sebaiknya tata letak penyimpanan tabel fisik dalam urutan itu dan gunakan pemindaian berurutan. Untuk menyusun ulang tabel secara fisik dalam urutan yang ditentukan oleh indeks, gunakan:

CLUSTER VERBOSE movies USING ix_year;

Anda biasanya menggunakan indeks B-Tree untuk mengelompokkan ulang tabel, karena menyediakan urutan lengkap untuk semua baris dalam tabel.

Statistik Indeks

Berapa banyak ruang disk yang digunakan indeks Anda? Fungsi pg_relation_size dapat menjawabnya:

idxdemo=# select * from pg_relation_size('ix_year');
 pg_relation_size
------------------
           663552
(1 row)

Ini mengembalikan ruang disk yang digunakan oleh indeks, dalam byte.

Informasi lebih lanjut tentang indeks dapat dikumpulkan menggunakan extensionpgstattuple standar. Sebelum Anda menggunakan fungsi di bawah ini, Anda perlu melakukan CREATE EXTENSION pgstattuple; dalam database yang relevan sebagai superuser. Penggunaan fungsi ini juga membutuhkan hak pengguna super.

pgstattuple mengembalikan fungsi, antara lain, yang tidak digunakan (free_space ) dan dapat digunakan kembali (dead_tuple_len ) ruang disk dalam file index. Ini bisa sangat membantu dalam memutuskan apakah akan menjalankan REINDEX untuk mengurangi indeks kembung.

idxdemo=# select * from pgstattuple('ix_year'::regclass);
-[ RECORD 1 ]------+-------
table_len          | 663552
tuple_count        | 28795
tuple_len          | 460720
tuple_percent      | 69.43
dead_tuple_count   | 0
dead_tuple_len     | 0
dead_tuple_percent | 0
free_space         | 66232
free_percent       | 9.98

pgstattuple fungsi mengembalikan informasi spesifik B-Tree, termasuk level pohon:

idxdemo=# select * from pgstatindex('ix_year'::regclass);
-[ RECORD 1 ]------+-------
version            | 2
tree_level         | 1
index_size         | 663552
root_block_no      | 3
internal_pages     | 1
leaf_pages         | 79
empty_pages        | 0
deleted_pages      | 0
avg_leaf_density   | 89.72
leaf_fragmentation | 0

Ini dapat digunakan untuk memutuskan apakah akan menyesuaikan faktor pengisian indeks.

Memeriksa Isi Indeks B-Tree

Bahkan isi dari B-Tree dapat diperiksa secara langsung, menggunakan extensionpageinspect. Penggunaan ekstensi ini membutuhkan hak pengguna super.

Berikut adalah properti dari satu halaman (di sini, halaman ke-13) dari indeks:

idxdemo=# select * from bt_page_stats('ix_year', 13);
-[ RECORD 1 ]-+-----
blkno         | 13
type          | l
live_items    | 367
dead_items    | 0
avg_item_size | 16
page_size     | 8192
free_size     | 808
btpo_prev     | 12
btpo_next     | 14
btpo          | 0
btpo_flags    | 1

Dan berikut adalah isi sebenarnya dari setiap item (dibatasi 5 di sini) di halaman:

idxdemo=# select * from bt_page_items('ix_year', 13) limit 5;
 itemoffset |   ctid   | itemlen | nulls | vars |          data
------------+----------+---------+-------+------+-------------------------
          1 | (104,40) |      16 | f     | f    | 86 07 00 00 00 00 00 00
          2 | (95,38)  |      16 | f     | f    | 86 07 00 00 00 00 00 00
          3 | (95,39)  |      16 | f     | f    | 86 07 00 00 00 00 00 00
          4 | (95,40)  |      16 | f     | f    | 86 07 00 00 00 00 00 00
          5 | (96,1)   |      16 | f     | f    | 86 07 00 00 00 00 00 00
(5 rows)

Dan jika Anda berpikir untuk menulis kueri untuk menggabungkan sesuatu di setiap halaman, Anda juga memerlukan jumlah total halaman dalam relasi, yang dapat dihasilkan melalui pg_relpages dari pgstattuple ekstensi:

idxdemo=# select pg_relpages('ix_year');
 pg_relpages
-------------
          81
(1 row)

Jenis Indeks Lainnya

Indeks B-Tree adalah alat serbaguna untuk mengoptimalkan kueri. Dengan sedikit eksperimen dan perencanaan, ini dapat digunakan untuk sangat meningkatkan waktu respons aplikasi dan pekerjaan laporan.

Jenis indeks PostgreSQL lainnya juga berguna dan bisa lebih efisien dan berkinerja daripada B-Tree dalam kasus tertentu. Artikel ini memberikan gambaran singkat tentang semua jenis.

Punya tip tentang indeks yang ingin Anda bagikan? Berikan komentar di bawah ini!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Barman 2.11:barman-cloud-restore dan barman-cloud-wal-restore

  2. Batasan Unik dengan kondisi di MYSQL

  3. Postgres hilang kesalahan entri FROM-klausa pada kueri dengan klausa WITH

  4. Meningkatkan ke PostgreSQL13

  5. Jenis JOIN apa yang digunakan