PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Ghi chú về Chỉ mục B-Tree PostgreSQL

PostgreSQL có không dưới 6 loại chỉ mục khác nhau, trong đó B-Treeindex là loại được sử dụng phổ biến nhất. Đọc tiếp để tìm hiểu thêm về B-Treeindexes trong PostgreSQL.

Các loại chỉ mục

Một chỉ mục trong PostgreSQL, giống như những chỉ mục được tạo cho các KHÓA CHÍNH và DUY NHẤT trong câu lệnh aCREATE TABLE hoặc được tạo rõ ràng bằng câu lệnh CREATE INDEX, thuộc một “loại” cụ thể (mặc dù về mặt kỹ thuật, chúng ta nên gọi chúng là “phương thức truy cập chỉ mục”).

PostgreSQL đi kèm với các loại chỉ mục tích hợp sau:

  • B-Tree
  • Băm
  • GIN - Chỉ số Đảo ngược Tổng quát
  • BRIN - Chỉ mục phạm vi khối (chỉ trong v9.5 trở lên)
  • GiST - Cây Tìm kiếm Đảo ngược Tổng quát
  • SP-GiST - GiST được phân vùng theo không gian

B-Tree là loại chỉ mục mặc định và được sử dụng phổ biến nhất. Việc chỉ định khóa aprimary hoặc một khóa duy nhất trong câu lệnh CREATE TABLE khiến PostgreSQL tạo chỉ mục B-Tree. TẠO các câu lệnh INDEX mà không có mệnh đề USING cũng sẽ tạo các chỉ mục 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);

Đặt hàng

Các chỉ mục B-Tree vốn có thứ tự. PostgreSQL có thể sử dụng trật tự này hơn là sắp xếp theo biểu thức đã lập chỉ mục. Ví dụ:lấy tiêu đề của tất cả các phim thập niên 80 được sắp xếp theo tiêu đề sẽ yêu cầu sắp xếp:

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)

Nhưng nếu bạn đang sắp xếp chúng theo cột được lập chỉ mục (năm), thì bạn không cần phải sắp xếp bổ sung.

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)

Hệ số lấp đầy

Đối với các bảng sẽ không được cập nhật, bạn tăng "hệ số lấp đầy" từ mặc định là 90, điều này sẽ cung cấp cho các chỉ mục nhỏ hơn và nhanh hơn một chút. Ngược lại, nếu có các bản cập nhật thường xuyên của bảng liên quan đến tham số được lập chỉ mục, bạn có thể giảm hệ số lấp đầy xuống một số nhỏ hơn - điều này sẽ cho phép chèn và cập nhật nhanh hơn, với chi phí là các chỉ mục lớn hơn một chút.

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

Lập chỉ mục trên Văn bản

Các chỉ mục B-Tree có thể giúp đối sánh tiền tố của văn bản. Hãy thực hiện một truy vấn để liệt kê tất cả các phim bắt đầu bằng chữ cái ‘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)

Kế hoạch này yêu cầu quét tuần tự đầy đủ bảng. Điều gì xảy ra nếu bạn đọc chỉ mục B-Tree trên phim.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)

Chà, điều đó chẳng giúp ích được gì cả. Tuy nhiên, có một dạng bụi pixie ma thuật mà chúng ta có thể rắc để Postgres làm những gì chúng ta muốn:

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)

Kế hoạch hiện sử dụng một chỉ mục và chi phí đã giảm xuống. Điều kỳ diệu ở đây là “text_pattern_ops” cho phép chỉ mục B-Tree trên một biểu thức “văn bản” được sử dụng cho các toán tử mẫu (LIKE và biểu thức chính quy). “Text_pattern_ops” được gọi là Lớp toán tử.

Lưu ý rằng điều này sẽ chỉ hoạt động đối với các mẫu có tiền tố văn bản cố định, vì vậy “% Angry%” hoặc “% Men” sẽ không hoạt động. Sử dụng tìm kiếm văn bản đầy đủ của PostgreSQL dựa trên các truy vấn văn bản nâng cao.

Bao gồm các chỉ mục

Các chỉ mục bao phủ đã được thêm vào PostgreSQL trong v11. Việc bao gồm các chỉ mục cho phép bạn bao gồm giá trị của một hoặc nhiều biểu thức cùng với biểu thức được lập chỉ mục bên cạnh chỉ mục.

Hãy thử truy vấn tất cả các tựa phim, được sắp xếp theo năm phát hành:

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)

Điều này liên quan đến việc quét tuần tự đầy đủ bảng, theo sau là một loại cột được dự kiến. Đầu tiên chúng ta hãy thêm một chỉ mục thông thường trên phim ảnh.year:

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)

