PostgreSQL is een van de meest populaire open-sourcedatabases ter wereld en heeft succesvolle implementaties in verschillende bedrijfskritieke omgevingen in verschillende domeinen, met behulp van realtime high-end OLTP-applicaties die miljoenen en miljarden transacties per dag uitvoeren. PostgreSQL I/O is redelijk betrouwbaar, stabiel en presteert op vrijwel alle hardware, zelfs in de cloud.
Om ervoor te zorgen dat databases op de verwachte schaal presteren met verwachte responstijden, is er wat prestatie-engineering nodig. Welnu, het bereiken van goede databaseprestaties hangt af van verschillende factoren. Databaseprestaties kunnen om verschillende redenen slecht gaan, zoals infrastructuurdimensionering, inefficiënte database-onderhoudsstrategie, slechte SQL-code of slecht geconfigureerde databaseprocessen die niet alle beschikbare bronnen gebruiken - CPU, geheugen, netwerkbandbreedte en schijf-I/O.
Wat kan ervoor zorgen dat de databaseprestaties afnemen?
- Slecht geschreven queries met slechte joins, logica enz. die veel CPU en geheugen vergen
- Query's die volledige-tabel-scans uitvoeren op grote tafels vanwege onjuiste indexering
- Slecht database-onderhoud zonder goede statistieken
- Inefficiënte capaciteitsplanning resulterend in onvoldoende gedimensioneerde infrastructuur
- Onjuist logisch en fysiek ontwerp
- Geen verbindingspooling, waardoor applicaties op een oncontroleerbare manier een groot aantal verbindingen maken
Dat zijn dus veel potentiële gebieden die prestatieproblemen kunnen veroorzaken. Een van de belangrijke gebieden waarop ik me in deze blog wil concentreren, is het afstemmen van de PostgreSQL I/O-prestaties (Input / Output). Het afstemmen van de input/output-bewerkingen van PostgreSQL is essentieel, vooral in een omgeving met veel transacties zoals OLTP of in een datawarehousing-omgeving met complexe data-analyse op enorme datasets.
Meestal worden problemen met de databaseprestaties voornamelijk veroorzaakt door hoge I/O. Dit betekent dat databaseprocessen meer tijd besteden aan het schrijven naar of lezen van de schijf. Elke realtime gegevensbewerking is I/O-gebonden, het is absoluut noodzakelijk om ervoor te zorgen dat de database I/O-afgestemd is. In deze blog zal ik me concentreren op veelvoorkomende I/O-problemen die PostgreSQL-databases kunnen tegenkomen in realtime productieomgevingen.
PostgreSQL I/O afstemmen
Het afstemmen van PostgreSQL I/O is absoluut noodzakelijk voor het bouwen van een zeer performante en schaalbare database-architectuur. Laten we eens kijken naar verschillende factoren die van invloed zijn op de I/O-prestaties:
- Indexeren
- Partitioneren
- Checkpoints
- VACUM, ANALYSEREN (met FILLFACTOR)
- Andere I/O-problemen
- PostgreSQL I/O op cloud
- Extra
Indexeren
Indexering is een van de belangrijkste afstemmingstechnieken die een cruciale rol spelen bij het verbeteren van de I/O-prestaties van de database. Dit geldt eigenlijk voor elke database. PostgreSQL ondersteunt verschillende indextypen die leesbewerkingen in hoge mate kunnen versnellen, wat een verbeterde schaalbaarheid voor toepassingen oplevert. Hoewel het maken van indexen vrij eenvoudig en duidelijk is, is het essentieel voor DBA's en ontwikkelaars om te weten welk type index ze moeten kiezen en op welke kolommen. Dit laatste is gebaseerd op verschillende factoren, zoals de complexiteit van de query, het gegevenstype, de gegevenskardinaliteit, het schrijfvolume, de gegevensgrootte, de schijfarchitectuur, de infrastructuur (public cloud, private cloud of on-premises), enz.
Hoewel indexering de leesprestaties van query's drastisch kan verbeteren, kan het ook de schrijfacties op de geïndexeerde kolommen vertragen. Laten we een voorbeeld bekijken:
Impact van indexen op READ-bewerkingen
Een tabel genaamd emp met ongeveer 1 miljoen rijen.
LEES Prestaties zonder een Index
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
-----+---------------+--------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 70.020 ms => took about 70+ milli-seconds to respond with on row
LEES Prestaties met een Index
Laten we een index op de eid-kolom plaatsen en het verschil zien
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
------+-------------+-------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 0.454 ms => 0.4+ milli-seconds!!! thats a huge difference - isn’t it?
Indexeren is dus belangrijk.
Impact van indexen op WRITE-bewerkingen
Indexen vertragen de schrijfprestaties. Hoewel de indexen een impact hebben op alle soorten schrijfbewerkingen, laten we eens kijken naar een analyse van de impact van indexen op INSERT's
1 miljoen rijen invoegen in een tabel zonder indexen
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 4818.470 ms (00:04.818) => Takes about 4.8 seconds
Dezelfde 1 miljoen rijen invoegen met een index
Laten we eerst een Index maken
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 7825.494 ms (00:07.825) => Takes about 7.8 seconds
Dus, zoals we kunnen zien, nam de INSERT-tijd toe met 80% met slechts één index en het kan veel meer tijd kosten om te voltooien wanneer er meerdere indexen zijn. Het kan nog erger worden als er functiegebaseerde indexen zijn. Dat is waar DBA's mee moeten leven! Indexen zullen de schrijfprestaties verhogen. Er zijn echter manieren om dit probleem aan te pakken, dat afhankelijk is van de schijfarchitectuur. Als de databaseserver meerdere schijfbestandssystemen gebruikt, kunnen de indexen en tabellen over meerdere tabelruimten worden geplaatst die zich over meerdere schijfbestandssystemen bevinden. Op deze manier kunnen betere I/O-prestaties worden bereikt.
TIPS voor indexbeheer
- Begrijp de noodzaak van indexen. Intelligent indexeren is de sleutel.
- Vermijd het maken van meerdere indexen, en zeker geen onnodige indexen, dit kan de schrijfprestaties echt verslechteren.
- Bewaak het gebruik van indexen en verwijder ongebruikte indexen.
- Als geïndexeerde kolommen worden onderworpen aan gegevenswijzigingen, worden indexen ook opgeblazen. Dus reorganiseer regelmatig indexen.
Partitionering
Een effectieve partitioneringsstrategie kan I/O-prestatieproblemen aanzienlijk verminderen. Grote tabellen kunnen worden gepartitioneerd op basis van bedrijfslogica. PostgreSQL ondersteunt tabelpartitionering. Hoewel het momenteel niet alle functies volledig ondersteunt, kan het alleen helpen bij enkele van de realtime use-cases. In PostgreSQL zijn gepartitioneerde onderliggende tabellen volledig individueel voor de hoofdtabel, wat een knelpunt is. Beperkingen die zijn gemaakt op de hoofdtabel kunnen bijvoorbeeld niet automatisch worden overgenomen naar de onderliggende tabellen.
Vanuit het perspectief van balancerend I/O kan partitionering echter echt helpen. Alle onderliggende partities kunnen worden verdeeld over meerdere tablespaces en schijfbestandssystemen. Query's met een datumbereik in de "where"-clausule die de tabel raken, gepartitioneerd op basis van datumbereik, kunnen profiteren van partitionering door slechts één of twee partities te scannen in plaats van de volledige tabel.
Controlepunten
Checkpoints bepalen de consistente staat van de database. Ze zijn van cruciaal belang en het is belangrijk dat controlepunten regelmatig genoeg plaatsvinden om ervoor te zorgen dat gegevenswijzigingen permanent op schijf worden opgeslagen en dat de database altijd in een consistente staat verkeert. Dat gezegd hebbende, kan een onjuiste configuratie van controlepunten leiden tot problemen met de I/O-prestaties. DBA's moeten nauwgezet zijn bij het configureren van controlepunten om ervoor te zorgen dat er geen I/O-piek is en dit hangt ook af van hoe goed de schijven zijn en hoe goed de lay-out van de gegevensbestanden is ontworpen.
Welk controlepunt doet ?
In eenvoudige bewoordingen zorgen checkpoints voor:
- Alle vastgelegde gegevens worden naar de gegevensbestanden op de schijf geschreven.
- klompbestanden worden bijgewerkt met de vastleggingsstatus.
- Transactielogbestanden in de map pg_xlog (nu pg_wal) worden hergebruikt.
Dat verklaart hoe I/O-intensieve checkpoints zijn. Er zijn parameters in postgresql.conf die kunnen worden geconfigureerd / afgestemd om het gedrag van checkpoints te controleren en die parameters zijn max_wal_size, min_wal_size, checkpoint_timeout en checkpoint_completion_target. Deze parameters bepalen hoe vaak de checkpoints moeten plaatsvinden en binnen hoeveel tijd de checkpoints moeten eindigen.
Hoe te begrijpen welke configuratie beter is voor checkpoints? Hoe stem je ze af?
Hier zijn enkele tips:
- Evalueer de database TPS. Evalueer het totale aantal transacties dat op een werkdag in de database plaatsvindt en identificeer ook op welk tijdstip het hoogste aantal transacties de database bereikt.
- Bespreek regelmatig met applicatieontwikkelaars en andere technische teams om inzicht te krijgen in de transactiesnelheidsstatistieken van de database en in de toekomstige transactiegroei.
- Dit kan ook vanaf de database worden gedaan:
-
Bewaak de database en evalueer het aantal transacties dat gedurende de dag plaatsvindt. Dit kan gedaan worden door pgcatalog-tabellen zoals pg_stat_user_tables op te vragen.
-
Evalueer het aantal wal-archiefbestanden dat per dag wordt gegenereerd
-
Controleer om te begrijpen hoe de controlepunten presteren door de parameter log_checkpoints in te schakelen
2018-06-06 15:03:16.446 IST [2111] LOG: checkpoint starting: xlog 2018-06-06 15:03:22.734 IST [2111] LOG: checkpoint complete: wrote 12112 buffers (73.9%); 0 WAL file(s) added, 0 removed, 25 recycled; write=6.058 s, sync=0.218 s, total=6.287 s; sync files=4, longest=0.178 s, average=0.054 s; distance=409706 kB, estimate=412479 kB
-
Begrijp of de huidige controlepuntconfiguratie goed genoeg is voor de database. Configureer de parameter checkpoint_warning (standaard geconfigureerd op 30 seconden) om de onderstaande waarschuwingen in de postgres-logbestanden te zien.
2018-06-06 15:02:42.295 IST [2111] LOG: checkpoints are occurring too frequently (11 seconds apart) 2018-06-06 15:02:42.295 IST [2111] HINT: Consider increasing the configuration parameter "max_wal_size".
-
Wat betekent bovenstaande waarschuwing?
Checkpoints vinden over het algemeen plaats wanneer max_wal_size (standaard 1 GB, wat 64 WAL-bestanden betekent) aan logbestanden is gevuld of wanneer checkpoint_timeout (elke 5 minuten elke standaard) wordt bereikt. De bovenstaande waarschuwing betekent dat de geconfigureerde max_wal_size niet adequaat is en dat de controlepunten elke 11 seconden plaatsvinden, wat op zijn beurt betekent dat 64 WAL-bestanden in de PG_WAL-directory in slechts 11 seconden worden gevuld, wat te vaak is. Met andere woorden, als er minder frequente transacties zijn, zullen de controlepunten elke 5 minuten plaatsvinden. Dus, zoals de hint suggereert, verhoog de parameter max_wal_size naar een hogere waarde, de parameter max_min_size kan worden verhoogd naar dezelfde of een kleinere dan de vorige.
Een andere kritische parameter om te overwegen vanuit het perspectief van I/O-prestaties is checkpoint_completion_target, dat standaard is geconfigureerd op 0,5.
checkpoint_completion_target =0,5 x checkpoint_timeout =2,5 minuten
Dat betekent dat controleposten 2,5 minuten de tijd hebben om de vuile blokken naar de schijf te synchroniseren. Is 2,5 minuut genoeg? Dat moet geëvalueerd worden. Als het aantal te schrijven vuile blokken erg hoog is, kan 2,5 minuut heel erg agressief lijken en dat is het moment waarop een I/O-piek kan worden waargenomen. Het configureren van de parameter completion_target moet worden gedaan op basis van max_wal_size en checkpoint_timeout-waarden. Als deze parameters naar een hogere waarde worden verhoogd, overweeg dan om checkpoint_completion_target dienovereenkomstig te verhogen.
VACUM, ANALYSEREN (met FILLFACTOR)
VACUUMM is een van de krachtigste functies van PostgreSQL. Het kan worden gebruikt om bloats (gefragmenteerde ruimte) in tabellen en indexen te verwijderen en wordt gegenereerd door transacties. De database moet regelmatig worden gestofzuigd om gezond onderhoud en betere prestaties te garanderen. Nogmaals, het niet regelmatig VACUMEN van de database kan leiden tot ernstige prestatieproblemen. ANALYSE moet samen met VACUUM (VACUUM ANALYZE) worden uitgevoerd om up-to-date statistieken voor de queryplanner te garanderen.
VACUM ANALYSE kan op twee manieren worden uitgevoerd:handmatig, automatisch of beide. In een realtime productieomgeving is het over het algemeen beide. Automatisch VACUM wordt ingeschakeld door de parameter "autovacuum" die standaard is geconfigureerd op "aan". Als autovacuüm is ingeschakeld, begint PostgreSQL automatisch met het periodiek VACUMEN van de tabellen. De kandidaat-tafels die moeten worden gestofzuigd, worden opgepikt door autovacuümprocessen op basis van verschillende drempels die zijn ingesteld door verschillende autovacuüm*-parameters. Deze parameters kunnen worden aangepast/afgesteld om ervoor te zorgen dat de tafels regelmatig opzwellen. Laten we eens kijken naar enkele parameters en hun gebruik -
Autovacuümparameters
autovacuum=aan | Deze parameter wordt gebruikt om autovacuüm in of uit te schakelen. Standaard is "aan". |
log_autovacuum_min_duration =-1 | Hiermee wordt de duur van het autovacuümproces vastgelegd. Dit is belangrijk om te begrijpen hoe lang het autovacuümproces duurde. |
autovacuum_max_workers =3 | Aantal autovacuümprocessen nodig. Dit hangt af van hoe agressief databasetransacties zijn en hoeveel CPU's u kunt aanbieden voor autovacuümprocessen. |
autovacuum_naptime =1 min | Autovacuüm rusttijd tussen autovacuüm runs. |
Parameters die de drempel definiëren voor het starten van het autovacuümproces
Autovacuümklus(sen) starten wanneer een bepaalde drempel is bereikt. Hieronder staan de parameters die kunnen worden gebruikt om een bepaalde drempel in te stellen, op basis waarvan het autovacuümproces zal starten.
autovacuum_vacuum_threshold =50 | De tabel wordt gestofzuigd wanneer minimaal 50 rijen worden bijgewerkt / verwijderd in een tabel. |
autovacuum_analyze_threshold =50 | De tabel wordt geanalyseerd wanneer minimaal 50 rijen worden bijgewerkt / verwijderd in een tabel. |
autovacuum_vacuum_scale_factor =0.2 | De tabel wordt leeggezogen wanneer minimaal 20% van de rijen in een tabel is bijgewerkt/verwijderd. |
autovacuum_analyze_scale_factor =0.1 | De tabel wordt leeggezogen wanneer minimaal 10% van de rijen in een tabel is bijgewerkt/verwijderd. |
Boven de drempelwaarde parameters kunnen worden gewijzigd op basis van databasegedrag. DBA's moeten de hete tafels analyseren en identificeren en ervoor zorgen dat die tafels zo vaak mogelijk worden gestofzuigd om goede prestaties te garanderen. Het bereiken van een bepaalde waarde voor deze parameters kan een uitdaging zijn in een omgeving met veel transacties, waarin gegevens elke seconde veranderen. Vaak heb ik gemerkt dat autovacuümprocessen vrij lang duren om te voltooien, waardoor uiteindelijk te veel bronnen in productiesystemen worden verbruikt.
Ik zou willen voorstellen om niet volledig afhankelijk te zijn van het autovacuümproces. De beste manier is om een nachtelijke VACUM ANALYSE-taak te plannen, zodat de belasting van het autovacuüm wordt verminderd. Overweeg om te beginnen handmatig grote tafels met een hoog transactiepercentage te VACUMEN.
VACUM VOL
VACUUM FULL helpt de opgeblazen ruimte in de tabellen en indexen terug te winnen. Dit hulpprogramma kan niet worden gebruikt wanneer de database online is, omdat het de tabel vergrendelt. Tabellen mogen alleen worden onderworpen aan VACUUM FULL wanneer de toepassingen zijn afgesloten. Indexen zullen ook opnieuw worden georganiseerd samen met tabellen tijdens VACUUM FULL.
Laten we eens kijken naar de impact van VACUUMM ANALYSE
Bloats:hoe herken je een bloat? Wanneer worden bloats gegenereerd?
Hier zijn enkele tests:
Ik heb een tabel van 1 GB met 10 miljoen rijen.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
----------------
1
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Laten we eens kijken naar de impact van bloats op een eenvoudige zoekopdracht:selecteer * van pgbench_accounts;
Hieronder vindt u het uitlegplan voor de vraag:
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.00 rows=10000000 width=97)
(actual time=0.033..1054.257 rows=10000000 loops=1)
Planning time: 0.255 ms
Execution time: 1494.448 ms
Laten we nu alle rijen in de tabel bijwerken en de impact van de bovenstaande SELECT-query bekijken.
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Hieronder vindt u het UITLEGPLAN van de uitvoering van de query na de UPDATE.
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..527868.39 rows=19999939 width=97)
(actual time=404.474..1520.175 rows=10000000 loops=1)
Planning time: 0.051 ms
Execution time: 1958.532 ms
De grootte van de tabel nam toe tot 2 GB na de UPDATE
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
2
Als je de kostencijfers van het eerdere EXPLAIN PLAN kunt observeren en vergelijken, is er een enorm verschil. De kosten zijn met een grote marge gestegen. Wat nog belangrijker is, als je goed kijkt, is het aantal rijen (iets meer dan 19 miljoen) dat wordt gescand na de UPDATE hoger, wat bijna twee keer zo groot is als het daadwerkelijke bestaande rijen (10 miljoen). Dat betekent dat het aantal opgeblazen rijen 9+ miljoen is en de werkelijke tijd ook is toegenomen en de uitvoeringstijd is toegenomen van 1,4 seconden naar 1,9 seconden.
Dat is dus de impact van het niet VACUMEN van de TAFEL na de UPDATE. De bovenstaande UITLEG PLAN-nummers betekenen precies dat de tafel opgeblazen is.
Hoe te identificeren of de tafel opgeblazen is? Gebruik pgstattuple contrib module:
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 9879891 | 1195466811 | 44.51 | 52096468 | 1.94
Het bovenstaande getal geeft aan dat de helft van de tafel opgeblazen is.
Laten we de tafel VACUM ANALYSEREN en nu de impact zien:
postgres=# VACUUM ANALYZE pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..428189.05 rows=10032005 width=97)
(actual time=400.023..1472.118 rows=10000000 loops=1)
Planning time: 4.374 ms
Execution time: 1913.541 ms
Na VACUUMM ANALYSE zijn de kostenaantallen gedaald. Nu is het aantal gescande rijen bijna 10 miljoen, ook de werkelijke tijd en de uitvoeringstijd zijn niet veel veranderd. Dat komt omdat, hoewel de zwellingen in de tafel zijn verdwenen, de grootte van de te scannen tafel hetzelfde blijft. Hieronder staat de pgstattuple-uitvoerpost VACUUMM ANALYSE.
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 0 | 0 | 0 | 1316722516 | 49.02
Bovenstaand getal geeft aan dat alle bloats (dode tupels) zijn verdwenen.
Laten we eens kijken naar de impact van VACUUM FULL ANALYZE en zien wat er gebeurt:
postgres=# vacuum full analyze pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.35 rows=10000035 width=97)
(actual time=0.015..1089.726 rows=10000000 loops=1)
Planning time: 0.148 ms
Execution time: 1532.596 ms
Als u opmerkt, zijn de werkelijke tijd en de uitvoeringstijdnummers vergelijkbaar met de cijfers vóór UPDATE. Ook is de grootte van de tafel nu afgenomen van 2 GB naar 1 GB.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
1
Dat is de impact van VACUUM FULL.
FILLFACTOR
FILLFACTOR is een zeer belangrijk attribuut dat echt verschil kan maken voor de database-onderhoudsstrategie op tabel- en indexniveau. Deze waarde geeft de hoeveelheid ruimte aan die door de INSERT's binnen een gegevensblok moet worden gebruikt. De FILLFACTOR-waarde is standaard 100%, wat betekent dat INSERT's alle beschikbare ruimte in een gegevensblok kunnen gebruiken. Het betekent ook dat er geen ruimte beschikbaar is voor UPDATEs. Deze waarde kan worden verlaagd tot een bepaalde waarde voor sterk bijgewerkte tabellen.
Deze parameter kan worden geconfigureerd voor elke tabel en een index. Als FILLFACTOR op de optimale waarde is geconfigureerd, ziet u ook echt verschil in VACUUM-prestaties en queryprestaties. Kortom, optimale FILLFACTOR-waarden zorgen ervoor dat er geen onnodig aantal blokken wordt toegewezen.
Laten we naar hetzelfde voorbeeld hierboven kijken -
De tabel heeft een miljoen rijen
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Voor de update is de grootte van de tabel 1 GB
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
--------
1
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
Na de update is de tabel na de UPDATE vergroot tot 2 GB
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
---------
2
Dat betekent dat het aantal aan de tafel toegewezen blokken met 100% is toegenomen. Als de FILLFACTOR was geconfigureerd, is de grootte van de tabel mogelijk niet met die marge toegenomen.
Hoe weet u welke waarde u moet configureren voor FILLFACTOR?
Het hangt allemaal af van welke kolommen worden bijgewerkt en de grootte van de bijgewerkte kolommen. Over het algemeen zou het goed zijn om de FILLFACTOR-waarde te evalueren door deze uit te testen in UAT-databases. Als de kolommen die worden bijgewerkt bijvoorbeeld 10% van de hele tabel zijn, overweeg dan om de vulfactor in te stellen op 90% of 80%.
Belangrijke opmerking:
Als u de FILLFACTOR-waarde voor de bestaande tabel met de gegevens wijzigt, moet u een VACUUM FULL of een reorganisatie van de tabel uitvoeren om ervoor te zorgen dat de FILLFACTOR-waarde van kracht is voor de bestaande gegevens.
TIPS VOOR VACUMEREN
- Zoals hierboven gezegd, overweeg om de taak VACUM ANALYSE elke nacht handmatig uit te voeren op de intensief gebruikte tafels, zelfs wanneer autovacuüm is ingeschakeld.
- Overweeg om VACUUM ANALYZE uit te voeren op tabellen na bulk INSERT. Dit is belangrijk omdat velen denken dat VACUMEN misschien niet nodig is na INSERT's.
- Bewaak om ervoor te zorgen dat zeer actieve tabellen regelmatig worden VACUUMED door de tabel pg_stat_user_tables op te vragen.
- Gebruik de module pg_stattuple contrib om de grootte van de opgeblazen ruimte binnen de tabelsegmenten te identificeren.
- Het hulpprogramma VACUUM FULL kan niet worden gebruikt op productiedatabasesystemen. Overweeg het gebruik van tools zoals pg_reorg of pg_repack, waarmee u tabellen en indexen online kunt reorganiseren zonder vergrendelingen.
- Zorg ervoor dat het AUTOVACUUM-proces langer wordt uitgevoerd tijdens kantooruren (veel verkeer).
- Schakel de parameter log_autovacuum_min_duration in om de timing en duur van AUTOVACUUM-processen te loggen.
- Belangrijk is om ervoor te zorgen dat FILLFACTOR is geconfigureerd voor een optimale waarde op tabellen en indexen met veel transacties.
Andere I/O-problemen
Schijf sorteren
Query's die sorteren uitvoeren, komen ook veel voor in realtime productiedatabases en de meeste hiervan kunnen niet worden vermeden. Query's die gebruik maken van clausules zoals GROUP BY, ORDER BY, DISTINCT, CREATE INDEX, VACUUM FULL etc. voeren het sorteren uit en het sorteren kan op schijf plaatsvinden. Sorteren vindt plaats in het geheugen als de selectie en sortering gebeurt op basis van geïndexeerde kolommen. Hier spelen samengestelde indexen een sleutelrol. Indexen worden agressief in het geheugen opgeslagen. Anders, als het nodig is om de gegevens op de schijf te sorteren, zouden de prestaties drastisch afnemen.
Om ervoor te zorgen dat het sorteren in het geheugen plaatsvindt, kan de parameter work_mem worden gebruikt. Deze parameter kan zo worden geconfigureerd dat de hele sortering in het geheugen kan worden uitgevoerd. Het belangrijkste voordeel van deze parameter is dat deze, naast de configuratie in postgresql.conf, ook kan worden geconfigureerd op sessieniveau, gebruikersniveau of databaseniveau. Hoeveel moet de waarde work_mem zijn? Hoe weet u welke query's schijfsortering uitvoeren? Hoe kunt u query's controleren die schijfsortering uitvoeren op een realtime productiedatabase?
Het antwoord is - configureer de parameter log_temp_files op een bepaalde waarde. De waarde is in bytes, een waarde van 0 registreert alle tijdelijke bestanden (samen met hun grootte) die op schijf zijn gegenereerd vanwege schijfsortering. Zodra de parameter is geconfigureerd, kunt u de volgende berichten zien in de logbestanden
2018-06-07 22:48:02.358 IST [4219] LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp4219.0", size 200425472
2018-06-07 22:48:02.358 IST [4219] STATEMENT: create index bid_idx on pgbench_accounts(bid);
2018-06-07 22:48:02.366 IST [4219] LOG: duration: 6421.705 ms statement: create index bid_idx on pgbench_accounts(bid);
Het bovenstaande bericht betekent dat de CREATE INDEX-query schijfsortering uitvoerde en een bestand met een grootte van 200425472 bytes heeft gegenereerd, wat 191+ MB is. Dat betekent precies dat de parameter work_mem moet worden geconfigureerd op 191+ MB of hoger voordat deze specifieke query geheugensortering kan uitvoeren.
Welnu, voor de toepassingsquery's kan de parameter work_mem alleen worden geconfigureerd op gebruikersniveau. Voordat u dit doet, moet u rekening houden met het aantal verbindingen dat de gebruiker maakt met de database en het aantal sorteerquery's dat door die gebruiker wordt uitgevoerd. Omdat PostgreSQL probeert work_mem toe te wijzen aan elk proces (sortering uitvoert) in elke verbinding, wat mogelijk het geheugen op de databaseserver zou kunnen uithongeren.
Indeling database bestandssysteem
Het ontwerpen van een efficiënte en prestatiebevorderende lay-out van het databasebestandssysteem is belangrijk vanuit het oogpunt van prestaties en schaalbaarheid. Belangrijk is dat dit niet afhankelijk is van de databasegrootte. Over het algemeen is de perceptie dat enorme databases een krachtige schijfarchitectuur nodig hebben, wat NIET waar is. Zelfs als de databasegrootte 50 GB is, hebt u mogelijk een goede schijfarchitectuur nodig. En dit is misschien niet mogelijk zonder extra kosten.
Hier zijn enkele TIPS voor hetzelfde:
- Zorg ervoor dat de database meerdere tabelruimten heeft, met tabellen en indexen die zijn gegroepeerd op basis van de transactietarieven.
- De tabelruimte moet over meerdere schijfbestandssystemen worden geplaatst voor gebalanceerde I/O. Dit zorgt er ook voor dat meerdere CPU's in het spel komen om transacties over meerdere schijven uit te voeren.
- Overweeg om de map pg_xlog of pg_wal op een aparte schijf in een database met veel transacties te plaatsen.
- Zorg ervoor dat *_kostenparameters worden geconfigureerd op basis van de infrastructuur
- Gebruik iostat, mpstat en andere I/O-bewakingstools om de I/O-statistieken op alle schijven te begrijpen en de database-objecten dienovereenkomstig te ontwerpen/beheren.
PostgreSQL in de cloud
Infrastructuur is van cruciaal belang voor goede databaseprestaties. Strategieën voor prestatie-engineering verschillen op basis van infrastructuur en omgeving. Er moet speciale aandacht worden besteed aan PostgreSQL-databases die in de cloud worden gehost. Prestatiebenchmarking voor databases die worden gehost op fysieke barebone-servers in een lokaal datacenter kan heel anders zijn dan databases die in de openbare cloud worden gehost.
Over het algemeen kunnen cloudinstanties iets langzamer zijn en verschillen benchmarks aanzienlijk, vooral op het gebied van I/O. Voer altijd I/O-latentiecontroles uit voordat u een cloudinstantie kiest/bouwt. Tot mijn verbazing ontdekte ik dat de prestaties van cloudinstanties ook per regio kunnen verschillen, ook al zijn ze van dezelfde cloudprovider. Om dit verder uit te leggen:een cloudinstantie met dezelfde specificaties die in twee verschillende regio's is gebouwd, kan verschillende prestatieresultaten opleveren.
Bulk data laden
Offline bulkbewerkingen voor het laden van gegevens zijn vrij gebruikelijk in de databasewereld. Ze kunnen een aanzienlijke I/O-belasting genereren, wat op zijn beurt de prestaties van de gegevensbelasting vertraagt. In mijn ervaring als DBA heb ik met dergelijke uitdagingen te maken gehad. Vaak wordt het laden van gegevens vreselijk traag en moet worden afgestemd. Hier zijn een paar tips. Let op, deze zijn alleen van toepassing op offline bewerkingen voor het laden van gegevens en kunnen niet worden overwogen voor het laden van gegevens in de live-productiedatabase.
- Aangezien de meeste bewerkingen voor het laden van gegevens buiten kantooruren worden uitgevoerd, moet u ervoor zorgen dat de volgende parameters zijn geconfigureerd tijdens het laden van gegevens -
- Configureer checkpoint-gerelateerde waarden die groot genoeg zijn zodat checkpoints geen prestatieproblemen veroorzaken.
- Schakel full_page_write uit
- Wal archivering uitschakelen
- Configureer de parameter synchronous_commit op "off"
- Drop-beperkingen en indexen voor die tabellen die zijn onderworpen aan de gegevensbelasting (beperkingen en indexen kunnen opnieuw worden gemaakt na de gegevensbelasting met een grotere work_mem-waarde)
- Als je de gegevens uit een CSV-bestand laadt, kan een grotere maintenance_work_mem goede resultaten opleveren.
- Hoewel er een aanzienlijk prestatievoordeel zal zijn, mag u de fsync-parameter NIET uitschakelen, aangezien dit tot gegevensbeschadiging kan leiden.
TIPS voor analyse van cloudprestaties
- Voer grondige I/O-latentietests uit met pgbench. In mijn ervaring had ik vrij gewone prestatieresultaten bij het uitvoeren van schijflatentiecontroles als onderdeel van TPS-evaluatie. Er waren problemen met de cacheprestaties op sommige openbare cloudinstanties. Dit helpt bij het kiezen van de juiste specificaties voor de cloudinstantie die voor de databases is gekozen.
- Cloud-instanties kunnen per regio anders presteren. Een cloudinstantie met bepaalde specificaties in een regio kan andere prestatieresultaten opleveren dan een cloudinstantie met dezelfde specificaties in een andere regio. Mijn pgbench-tests die zijn uitgevoerd op meerdere cloudinstanties (allemaal dezelfde specificaties met dezelfde cloudleverancier) in verschillende regio's, gaven me verschillende resultaten op sommige ervan. Dit is vooral belangrijk wanneer u migreert naar de cloud.
- Queryprestaties in de cloud vereisen mogelijk een andere afstemmingsaanpak. DBA's moeten *_cost-parameters gebruiken om ervoor te zorgen dat er gezonde plannen voor het uitvoeren van query's worden gegenereerd.
Hulpprogramma's om PostgreSQL-prestaties te controleren
There are various tools to monitor PostgreSQL performance. Let me highlight some of those.
- pg_top is a GREAT tool to monitor PostgreSQL database dynamically. I would highly recommend this tool for DBAs for various reasons. This tool has numerous advantages, let me list them out:
- pg_top tool uses textual interface and is similar to Unix “top” utility.
- Will clearly list out the processes and the hardware resources utilized. What excites me with this tool is that it will clearly tell you if a particular process is currently on DISK or CPU - in my view that’s excellent. DBAs can clearly pick the process running for longer time on the disk.
- You can check the EXPLAIN PLAN of the top SQLs dynamically or instantly
- You can also find out what Tables or Indexes are being scanned instantly
- Nagios is a popular monitoring tool for PostgreSQL which has both open-source and commercial versions. Open source version should suffice for monitoring. Custom Perl scripts can be built and plugged into Nagios module.
- Pgbadger is a popular tool which can be used to analyze PostgreSQL log files and generate performance reports. This report can be used to analyze the performance of checkpoints, disk sorting.
- Zabbix is another popular tool used for PostgreSQL monitoring.
ClusterControl is an up-and-coming management platform for PostgreSQL. Apart from monitoring, it also has functionality to deploy replication setups with load balancers, automatic failover, backup management, among others.