Đây là phần thứ hai của blog "Phần mở rộng PostgreSQL Yêu thích của tôi", trong đó tôi đã giới thiệu cho bạn hai phần mở rộng PostgreSQL, postgres_fdw và pg_partman. Trong phần này, tôi sẽ khám phá thêm ba điều nữa.
pgAudit
Phần mở rộng PostgreSQL tiếp theo được quan tâm nhằm mục đích đáp ứng các yêu cầu kiểm toán của nhiều cơ quan chính phủ, tài chính và các tổ chức chứng nhận khác như ISO, BSI và FISCAM, v.v. Cơ sở ghi nhật ký tiêu chuẩn mà PostgreSQL cung cấp nguyên bản với log_statement =tất cả đều hữu ích cho việc giám sát, nhưng nó không cung cấp các chi tiết cần thiết để tuân thủ hoặc đối mặt với cuộc kiểm toán. Tiện ích mở rộng pgAudit tập trung vào các chi tiết về những gì đã xảy ra trong khi cơ sở dữ liệu đang đáp ứng yêu cầu ứng dụng.
Đường mòn kiểm tra hoặc nhật ký kiểm tra được tạo và cập nhật bởi cơ sở ghi nhật ký tiêu chuẩn do PostgreSQL cung cấp, cung cấp ghi nhật ký kiểm tra phiên và / hoặc đối tượng chi tiết. Đường mòn đánh giá do pgAudit tạo ra có thể có kích thước khổng lồ tùy thuộc vào các cài đặt đánh giá, vì vậy cần phải chú ý theo dõi để quyết định trước về những gì và bao nhiêu việc đánh giá là cần thiết. Bản trình diễn ngắn gọn trong phần sau cho thấy cách pgAudit được định cấu hình và sử dụng.
Đường mòn nhật ký được tạo trong nhật ký cụm cơ sở dữ liệu PostgreSQL được tìm thấy ở vị trí PGDATA / log nhưng các thông báo nhật ký kiểm tra được đặt trước bằng nhãn “AUDIT:“ để phân biệt giữa thông báo nền cơ sở dữ liệu thông thường và nhật ký kiểm tra Hồ sơ.
Bản trình diễn
Tài liệu chính thức của pgAudit giải thích rằng tồn tại một phiên bản pgAudit riêng cho từng phiên bản chính của PostgreSQL để hỗ trợ chức năng mới được giới thiệu trong mỗi bản phát hành PostgreSQL. Phiên bản của PostgreSQL trong bản demo này là 11, vì vậy phiên bản của pgAudit sẽ là từ nhánh 1.3.X. Pgaudit.log là tham số cơ bản được đặt để kiểm soát những lớp câu lệnh nào sẽ được ghi lại. Nó có thể được đặt bằng SET cho một cấp độ phiên hoặc trong tệp postgresql.conf sẽ được áp dụng trên toàn cầu.
postgres=# set pgaudit.log = 'read, write, role, ddl, misc';
SET
cat $PGDATA/pgaudit.log
pgaudit.log = 'read, write, role, ddl, misc'
db_replica=# show pgaudit.log;
pgaudit.log
------------------------------
read, write, role, ddl, misc
(1 row)
2020-01-29 22:51:49.289 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,3,1,MISC,SHOW,,,show pgaudit.log;,<not logged>
db_replica=# create table t1 (f1 integer, f2 varchar);
CREATE TABLE
2020-01-29 22:52:08.327 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,4,1,DDL,CREATE TABLE,,,"create table t1 (f1 integer, f2 varchar);",<not logged>
db_replica=# insert into t1 values (1,'one');
INSERT 0 1
db_replica=# insert into t1 values (2,'two');
INSERT 0 1
db_replica=# insert into t1 values (3,'three');
INSERT 0 1
2020-01-29 22:52:19.261 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,5,1,WRITE,INSERT,,,"insert into t1 values (1,'one');",<not logged>
20-01-29 22:52:38.145 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,6,1,WRITE,INSERT,,,"insert into t1 values (2,'two');",<not logged>
2020-01-29 22:52:44.988 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,7,1,WRITE,INSERT,,,"insert into t1 values (3,'three');",<not logged>
db_replica=# select * from t1 where f1 >= 2;
f1 | f2
----+-------
2 | two
3 | three
(2 rows)
2020-01-29 22:53:09.161 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,9,1,READ,SELECT,,,select * from t1 where f1 >= 2;,<not logged>
db_replica=# grant select on t1 to usr_replica;
GRANT
2020-01-29 22:54:25.283 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,13,1,ROLE,GRANT,,,grant select on t1 to usr_replica;,<not logged>
db_replica=# alter table t1 add f3 date;
ALTER TABLE
2020-01-29 22:55:17.440 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,23,1,DDL,ALTER TABLE,,,alter table t1 add f3 date;,<not logged>
db_replica=# checkpoint;
CHECKPOINT
2020-01-29 22:55:50.349 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,33,1,MISC,CHECKPOINT,,,checkpoint;,<not logged>
db_replica=# vacuum t1;
VACUUM
2020-01-29 22:56:03.007 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,34,1,MISC,VACUUM,,,vacuum t1;,<not logged>
db_replica=# show log_statement;
log_statement
---------------
none
2020-01-29 22:56:14.740 AEDT 4710 db_replica postgres [local] psql LOG: AUDIT: SESSION,36,1,MISC,SHOW,,,show log_statement;,<not logged>
Các mục nhật ký, như thể hiện trong bản trình diễn ở trên, chỉ được ghi vào logfile nền của máy chủ khi tham số log_statement được đặt, tuy nhiên trong trường hợp này, nó không được định cấu hình nhưng các thông báo kiểm tra được viết bằng cách của tham số pgaudit.log như được minh chứng trong bản trình diễn. Có nhiều tùy chọn mạnh mẽ hơn có sẵn để đáp ứng tất cả các yêu cầu kiểm tra cơ sở dữ liệu của bạn trong PostgreSQL, có thể được định cấu hình bằng cách làm theo tài liệu chính thức của pgaudit tại đây hoặc trên github repository.pg_repack
Đây là một tiện ích mở rộng được nhiều kỹ sư PostgreSQL yêu thích có liên quan trực tiếp đến việc quản lý và duy trì tình trạng chung của một cụm PostgreSQL. Lý do cho điều đó sẽ được thảo luận sau một chút nhưng phần mở rộng này cung cấp chức năng loại bỏ cơ sở dữ liệu bloat trong cơ sở dữ liệu PostgreSQL, đây là một trong những mối quan tâm dai dẳng giữa các cụm cơ sở dữ liệu PostgreSQL rất lớn yêu cầu tổ chức lại cơ sở dữ liệu.
Do cơ sở dữ liệu PostgreSQL trải qua quá trình WRITES (cập nhật và xóa) liên tục và nặng nề, dữ liệu cũ được đánh dấu là đã xóa trong khi phiên bản mới của hàng được chèn vào, nhưng dữ liệu cũ không thực sự bị xóa khỏi khối dữ liệu. Điều này yêu cầu một hoạt động bảo trì định kỳ được gọi là hút bụi, là một quy trình tự động thực hiện trong nền để xóa tất cả các hàng "được đánh dấu là đã xóa". Quá trình này đôi khi được gọi là thu gom rác theo thuật ngữ thông tục.
Quá trình hút bụi thường nhường chỗ cho các hoạt động cơ sở dữ liệu trong thời gian bận rộn hơn. Cách thức hút bụi ít hạn chế nhất có lợi cho các hoạt động cơ sở dữ liệu dẫn đến một số lượng lớn các hàng “được đánh dấu là đã xóa” khiến cơ sở dữ liệu phát triển theo tỷ lệ được gọi là “cơ sở dữ liệu phình to”. Có một quá trình hút bụi mạnh mẽ được gọi là VACUUM FULL, nhưng điều đó dẫn đến việc có được một khóa độc quyền trên đối tượng cơ sở dữ liệu đang được xử lý, làm ngừng hoạt động cơ sở dữ liệu trên đối tượng đó.
pg_repack
Chính vì lý do này mà pg_repack là một hit trong số các DBA và kỹ sư PostgreSQL, bởi vì nó thực hiện công việc của một quy trình hút bụi thông thường nhưng mang lại hiệu quả VACUUM FULL bằng cách không có được một khóa độc quyền trên cơ sở dữ liệu đối tượng, trong ngắn hạn, nó hoạt động trực tuyến. Tài liệu chính thức ở đây giải thích thêm về các phương pháp tổ chức lại cơ sở dữ liệu khác nhưng một bản demo nhanh như bên dưới sẽ đưa mọi thứ vào ánh sáng thích hợp để bạn hiểu rõ hơn. Có một yêu cầu rằng bảng mục tiêu phải có ít nhất một cột được xác định là TỪ KHÓA CHÍNH, đây là tiêu chuẩn chung trong hầu hết các thiết lập cơ sở dữ liệu sản xuất.
Bản trình diễn
Bản demo cơ bản cho thấy việc cài đặt và sử dụng pg_repack trong môi trường thử nghiệm. Bản demo này sử dụng phiên bản 1.4.5 của pg_repack, đây là phiên bản mới nhất của tiện ích mở rộng này tại thời điểm xuất bản blog này. Bảng demo t1 ban đầu có 80000 hàng trải qua một thao tác xóa lớn, thao tác này sẽ xóa mọi hàng thứ 5 của bảng. Việc thực thi pg_repack hiển thị kích thước của bảng trước và sau.
mydb=# CREATE EXTENSION pg_repack;
CREATE EXTENSION
mydb=# create table t1 (no integer primary key, f_name VARCHAR(20), l_name VARCHAR(20), d_o_b date);
CREATE TABLE
mydb=# insert into t1 (select generate_series(1,1000000,1),'a'||
mydb(# generate_series(1,1000000,1),'a'||generate_series(1000000,1,-1),
mydb(# cast( now() - '1 year'::interval * random() as date ));
INSERT 0 1000000
mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));
pg_size_pretty
----------------
71 MB
(1 row)
mydb=# CREATE or replace FUNCTION delete5() RETURNS void AS $$
mydb$# declare
mydb$# counter integer := 0;
mydb$# BEGIN
mydb$#
mydb$# while counter <= 1000000
mydb$# loop
mydb$# delete from t1 where no=counter;
mydb$# counter := counter + 5;
mydb$# END LOOP;
mydb$# END;
mydb$# $$ LANGUAGE plpgsql;
CREATE FUNCTION
Hàm delete5 xóa 200000 hàng khỏi bảng t1 bằng cách sử dụng một bộ đếm tăng 5 số
mydb=# select delete5();
delete5
------
(1 row)
mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));
pg_size_pretty
----------------
71 MB
(1 row)
$ pg_repack -t t1 -N -n -d mydb -p 5433
INFO: Dry run enabled, not executing repack
INFO: repacking table "public.t1"
$ pg_repack -t t1 -n -d mydb -p 5433
INFO: repacking table "public.t1"
mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));
pg_size_pretty
----------------
57 MB
(1 row)
Như hình trên, kích thước ban đầu của bảng không thay đổi sau khi thực hiện hàm delete5, điều này cho thấy các hàng vẫn tồn tại trong bảng. Việc thực thi pg_repack xóa các hàng "được đánh dấu là đã xóa" khỏi bảng t1, làm giảm kích thước của bảng t1 xuống còn 57 MB. Một điều tốt khác về pg_repack là một tùy chọn để chạy khô với cờ -N, sử dụng tùy chọn này bạn có thể kiểm tra những gì sẽ được thực thi trong quá trình chạy thực tế.
HypoPG
Phần mở rộng thú vị tiếp theo giống với một khái niệm phổ biến được gọi là chỉ mục vô hình giữa các máy chủ cơ sở dữ liệu độc quyền. Tiện ích mở rộng HypoPG cho phép DBA thấy tác dụng của việc giới thiệu một chỉ mục giả định (không tồn tại) và liệu nó có cải thiện hiệu suất của một hoặc nhiều truy vấn hay không, do đó có tên là HypoPG.
Việc tạo chỉ mục giả định không yêu cầu bất kỳ tài nguyên CPU hoặc đĩa nào, tuy nhiên, nó sử dụng bộ nhớ riêng của kết nối. Vì chỉ mục giả định không được lưu trữ trong bất kỳ bảng danh mục cơ sở dữ liệu nào, nên không có tác động của hiện tượng phồng bảng. Chính vì lý do này, không thể sử dụng chỉ mục giả định trong câu lệnh GIẢI THÍCH PHÂN TÍCH trong khi GIẢI THÍCH đơn giản là một cách tốt để đánh giá xem chỉ mục tiềm năng có được sử dụng bởi một truy vấn có vấn đề nhất định hay không. Đây là bản demo nhanh để giải thích cách hoạt động của HypoPG.
Bản trình diễn
Tôi sẽ tạo một bảng chứa 100000 hàng bằng cách sử dụng create_series và thực hiện một vài truy vấn đơn giản để hiển thị sự khác biệt trong ước tính chi phí có và không có chỉ mục giả định.
olap=# CREATE EXTENSION hypopg;
CREATE EXTENSION
olap=# CREATE TABLE stock (id integer, line text);
CREATE TABLE
olap=# INSERT INTO stock SELECT i, 'line ' || i FROM generate_series(1, 100000) i;
INSERT 0 100000
olap=# ANALYZE STOCK;
ANALYZE
olap=# EXPLAIN SELECT line FROM stock WHERE id = 1;
QUERY PLAN
---------------------------------------------------------
Seq Scan on stock (cost=0.00..1791.00 rows=1 width=10)
Filter: (id = 1)
(2 rows)
olap=# SELECT * FROM hypopg_create_index('CREATE INDEX ON stock (id)') ;
indexrelid | indexname
------------+-----------------------
25398 | <25398>btree_stock_id
(1 row)
olap=# EXPLAIN SELECT line FROM stock WHERE id = 1;
QUERY PLAN
------------------------------------------------------------------------------------
Index Scan using <25398>btree_stock_id on stock (cost=0.04..8.06 rows=1 width=10)
Index Cond: (id = 1)
(2 rows)
olap=# EXPLAIN ANALYZE SELECT line FROM stock WHERE id = 1;
QUERY PLAN
----------------------------------------------------------------------------------------------------
Seq Scan on stock (cost=0.00..1791.00 rows=1 width=10) (actual time=0.028..41.877 rows=1 loops=1)
Filter: (id = 1)
Rows Removed by Filter: 99999
Planning time: 0.057 ms
Execution time: 41.902 ms
(5 rows)
olap=# SELECT indexname, pg_size_pretty(hypopg_relation_size(indexrelid))
olap-# FROM hypopg_list_indexes() ;
indexname | pg_size_pretty
-----------------------+----------------
<25398>btree_stock_id | 2544 kB
(1 row)
olap=# SELECT pg_size_pretty(pg_relation_size('stock'));
pg_size_pretty
----------------
4328 kB
(1 row)
Phần trình bày ở trên cho thấy cách tổng chi phí ước tính có thể giảm từ 1791 xuống 8,06 bằng cách thêm chỉ mục vào trường "id" của bảng để tối ưu hóa một truy vấn đơn giản. Nó cũng chứng minh rằng chỉ mục không thực sự được sử dụng khi truy vấn được thực thi với PHÂN TÍCH GIẢI THÍCH thực thi truy vấn trong thời gian thực. Ngoài ra còn có một cách để tìm ra khoảng không gian đĩa mà chỉ mục chiếm bằng cách sử dụng hàm hypopg_list_indexes của tiện ích mở rộng.
HypoPG có một số chức năng khác để quản lý các chỉ mục giả định và ngoài ra, nó cũng cung cấp một cách để tìm hiểu xem việc phân vùng bảng có cải thiện hiệu suất của các truy vấn tìm nạp một tập dữ liệu lớn hay không. Có một tùy chọn phân vùng giả định của tiện ích mở rộng HypoPG và nhiều tùy chọn khác của nó có thể được thực hiện bằng cách tham khảo tài liệu chính thức.
Kết luận
Như đã nêu trong phần một, PostgreSQL đã phát triển trong những năm qua chỉ ngày càng lớn hơn, tốt hơn và nhanh hơn với sự phát triển nhanh chóng cả về mã nguồn gốc cũng như các tiện ích mở rộng plug and play. Một phiên bản nguồn mở của PostgreSQL mới có thể phù hợp nhất cho nhiều cửa hàng CNTT đang chạy một trong những máy chủ cơ sở dữ liệu độc quyền lớn, để giảm IT CAPEX và OPEX của họ.
Có rất nhiều tiện ích mở rộng PostgreSQL cung cấp các tính năng từ giám sát đến khả năng sẵn sàng cao và từ mở rộng quy mô đến kết xuất tệp dữ liệu nhị phân sang định dạng con người có thể đọc được. Hy vọng rằng các minh chứng trên đã làm sáng tỏ tiềm năng và sức mạnh tối đa của cơ sở dữ liệu PostgreSQL.