Dies ist der zweite Teil meines Blogs „Meine bevorzugten PostgreSQL-Erweiterungen“, in dem ich Ihnen zwei PostgreSQL-Erweiterungen vorgestellt habe, postgres_fdw und pg_partman. In diesem Teil werde ich drei weitere untersuchen.
pgAudit
Die nächste PostgreSQL-Erweiterung von Interesse dient dem Zweck, Prüfungsanforderungen verschiedener Regierungs-, Finanz- und anderer Zertifizierungsstellen wie ISO, BSI und FISCAM usw. zu erfüllen. Die standardmäßige Protokollierungsfunktion, die PostgreSQL nativ anbietet mit log_statement =all ist für die Überwachung nützlich, liefert jedoch nicht die Details, die erforderlich sind, um die Prüfung zu erfüllen oder zu bestehen. Die pgAudit-Erweiterung konzentriert sich auf die Details dessen, was unter der Haube geschah, während eine Datenbank eine Anwendungsanfrage erfüllte.
Ein Audit-Trail oder Audit-Log wird von einer standardmäßigen Protokollierungseinrichtung erstellt und aktualisiert, die von PostgreSQL bereitgestellt wird, die eine detaillierte Sitzungs- und/oder Objekt-Audit-Protokollierung bereitstellt. Der von pgAudit erstellte Audit-Trail kann je nach Audit-Einstellungen enorm groß werden, daher muss sorgfältig entschieden werden, welche und wie viele Audits im Voraus erforderlich sind. Eine kurze Demo im folgenden Abschnitt zeigt, wie pgAudit konfiguriert und verwendet wird.
Der Log-Trail wird innerhalb des PostgreSQL-Datenbank-Cluster-Logs erstellt, das sich im Speicherort PGDATA/log befindet, aber den Audit-Log-Meldungen wird ein „AUDIT:“-Label vorangestellt, um zwischen regulären Datenbank-Hintergrundmeldungen und Audit-Log zu unterscheiden Aufzeichnungen.
Demo
Die offizielle Dokumentation von pgAudit erklärt, dass es eine separate Version von pgAudit für jede Hauptversion von PostgreSQL gibt, um neue Funktionen zu unterstützen, die in jeder PostgreSQL-Version eingeführt werden. Die Version von PostgreSQL in dieser Demo ist 11, daher wird die Version von pgAudit aus dem 1.3.X-Zweig stammen. pgaudit.log ist der grundlegende zu setzende Parameter, der steuert, welche Klassen von Anweisungen protokolliert werden. Es kann mit einem SET für eine Sitzungsebene oder innerhalb der postgresql.conf-Datei festgelegt werden, um global angewendet zu werden.
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>
Die Log-Einträge, wie in der Demo oben gezeigt, werden nur in die Hintergrund-Logdatei des Servers geschrieben, wenn der Parameter log_statement gesetzt ist, aber in diesem Fall ist es nicht konfiguriert, aber die Audit-Meldungen werden kraft Gesetzes geschrieben des Parameters pgaudit.log, wie in der Demo gezeigt. Es sind leistungsfähigere Optionen verfügbar, um alle Ihre Anforderungen an die Datenbankprüfung in PostgreSQL zu erfüllen, die konfiguriert werden können, indem Sie der offiziellen Dokumentation von pgaudit hier oder auf github repository.pg_repack
folgenDies ist eine beliebte Erweiterung vieler PostgreSQL-Ingenieure, die direkt an der Verwaltung und Aufrechterhaltung des allgemeinen Zustands eines PostgreSQL-Clusters beteiligt sind. Der Grund dafür wird etwas später besprochen, aber diese Erweiterung bietet die Funktionalität zum Entfernen von Datenbankaufblähungen innerhalb einer PostgreSQL-Datenbank, was eines der nagenden Bedenken bei sehr großen PostgreSQL-Datenbankclustern ist, die eine Neuorganisation der Datenbank erfordern.
Da eine PostgreSQL-Datenbank konstanten und starken WRITES (Aktualisierungen und Löschungen) unterzogen wird, werden die alten Daten als gelöscht markiert, während die neue Version der Zeile eingefügt wird, aber die alten Daten werden nicht wirklich aus a gelöscht Datenblock. Dies erfordert einen regelmäßigen Wartungsvorgang namens Bereinigung, bei dem es sich um ein automatisiertes Verfahren handelt, das im Hintergrund ausgeführt wird und alle „als gelöscht markierten“ Zeilen löscht. Dieser Vorgang wird umgangssprachlich manchmal als Garbage Collection bezeichnet.
Der Bereinigungsprozess weicht in geschäftigen Zeiten im Allgemeinen den Datenbankoperationen. Die am wenigsten restriktive Art der Bereinigung zugunsten von Datenbankvorgängen führt zu einer großen Anzahl von „als gelöscht markierten“ Zeilen, die dazu führen, dass Datenbanken überproportional wachsen, was als „Datenbankaufblähung“ bezeichnet wird. Es gibt einen erzwungenen Bereinigungsprozess namens VACUUM FULL, der jedoch dazu führt, dass eine exklusive Sperre für das verarbeitete Datenbankobjekt erworben wird, wodurch Datenbankoperationen für dieses Objekt blockiert werden.
pg_repack
Aus diesem Grund ist pg_repack ein Hit unter PostgreSQL-DBAs und -Ingenieuren, da es die Aufgabe eines normalen Bereinigungsprozesses erfüllt, aber eine Effizienz von VACUUM FULL bietet, indem es keine exklusive Sperre für eine Datenbank erwirbt Objekt, kurz gesagt, es funktioniert online. Die offizielle Dokumentation hier erklärt mehr über die anderen Methoden zum Reorganisieren einer Datenbank, aber eine kurze Demo wie unten wird die Dinge zum besseren Verständnis in ein angemessenes Licht rücken. Es gibt eine Anforderung, dass die Zieltabelle mindestens eine Spalte haben muss, die als PRIMARY KEY definiert ist, was eine allgemeine Norm in den meisten Produktionsdatenbank-Setups ist.
Demo
Die grundlegende Demo zeigt die Installation und Verwendung von pg_repack in einer Testumgebung. Diese Demo verwendet die Version 1.4.5 von pg_repack, die zum Zeitpunkt der Veröffentlichung dieses Blogs die neueste Version dieser Erweiterung ist. Eine Demo-Tabelle t1 hat anfänglich 80000 Zeilen, die einem massiven Löschvorgang unterzogen werden, der jede 5. Zeile der Tabelle löscht. Eine Ausführung von pg_repack zeigt die Größe der Tabelle davor und danach.
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
Die Funktion delete5 löscht 200.000 Zeilen aus der Tabelle t1 unter Verwendung eines Zählers, der um 5 Zähler erhöht wird
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)
Wie oben gezeigt, ändert sich die ursprüngliche Größe der Tabelle nach dem Ausführen der Funktion delete5 nicht, was zeigt, dass die Zeilen noch in der Tabelle vorhanden sind. Die Ausführung von pg_repack löscht diese „als gelöscht markierten“ Zeilen aus der t1-Tabelle, wodurch die Größe der t1-Tabelle auf 57 MB reduziert wird. Eine weitere gute Sache an pg_repack ist eine Option für Probeläufe mit dem Flag -N, mit der Sie überprüfen können, was während eines tatsächlichen Laufs ausgeführt wird.
HypoPG
Die nächste interessante Erweiterung ist identisch mit einem beliebten Konzept namens unsichtbare Indizes bei proprietären Datenbankservern. Die HypoPG-Erweiterung ermöglicht es einem DBA, die Auswirkung der Einführung eines hypothetischen Index (der nicht existiert) zu sehen und ob er die Leistung einer oder mehrerer Abfragen verbessern wird, und daher der Name HypoPG.
Die Erstellung eines hypothetischen Index erfordert keine CPU- oder Festplattenressourcen, verbraucht jedoch den privaten Speicher einer Verbindung. Da der hypothetische Index nicht in Datenbankkatalogtabellen gespeichert wird, gibt es keine Auswirkungen auf das Aufblähen von Tabellen. Aus diesem Grund kann ein hypothetischer Index nicht in einer EXPLAIN ANALYZE-Anweisung verwendet werden, während ein einfaches EXPLAIN eine gute Methode darstellt, um zu beurteilen, ob ein potenzieller Index von einer gegebenen problematischen Abfrage verwendet wird. Hier ist eine kurze Demo, die erklärt, wie HypoPG funktioniert.
Demo
Ich werde eine Tabelle mit 100000 Zeilen mit generate_series erstellen und ein paar einfache Abfragen ausführen, um den Unterschied zwischen Kostenschätzungen mit und ohne hypothetische Indizes zu zeigen.
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)
Die obige Abbildung zeigt, wie die geschätzten Gesamtkosten von 1791 auf 8,06 reduziert werden können, indem ein Index zum „id“-Feld der Tabelle hinzugefügt wird, um eine einfache Abfrage zu optimieren. Es beweist auch, dass der Index nicht wirklich verwendet wird, wenn die Abfrage mit einem EXPLAIN ANALYZE ausgeführt wird, das die Abfrage in Echtzeit ausführt. Es gibt auch eine Möglichkeit herauszufinden, wie viel Speicherplatz der Index ungefähr belegt, indem Sie die Funktion hypopg_list_indexes der Erweiterung verwenden.
Das HypoPG hat einige andere Funktionen, um hypothetische Indizes zu verwalten, und darüber hinaus bietet es auch eine Möglichkeit herauszufinden, ob die Partitionierung einer Tabelle die Leistung von Abfragen verbessert, die einen großen Datensatz abrufen. Es gibt eine hypothetische Partitionierungsoption der HypoPG-Erweiterung und mehr davon kann durch Bezugnahme auf die offizielle Dokumentation verfolgt werden.
Fazit
Wie bereits in Teil 1 erwähnt, hat sich PostgreSQL im Laufe der Jahre dahingehend entwickelt, dass es immer größer, besser und schneller wurde, und zwar sowohl im nativen Quellcode als auch bei Plug-and-Play-Erweiterungen. Eine Open-Source-Version des neuen PostgreSQL kann für viele IT-Shops, die einen der großen proprietären Datenbankserver betreiben, am besten geeignet sein, um ihre IT-CAPEX und OPEX zu reduzieren.
Es gibt viele PostgreSQL-Erweiterungen, die Funktionen bieten, die von der Überwachung bis zur Hochverfügbarkeit und von der Skalierung bis zum Speichern binärer Datendateien in ein für Menschen lesbares Format reichen. Wir hoffen, dass die obigen Demonstrationen ein enormes Licht auf das maximale Potenzial und die Leistungsfähigkeit einer PostgreSQL-Datenbank geworfen haben.