Bây giờ Postgres quyết định sử dụng chỉ mục để kéo các mục ra khỏi bảng một cách trực tiếp theo thứ tự mong muốn. Bảng cần được tra cứu vì chỉ mục chỉ chứa giá trị của "year" và tham chiếu đến bộ giá trị trong bảng.

Nếu chúng ta bao gồm cả giá trị của 'title' bên trong chỉ mục, thì có thể tránh hoàn toàn việc tra cứu bảng. Hãy sử dụng cú pháp mới để tạo chỉ mục như vậy:

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 hiện đang sử dụng Index OnlyScan, có nghĩa là hoàn toàn tránh được tablelookup. Lưu ý rằng chúng tôi phải bỏ chỉ mục cũ vìPostgres không chọn ix_year_cov thay vì ix_year cho truy vấn này.

Phân cụm

PostgreSQL khét tiếng không hỗ trợ tự động sắp xếp vật lý các hàng trong bảng, không giống như “chỉ mục được phân cụm” trong RDBMS khác. Nếu hầu hết các truy vấn của bạn muốn kéo ra hầu hết các hàng của một bảng chủ yếu là tĩnh theo một thứ tự cố định, bạn nên bố trí bộ lưu trữ bảng vật lý trong thử thách đó và sử dụng quét tuần tự. Để sắp xếp lại một bảng về mặt vật lý theo thứ tự được chỉ định bởi một chỉ mục, hãy sử dụng:

CLUSTER VERBOSE movies USING ix_year;

Bạn thường sử dụng chỉ mục B-Tree để thu thập lại một bảng, vì nó cung cấp thứ tự đầy đủ cho tất cả các hàng trong bảng.

Thống kê Chỉ mục

Chỉ mục của bạn chiếm bao nhiêu dung lượng đĩa? Hàm pg_relation_size có thể trả lời rằng:

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

Điều này trả về không gian đĩa được sử dụng bởi chỉ mục, tính bằng byte.

Thông tin thêm về chỉ mục có thể được thu thập bằng cách sử dụng extensionpgstattuple tiêu chuẩn. Trước khi sử dụng các chức năng bên dưới, bạn cần thực hiện CREATE EXTENSION pgstattuple; trong cơ sở dữ liệu có liên quan như một superuser. Việc sử dụng các chức năng này cũng cần có đặc quyền của người dùng.

pgstattuple Hàm trả về, trong số những thứ khác, không sử dụng (free_space ) và có thể sử dụng lại (dead_tuple_len ) không gian đĩa trong chỉ mục. Điều này có thể rất hữu ích trong việc quyết định có chạy REINDEX hay không để giảm bớt sự phình to của chỉ mục.

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 hàm trả về thông tin cụ thể của B-Tree, bao gồm cả cấp của cây:

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

Điều này có thể được sử dụng để quyết định xem có nên điều chỉnh hệ số lấp đầy của chỉ số hay không.

Kiểm tra nội dung chỉ mục B-Tree

Ngay cả nội dung của B-Tree cũng có thể được kiểm tra trực tiếp bằng cách sử dụng trang mở rộng. Việc sử dụng phần mở rộng này cần có đặc quyền của người dùng cấp cao.

Đây là các thuộc tính của một trang (đây, trang thứ 13) của chỉ mục:

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

Và đây là nội dung thực tế của từng mục (giới hạn ở 5 mục ở đây) trong trang:

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)

Và nếu bạn đang nghĩ đến việc viết một truy vấn để tổng hợp nội dung nào đó trên mỗi trang, bạn cũng sẽ cần tổng số trang trong mối quan hệ, có thể sinh ra thông qua pg_relpages từ pgstattuple phần mở rộng:

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

Các loại chỉ mục khác

Chỉ mục B-Tree là công cụ đa năng để tối ưu hóa các truy vấn. Với một chút kinh nghiệm và lập kế hoạch, nó có thể được sử dụng để cải thiện đáng kể thời gian phản hồi của các ứng dụng và báo cáo công việc.

Các loại chỉ mục khác của PostgreSQL cũng hữu ích và có thể hiệu quả hơn và hoạt động hiệu quả hơn B-Tree trong các trường hợp cụ thể. Bài viết này cung cấp aquickoverview về tất cả các loại.

Bạn có mẹo về các chỉ mục mà bạn muốn chia sẻ? Hãy để lại chúng như một bình luận bên dưới!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chọn hàng ngẫu nhiên cho mỗi nhóm

  2. Trả về bản ghi setof (bảng ảo) từ hàm

  3. Cách tạo người dùng trong PostgreSQL

  4. SQL:Chọn các bản ghi trong đó TẤT CẢ các bản ghi được kết hợp thỏa mãn một số điều kiện

  5. ver.2 LỖI PyGreSQL:from _pg import * ImportError:DLL load failed:Không tìm thấy mô-đun được chỉ định