Това е втората част от моя блог „Моите любими разширения на PostgreSQL“, в която ви запознах с две разширения на PostgreSQL, postgres_fdw и pg_partman. В тази част ще разгледам още три.
pgAudit
Следващото разширение на PostgreSQL, представляващо интерес, е с цел удовлетворяване на изискванията за одит от различни правителствени, финансови и други сертифициращи органи като ISO, BSI и FISCAM и др. Стандартното средство за регистриране, което PostgreSQL предлага първоначално с log_statement =all е полезно за наблюдение, но не предоставя подробностите, необходими за спазване или изправяне на одита. Разширението pgAudit се фокусира върху подробностите за случилото се под капака, докато база данни удовлетворяваше заявка за приложение.
Одиторска пътека или дневник за одит се създава и актуализира от стандартно средство за регистриране, предоставено от PostgreSQL, което предоставя подробен регистрационен файл на сесия и/или обект. Одитната пътека, създадена от pgAudit, може да придобие огромен размер в зависимост от настройките на одита, така че трябва да се внимава, за да се реши какво и колко одит се изисква предварително. Кратка демонстрация в следващия раздел показва как pgAudit е конфигуриран и използван.
Пътеката на регистрационния файл се създава в клъстерния дневник на базата данни PostgreSQL, който се намира в местоположението на PGDATA/log, но съобщенията в регистъра на одита са с префикс с етикет „AUDIT:“ за разграничаване между обикновените фонови съобщения на базата данни и дневника за одит записи.
Демо
Официалната документация на pgAudit обяснява, че съществува отделна версия на pgAudit за всяка основна версия на PostgreSQL, за да се поддържа нова функционалност, въведена във всяка версия на PostgreSQL. Версията на PostgreSQL в тази демонстрация е 11, така че версията на pgAudit ще бъде от клона 1.3.X. pgaudit.log е основният параметър, който трябва да се зададе, който контролира кои класове изрази ще бъдат регистрирани. Може да бъде зададен с SET за ниво на сесия или във файла postgresql.conf, за да се прилага глобално.
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>
Записите в дневника, както е показано в демонстрацията по-горе, се записват във фоновия лог файл на сървъра само когато е зададен параметърът log_statement, но в този случай той не е конфигуриран, а съобщенията за одит се записват по силата на параметъра pgaudit.log, както е показано в демонстрацията. Налични са по-мощни опции за изпълнение на всички ваши изисквания за одит на база данни в PostgreSQL, които могат да бъдат конфигурирани, като следвате официалната документация на pgaudit тук или в github repository.pg_repack
Това е любимо разширение сред много инженери на PostgreSQL, които участват директно в управлението и поддържането на общото здраве на PostgreSQL клъстер. Причината за това ще бъде обсъдена малко по-късно, но това разширение предлага функционалност за премахване на раздуване на база данни в PostgreSQL база данни, което е един от заядливите проблеми сред много големите PostgreSQL клъстери от бази данни, изискващи реорганизация на базата данни.
Тъй като PostgreSQL база данни претърпява постоянни и тежки ЗАПИСИ (актуализации и изтривания), старите данни се маркират като изтрити, докато новата версия на реда се вмъква, но старите данни всъщност не се изтриват от блок данни. Това изисква периодична операция по поддръжка, наречена вакуумиране, която е автоматизирана процедура, която се изпълнява във фонов режим, която изчиства всички „маркирани като изтрити“ редове. Този процес понякога се нарича събиране на боклук в разговорни термини.
Процесът на вакуумиране обикновено отстъпва място на операциите с базата данни по време на по-натоварено време. Най-малко ограничителният начин на вакуумиране в полза на операциите с базата данни води до голям брой „маркирани като изтрити“ редове, причиняващи нарастване на базите данни извън пропорцията, наричана „раздуване на базата данни“. Има процес на принудително вакуумиране, наречен VACUUM FULL, но това води до придобиване на изключително заключване на обекта на базата данни, който се обработва, спирайки операциите на базата данни върху този обект.
pg_repack
Именно поради тази причина pg_repack е хит сред PostgreSQL DBA и инженерите, защото върши работата на нормален процес на вакуумиране, но предлага ефективност на VACUUM FULL, като не придобива изключително заключване на база данни обект, накратко, работи онлайн. Официалната документация тук обяснява повече за другите методи за реорганизиране на база данни, но една бърза демонстрация, както е по-долу, ще постави нещата в подходяща светлина за по-добро разбиране. Има изискване целевата таблица да има поне една колона, дефинирана като ПЪРВИЧЕН КЛЮЧ, което е обща норма в повечето настройки на производствената база данни.
Демо
Основната демонстрация показва инсталирането и използването на pg_repack в тестова среда. Тази демонстрация използва версия 1.4.5 на pg_repack, която е най-новата версия на това разширение към момента на публикуване на този блог. Демо таблица t1 първоначално има 80000 реда, които претърпяват масивна операция на изтриване, която изтрива всеки 5-ти ред от таблицата. Изпълнението на pg_repack показва размера на таблицата преди и след.
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
Функцията delete5 изтрива 200 000 реда от таблица t1 с помощта на брояч, който увеличава 5 броя
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)
Както е показано по-горе, оригиналният размер на таблицата не се променя след изпълнение на функцията delete5 , което показва, че редовете все още съществуват в таблицата. Изпълнението на pg_repack изчиства тези „маркирани като изтрити“ редове от таблицата t1, намалявайки размера на таблицата t1 до 57 MB. Друго добро нещо за pg_repack е опция за сухо изпълнение с -N флаг, с помощта на който можете да проверите какво ще бъде изпълнено по време на действително изпълнение.
HypoPG
Следващото интересно разширение е идентично с популярната концепция, наречена невидими индекси сред собствените сървъри на бази данни. Разширението HypoPG позволява на DBA да види ефекта от въвеждането на хипотетичен индекс (който не съществува) и дали ще подобри производителността на една или повече заявки, а оттам и името HypoPG.
Създаването на хипотетичен индекс не изисква никакви централни или дискови ресурси, но консумира личната памет на връзката. Тъй като хипотетичният индекс не се съхранява в никакви каталожни таблици на базата данни, така че няма влияние на раздуването на таблицата. Поради тази причина хипотетичен индекс не може да се използва в оператор EXPLAIN ANALYZE, докато обикновеният EXPLAIN е добър начин да се оцени дали потенциален индекс ще бъде използван от дадена проблемна заявка. Ето кратка демонстрация, която обяснява как работи HypoPG.
Демо
Ще създам таблица, съдържаща 100 000 реда, използвайки generate_series и ще изпълня няколко прости заявки, за да покажа разликата в оценките на разходите със и без хипотетични индекси.
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)
Горещият експонат показва как прогнозната обща цена може да бъде намалена от 1791 на 8,06 чрез добавяне на индекс към полето „id“ на таблицата, за да се оптимизира проста заявка. Той също така доказва, че индексът не се използва реално, когато заявката се изпълнява с EXPLAIN ANALYZE, който изпълнява заявката в реално време. Има и начин да разберете приблизително колко дисково пространство заема индексът, като използвате функцията hypopg_list_indexes на разширението.
HypoPG има няколко други функции за управление на хипотетични индекси и в допълнение към това предлага и начин да разберете дали разделянето на таблица ще подобри производителността на заявките, извличащи голям набор от данни. Има хипотетична опция за разделяне на разширението HypoPG и повече от него могат да бъдат последвани, като се обърнете към официалната документация.
Заключение
Както е посочено в част първа, PostgreSQL се е развил през годините, като става все по-голям, по-добър и по-бърз с бързо развитие както в родния изходен код, така и в разширенията plug and play. Версията с отворен код на новия PostgreSQL може да бъде най-подходяща за много ИТ магазини, които работят с един от основните собствени сървъри за бази данни, за да намалят техните ИТ CAPEX и OPEX.
Има много разширения на PostgreSQL, които предлагат функции, вариращи от наблюдение до висока наличност и от мащабиране до изхвърляне на двоични файлове с данни в четим от човека формат. Надяваме се, че горните демонстрации хвърлят огромна светлина върху максималния потенциал и мощност на PostgreSQL база данни.