Việc áp dụng các chỉ mục phù hợp có thể làm cho các truy vấn trở nên nhanh chóng.
Các chỉ mục sử dụng con trỏ để truy cập các trang dữ liệu một cách nhanh chóng.
Những thay đổi lớn đã xảy ra trên các Chỉ mục trong PostgreSQL 11, rất nhiều bản vá được chờ đợi đã được phát hành.
Hãy cùng xem qua một số tính năng tuyệt vời của phiên bản này.
Tạo chỉ mục B-TREE song song
PostgreSQL 11 đã giới thiệu một bản vá cơ sở hạ tầng để cho phép tạo chỉ mục song song.
Nó chỉ có thể được sử dụng với chỉ mục B-Tree như bây giờ.
Việc tạo chỉ mục B-Tree song song nhanh hơn gấp hai đến ba lần so với thực hiện cùng một việc mà không làm việc song song (hoặc xây dựng nối tiếp).
Trong PostgreSQL 11, việc tạo chỉ mục song song được bật theo mặc định.
Có hai tham số quan trọng:
- max_parallel_workers - Đặt số lượng nhân viên tối đa mà hệ thống có thể hỗ trợ cho các truy vấn song song.
- max_parallel_maintenance_workers - Kiểm soát số lượng quy trình công nhân tối đa có thể được sử dụng để TẠO CHỈ SỐ.
Hãy kiểm tra nó với một ví dụ:
severalnines=# CREATE TABLE test_btree AS SELECT generate_series(1,100000000) AS id;
SELECT 100000000
severalnines=# SET maintenance_work_mem = '1GB';
severalnines=# \timing
severalnines=# CREATE INDEX q ON test_btree (id);
TIME: 25294.185 ms (00:25.294)
Hãy thử nó với công việc song song 8 chiều:
severalnines=# SET maintenance_work_mem = '2GB';
severalnines=# SET max_parallel_workers = 16;
severalnines=# SET max_parallel_maintenance_workers = 8;
severalnines=# \timing
severalnines=# CREATE INDEX q1 ON test_btree (id);
TIME: 11001.240 ms (00:11.001)
Chúng ta có thể thấy sự khác biệt về hiệu suất với công nhân song song, hơn 60% hiệu suất chỉ với một thay đổi nhỏ. Bạn cũng có thể tăng giá trị bảo trì_work_mem để có được nhiều hiệu suất hơn.
Bảng ALTER cũng giúp tăng nhân công song song. Cú pháp dưới đây có thể được sử dụng để tăng công nhân song song cùng với max_parallel_maintenance_workers. Điều này hoàn toàn bỏ qua mô hình chi phí.
ALTER TABLE test_btree SET (parallel_workers = 24);
Mẹo:ĐẶT LẠI về mặc định sau khi hoàn thành xây dựng chỉ mục để ngăn kế hoạch truy vấn bất lợi.
TẠO CHỈ SỐ với tùy chọn CONCURRENTLY hỗ trợ các bản dựng song song mà không có hạn chế đặc biệt, chỉ quá trình quét bảng đầu tiên thực sự được thực hiện song song.
Bạn có thể tìm thấy các bài kiểm tra hiệu suất sâu hơn tại đây.
Thêm khóa định vị cho các chỉ mục Hash, Gist và Gin
PostgreSQL 11 được xuất xưởng với hỗ trợ khóa vị từ cho chỉ mục băm, chỉ mục gin và chỉ mục ý chính. Những điều này sẽ làm cho việc phân lập giao dịch SERIALIZABLE hiệu quả hơn nhiều với các chỉ mục đó.
Lợi ích:khóa vị từ có thể cung cấp hiệu suất tốt hơn ở mức cách ly có thể tuần tự hóa bằng cách giảm số lần dương tính giả dẫn đến lỗi tuần tự hóa không cần thiết.
Trong PostgreSQL 10, phạm vi khóa là mối quan hệ, nhưng trong PostgreSQL 11, khóa được tìm thấy chỉ là trang.
Hãy cùng kiểm tra.
severalnines=# CREATE TABLE sv_predicate_lock1(c1 INT, c2 VARCHAR(10)) ;
CREATE TABLE
severalnines=# CREATE INDEX idx1_sv_predicate_lock1 ON sv_predicate_lock1 USING 'hash(c1) ;
CREATE INDEX
severalnines=# INSERT INTO sv_predicate_lock1 VALUES (generate_series(1, 100000), 'puja') ;
INSERT 0 100000
severalnines=# BEGIN ISOLATION LEVEL SERIALIZABLE ;
BEGIN
severalnines=# SELECT * FROM sv_predicate_lock1 WHERE c1=10000 FOR UPDATE ;
c1 | c2
-------+-------
10000 | puja
(1 row)
Như chúng ta có thể thấy bên dưới, khóa ở cấp độ trang thay vì quan hệ. Trong PostgreSQL 10, nó ở cấp độ quan hệ, vì vậy nó là một CHIẾN THẮNG LỚN cho các giao dịch đồng thời trong PostgreSQL 11.
severalnines=# SELECT locktype, relation::regclass, mode FROM pg_locks ;
locktype | relation | mode
---------------+-------------------------+-----------------
relation | pg_locks | AccessShareLock
relation | idx1_sv_predicate_lock1 | AccessShareLock
relation | sv_predicate_lock1 | RowShareLock
virtualxid | | ExclusiveLock
transactionid | | ExclusiveLock
page | idx1_sv_predicate_lock1 | SIReadLock
tuple | sv_predicate_lock1 | SIReadLock
(7 rows)
Mẹo:Quét tuần tự sẽ luôn cần một khóa vị từ cấp quan hệ. Điều này có thể dẫn đến tỷ lệ các lỗi tuần tự hóa tăng lên. Có thể hữu ích khi khuyến khích sử dụng tính năng quét chỉ mục bằng cách giảm random_page_cost và / hoặc tăng cpu_tuple_cost.
Cho phép cập nhật HOT cho một số chỉ mục biểu thức
Tính năng Heap Only Tuple (HOT), loại bỏ các mục nhập chỉ mục dư thừa và cho phép sử dụng lại không gian được lấy bởi các bộ giá trị DELETEd hoặc UPDATEd bị che khuất mà không cần thực hiện hút chân không trên toàn bảng. Nó làm giảm kích thước chỉ mục bằng cách tránh tạo các mục nhập chỉ mục được khóa giống hệt nhau.
Nếu giá trị của biểu thức chỉ mục không thay đổi sau khi CẬP NHẬT, hãy cho phép cập nhật HOT mà trước đó PostgreSQL không cho phép chúng, giúp tăng hiệu suất đáng kể trong những trường hợp đó.
Điều này đặc biệt hữu ích cho các chỉ mục như trường JSON ->> trong đó giá trị JSON thay đổi nhưng giá trị được lập chỉ mục thì không.
Tính năng này đã được khôi phục vào phiên bản 11.1 do hiệu suất bị giảm sút (chỉ AT Free BSD theo Simon), bạn có thể tìm thêm thông tin chi tiết / điểm chuẩn tại đây. Điều này sẽ được khắc phục trong bản phát hành trong tương lai.
Cho phép quét toàn bộ các trang chỉ mục băm
Chỉ mục băm:Người lập kế hoạch truy vấn sẽ xem xét sử dụng chỉ mục băm bất cứ khi nào cột được lập chỉ mục tham gia vào phép so sánh bằng toán tử =. Nó cũng không an toàn khi gặp sự cố (không đăng nhập WAL) vì vậy nó cần phải xây dựng lại sau khi DB gặp sự cố và các thay đổi đối với hàm băm không được ghi thông qua sao chép trực tuyến.
Trong PostgreSQL 10, chỉ mục băm đã được ghi nhật ký WAL, điều đó có nghĩa là, nó an toàn CRASH và có thể được sao chép. Các chỉ mục băm sử dụng ít không gian hơn nhiều so với B-Tree để chúng có thể vừa với bộ nhớ tốt hơn.
Trong PostgreSQL 11, các chỉ mục Btree có một tính năng tối ưu hóa được gọi là "khoảng trống trang đơn", loại bỏ một cách cơ hội các con trỏ chỉ mục chết khỏi các trang chỉ mục, ngăn chặn một lượng lớn chỉ mục phình to, nếu không sẽ xảy ra. Logic tương tự đã được chuyển sang các chỉ mục Hash. Nó tăng tốc độ tái chế không gian, giảm sự cồng kềnh.
THỐNG KÊ Chỉ số Chức năng
Bây giờ có thể chỉ định một giá trị THỐNG KÊ cho một cột chỉ mục hàm. Nó có giá trị cao đối với hiệu quả của một ứng dụng chuyên biệt. Giờ đây, chúng tôi có thể thu thập số liệu thống kê trên các cột biểu thức, điều này sẽ giúp người lập kế hoạch đưa ra quyết định chính xác hơn.
severalnines=# CREATE INDEX idx1_stats ON stat ((s1 + s2)) ;
CREATE INDEX
severalnines=# ALTER INDEX idx1_stats ALTER COLUMN 1 SET STATISTICS 1000 ;
ALTER INDEX
severalnines=# \d+ idx1_stats
Index "public.idx1_stats"
Column | Type | Definition | Storage | Stats target
--------+---------+------------+---------+--------------
expr | numeric | (c1 + c2) | main | 1000
btree, for table "public.stat1"
kiểm tra
Một kiểm tra mô-đun Contrib mới đã được thêm vào. Chỉ các chỉ mục B-Tree mới có thể được kiểm tra.
Hãy kiểm tra nó ra!
severalnines=# CREATE EXTENSION amcheck ;
CREATE EXTENSION
severalnines=# SELECT bt_index_check('idx1_stats') ;
ERROR: invalid page in block 0 of relation base/16385/16580
severalnines=#CREATE INDEX idx1_hash_data1 ON data1 USING hash (c1) ;
CREATE INDEX
severalnines=# SELECT bt_index_check('idx1_hash_data1') ;
ERROR: only B-Tree indexes are supported as targets for verification
DETAIL: Relation "idx1_hash_data1" is not a B-Tree index.
Có thể có chỉ mục được phân vùng cục bộ
Trước PostgreSQL11, không thể tạo chỉ mục trên bảng con hoặc bảng được phân vùng.
Trong PostgreSQL 11, khi CREATE INDEX được chạy trên bảng được phân vùng / bảng cha, nó sẽ tạo các mục nhập danh mục cho một chỉ mục trên bảng được phân vùng và xếp tầng để tạo các chỉ mục thực tế trên các phân vùng hiện có. Nó cũng sẽ tạo chúng trong các phân vùng trong tương lai.
Hãy thử tạo một bảng cha và phân vùng nó:
severalnines=# create table test_part ( a int, list varchar(5) ) partition by list (list);
CREATE TABLE
severalnines=# create table part_1 partition of test_part for values in ('India');
CREATE TABLE
severalnines=# create table part_2 partition of test_part for values in ('USA');
CREATE TABLE
severalnines=#
severalnines=# \d+ test_part
Table "public.test_part"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+----------------------+-----------+----------+---------+----------+--------------+-------------
a | integer | | | | plain | |
list | character varying(5) | | | | extended | |
Partition key: LIST (list)
Partitions: part_1 FOR VALUES IN ('India'),
part_2 FOR VALUES IN ('USA')
Hãy thử tạo một chỉ mục trên bảng mẹ:
severalnines=# create index i_test on test_part (a);
CREATE INDEX
severalnines=# \d part_2
Table "public.part_2"
Column | Type | Collation | Nullable | Default
--------+----------------------+-----------+----------+---------
a | integer | | |
list | character varying(5) | | |
Partition of: test_part FOR VALUES IN ('USA')
Indexes:
"part_2_a_idx" btree (a)
severalnines=# \d part_1
Table "public.part_1"
Column | Type | Collation | Nullable | Default
--------+----------------------+-----------+----------+---------
a | integer | | |
list | character varying(5) | | |
Partition of: test_part FOR VALUES IN ('India')
Indexes:
"part_1_a_idx" btree (a)
Chỉ mục được xếp tầng xuống tất cả các phân vùng trong PostgreSQL 11, đây là một tính năng thực sự thú vị.
Chỉ mục bao gồm (bao gồm CLAUSE cho các chỉ mục)
Có thể chỉ định mệnh đề INCLUDE để thêm cột vào chỉ mục. Điều này có hiệu quả khi thêm các cột không liên quan đến ràng buộc duy nhất của một chỉ mục duy nhất. Các cột INCLUDE chỉ tồn tại duy nhất để cho phép nhiều truy vấn hơn được hưởng lợi từ việc quét chỉ chỉ mục. Hiện tại, chỉ có B-tree index mới hỗ trợ mệnh đề INCLUDE.
Hãy kiểm tra hành vi mà không BAO GỒM. Nó sẽ không sử dụng chỉ mục quét nếu các cột bổ sung xuất hiện trong CHỌN. Điều này có thể đạt được bằng cách sử dụng điều khoản INCLUDE.
severalnines=# CREATE TABLE no_include (a int, b int, c int);
CREATE TABLE
severalnines=# INSERT INTO no_include SELECT 3 * val, 3 * val + 1, 3 * val + 2 FROM generate_series(0, 1000000) as val;
INSERT 0 1000001
severalnines=# CREATE UNIQUE INDEX old_unique_idx ON no_include(a, b);
CREATE INDEX
severalnines=# VACUUM ANALYZE;
VACUUM
EXPLAIN ANALYZE SELECT a, b FROM no_include WHERE a < 1000; - It will do index only scan
EXPLAIN ANALYZE SELECT a, b, c FROM no_include WHERE a < 1000; - It will not do index only scan as we have extra column in select.
severalnines=# CREATE INDEX old_idx ON no_include (a, b, c);
CREATE INDEX
severalnines=# VACUUM ANALYZE;
VACUUM
severalnines=# EXPLAIN ANALYZE SELECT a, b, c FROM no_include WHERE a < 1000; - It did index only scan as index on all three columns.
QUERY PLAN
-------------------------------------------------
Index Only Scan using old_idx on no_include
(cost=0.42..14.92 rows=371 width=12)
(actual time=0.086..0.291 rows=334 loops=1)
Index Cond: (a < 1000)
Heap Fetches: 0
Planning Time: 2.108 ms
Execution Time: 0.396 ms
(5 rows)
Hãy thử với mệnh đề include. Trong ví dụ bên dưới, CONSTRAINT DUY NHẤT được tạo trong cột a và b, nhưng chỉ mục bao gồm cột c.
severalnines=# CREATE TABLE with_include (a int, b int, c int);
CREATE TABLE
severalnines=# INSERT INTO with_include SELECT 3 * val, 3 * val + 1, 3 * val + 2 FROM generate_series(0, 1000000) as val;
INSERT 0 1000001
severalnines=# CREATE UNIQUE INDEX new_unique_idx ON with_include(a, b) INCLUDE (c);
CREATE INDEX
severalnines=# VACUUM ANALYZE;
VACUUM
severalnines=# EXPLAIN ANALYZE SELECT a, b, c FROM with_include WHERE a < 10000;
QUERY PLAN
-----------------------------------------------------
Index Only Scan using new_unique_idx on with_include
(cost=0.42..116.06 rows=3408 width=12)
(actual time=0.085..2.348 rows=3334 loops=1)
Index Cond: (a < 10000)
Heap Fetches: 0
Planning Time: 1.851 ms
Execution Time: 2.840 ms
(5 rows)
Không được có bất kỳ sự chồng chéo nào giữa các cột trong danh sách cột chính và những cột từ danh sách bao gồm
severalnines=# CREATE UNIQUE INDEX new_unique_idx ON with_include(a, b) INCLUDE (a);
ERROR: 42P17: included columns must not intersect with key columns
LOCATION: DefineIndex, indexcmds.c:373
Một cột được sử dụng với một biểu thức trong danh sách chính sẽ hoạt động:
severalnines=# CREATE UNIQUE INDEX new_unique_idx_2 ON with_include(round(a), b) INCLUDE (a);
CREATE INDEX
Không thể sử dụng các biểu thức trong danh sách bao gồm vì chúng không thể được sử dụng trong quá trình quét chỉ chỉ mục:
severalnines=# CREATE UNIQUE INDEX new_unique_idx_2 ON with_include(a, b) INCLUDE (round(c));
ERROR: 0A000: expressions are not supported in included columns
LOCATION: ComputeIndexAttrs, indexcmds.c:1446
Kết luận
Các tính năng mới của PostgreSQL chắc chắn sẽ cải thiện tuổi thọ của DBA, vì vậy nó đang trở thành một lựa chọn thay thế mạnh mẽ trong DB mã nguồn mở. Tôi hiểu rằng một số tính năng của chỉ mục hiện đang bị giới hạn trong B-Tree, nó vẫn là một khởi đầu tuyệt vời của kỷ nguyên thực thi song song cho PostgreSQL và hướng đến một công cụ tốt để xem xét kỹ hơn. Cảm ơn!