sql >> Database teknologi >  >> RDS >> PostgreSQL

Et Performance Cheat Sheet til PostgreSQL

Ydeevne er en af ​​de vigtigste og mest komplekse opgaver, når man administrerer en database. Det kan være påvirket af konfigurationen, hardwaren eller endda designet af systemet. Som standard er PostgreSQL konfigureret med kompatibilitet og stabilitet i tankerne, da ydeevnen afhænger meget af hardwaren og af vores system selv. Vi kan have et system med mange data, der bliver læst, men informationen ændres ikke ofte. Eller vi kan have et system, der skriver kontinuerligt. Af denne grund er det umuligt at definere en standardkonfiguration, der fungerer for alle typer arbejdsbelastninger.

I denne blog vil vi se, hvordan man går om at analysere den arbejdsbyrde, eller forespørgsler, der kører. Vi vil derefter gennemgå nogle grundlæggende konfigurationsparametre for at forbedre ydeevnen af ​​vores PostgreSQL-database. Som vi nævnte, vil vi kun se nogle af parametrene. Listen over PostgreSQL-parametre er omfattende, vi vil kun berøre nogle af de vigtigste. Man kan dog altid konsultere den officielle dokumentation for at dykke ned i de parametre og konfigurationer, der virker mest vigtige eller nyttige i vores miljø.

FOKLAR

Et af de første skridt, vi kan tage for at forstå, hvordan vi forbedrer vores databases ydeevne, er at analysere de forespørgsler, der foretages.

PostgreSQL udarbejder en forespørgselsplan for hver forespørgsel, den modtager. For at se denne plan bruger vi EXPLAIN.

Strukturen af ​​en forespørgselsplan er et træ af planknudepunkter. Noderne i det nederste niveau af træet er scanningsknuder. De returnerer rå rækker fra en tabel. Der er forskellige typer scanningsknuder til forskellige metoder til at få adgang til tabellen. EXPLAIN-outputtet har en linje for hver node i plantræet.

world=# EXPLAIN SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
                               QUERY PLAN                                
--------------------------------------------------------------------------
Nested Loop  (cost=0.00..734.81 rows=50662 width=144)
  ->  Seq Scan on city t1  (cost=0.00..93.19 rows=347 width=31)
        Filter: ((id > 100) AND (population > 700000))
  ->  Materialize  (cost=0.00..8.72 rows=146 width=113)
        ->  Seq Scan on country t2  (cost=0.00..7.99 rows=146 width=113)
              Filter: (population < 7000000)
(6 rows)

Denne kommando viser, hvordan tabellerne i vores forespørgsel vil blive scannet. Lad os se, hvad disse værdier svarer til, som vi kan observere i vores EXPLAIN.

  • Den første parameter viser den operation, som motoren udfører på dataene i dette trin.
  • Anslåede opstartsomkostninger. Dette er den tid, der bruges, før outputfasen kan begynde.
  • Estimerede samlede omkostninger. Dette er angivet under forudsætning af, at planknudepunktet køres til færdiggørelse. I praksis kan en nodes overordnede node stoppe med at læse alle tilgængelige rækker.
  • Estimeret antal rækker, der udskrives af denne planknude. Igen antages det, at noden er kørt til fuldførelse.
  • Estimeret gennemsnitlig bredde af rækker, der er outputtet af denne planknude.

Den mest kritiske del af visningen er den estimerede erklæringsudførelsesomkostning, som er planlæggerens gæt på, hvor lang tid det vil tage at køre erklæringen. Når vi sammenligner, hvor effektiv den ene forespørgsel er med den anden, vil vi i praksis sammenligne omkostningsværdierne for dem.

Det er vigtigt at forstå, at prisen på en node på øverste niveau inkluderer prisen for alle dens underordnede noder. Det er også vigtigt at indse, at omkostningerne kun afspejler ting, som planlæggeren bekymrer sig om. Især tager omkostningerne ikke hensyn til den tid, der bruges på at sende resultatrækker til klienten, hvilket kan være en vigtig faktor i den reelle forløbne tid; men planlæggeren ignorerer den, fordi den ikke kan ændre den ved at ændre planen.

Omkostningerne måles i vilkårlige enheder bestemt af planlæggerens omkostningsparametre. Traditionel praksis er at måle omkostningerne i enheder af disksidehentninger; det vil sige, seq_page_cost er konventionelt sat til 1.0, og de andre omkostningsparametre er sat i forhold til det.

FOKLAR ANALYSE

Med denne indstilling udfører EXPLAIN forespørgslen og viser derefter det sande rækkeantal og den sande køretid akkumuleret inden for hver planknude sammen med de samme estimater, som en almindelig EXPLAIN viser.

Lad os se et eksempel på brugen af ​​dette værktøj.

world=# EXPLAIN ANALYZE SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
                                                     QUERY PLAN                                                      
----------------------------------------------------------------------------------------------------------------------
Nested Loop  (cost=0.00..734.81 rows=50662 width=144) (actual time=0.081..22.066 rows=51100 loops=1)
  ->  Seq Scan on city t1  (cost=0.00..93.19 rows=347 width=31) (actual time=0.069..0.618 rows=350 loops=1)
        Filter: ((id > 100) AND (population > 700000))
        Rows Removed by Filter: 3729
  ->  Materialize  (cost=0.00..8.72 rows=146 width=113) (actual time=0.000..0.011 rows=146 loops=350)
        ->  Seq Scan on country t2  (cost=0.00..7.99 rows=146 width=113) (actual time=0.007..0.058 rows=146 loops=1)
              Filter: (population < 7000000)
              Rows Removed by Filter: 93
Planning time: 0.136 ms
Execution time: 24.627 ms
(10 rows)

Hvis vi ikke finder årsagen til, at vores forespørgsler tager længere tid, end de burde, kan vi tjekke denne blog for mere information.

VAKUUM

VACUUM-processen er ansvarlig for adskillige vedligeholdelsesopgaver i databasen, en af ​​dem genopretter lager optaget af døde tupler. I den normale drift af PostgreSQL fjernes tuples, der er slettet eller forældet af en opdatering, ikke fysisk fra deres tabel; de forbliver til stede, indtil der udføres en STØVSUGNING. Derfor er det nødvendigt at udføre VACUUM med jævne mellemrum, især i hyppigt opdaterede tabeller.

Hvis VAKUUMET tager for meget tid eller ressourcer, betyder det, at vi skal gøre det oftere, så hver operation har mindre at rense.

Under alle omstændigheder kan det være nødvendigt at deaktivere VACUUM, f.eks. når data indlæses i store mængder.

VACUUM'en genvinder simpelthen plads og gør den tilgængelig til genbrug. Denne form for kommandoen kan fungere parallelt med normal læsning og skrivning af tabellen, da der ikke opnås en eksklusiv lås. Den ekstra plads returneres dog ikke til operativsystemet (i de fleste tilfælde); den er kun tilgængelig til genbrug i samme tabel.

VACUUM FULL omskriver alt indholdet af tabellen i en ny diskfil uden yderligere plads, hvilket tillader den ubrugte plads at vende tilbage til operativsystemet. Denne formular er meget langsommere og kræver en eksklusiv lås på hvert bord under behandlingen.

VACUUM ANALYSE udfører en VACUUM og derefter en ANALYSE for hver valgt tabel. Dette er en praktisk måde at kombinere rutinevedligeholdelsesscripts på.

ANALYSE indsamler statistik over indholdet af tabellerne i databasen og gemmer resultaterne i pg_statistic. Efterfølgende bruger forespørgselsplanlæggeren disse statistikker til at hjælpe med at bestemme de mest effektive eksekveringsplaner for forespørgsler.

Download Whitepaper Today PostgreSQL Management &Automation med ClusterControlFå flere oplysninger om, hvad du skal vide for at implementere, overvåge, administrere og skalere PostgreSQLDownload Whitepaper

Konfigurationsparametre

For at ændre disse parametre skal vi redigere filen $ PGDATA / postgresql.conf. Vi skal huske på, at nogle af dem kræver en genstart af vores database.

max_connections

Bestemmer det maksimale antal samtidige forbindelser til vores database. Der er hukommelsesressourcer, der kan konfigureres pr. klient, derfor kan det maksimale antal klienter foreslå den maksimale mængde hukommelse, der bruges.

superuser_reserved_connections

I tilfælde af at nå grænsen for max_connection, er disse forbindelser reserveret til superbruger.

delte_buffere

Indstiller mængden af ​​hukommelse, som databaseserveren bruger til delt hukommelsesbuffere. Hvis du har en dedikeret databaseserver med 1 GB eller mere RAM, er en rimelig startværdi for shared_buffers 25 % af dit systems hukommelse. Større konfigurationer for shared_buffers kræver generelt en tilsvarende stigning i max_wal_size for at forlænge processen med at skrive store mængder nye eller ændrede data over en længere periode.

temp_buffere

Indstiller det maksimale antal midlertidige buffere, der bruges til hver session. Disse er lokale sessionsbuffere, der kun bruges til at få adgang til midlertidige tabeller. En session vil tildele de midlertidige buffere efter behov op til grænsen givet af temp_buffers.

work_mem

Angiver mængden af ​​hukommelse, der vil blive brugt af de interne operationer af ORDER BY, DISTINCT, JOIN og hash-tabeller, før der skrives til de midlertidige filer på disken. Når vi konfigurerer denne værdi, skal vi tage højde for, at flere sessioner udfører disse operationer på samme tid, og hver operation vil få lov til at bruge så meget hukommelse som angivet af denne værdi, før den begynder at skrive data i midlertidige filer.

Denne mulighed blev kaldt sort_mem i ældre versioner af PostgreSQL.

maintenance_work_mem

Angiver den maksimale mængde hukommelse, som vedligeholdelsesoperationer vil bruge, såsom VACUUM, CREATE INDEX og ALTER TABLE ADD FOREIGN KEY. Da kun én af disse operationer kan udføres på samme tid af en session, og en installation normalt ikke har mange af dem kørende samtidigt, kan den være større end work_mem. Større konfigurationer kan forbedre ydeevnen for VACUUM og databasegendannelser.

Når autovacuum udføres, kan denne hukommelse tildeles det antal gange, hvor autovacuum_max_workers-parameteren er konfigureret, så vi skal tage højde for dette, eller på anden måde konfigurere autovacuum_work_mem-parameteren til at administrere dette separat.

fsync

Hvis fsync er aktiveret, vil PostgreSQL forsøge at sikre, at opdateringerne er fysisk skrevet til disken. Dette sikrer, at databaseklyngen kan gendannes til en konsistent tilstand efter et operativsystem- eller hardwarenedbrud.

Selvom deaktivering af fsync generelt forbedrer ydeevnen, kan det forårsage datatab i tilfælde af strømsvigt eller systemnedbrud. Derfor er det kun tilrådeligt at deaktivere fsync, hvis du nemt kan genskabe hele din database fra eksterne data.

checkpoint_segments (PostgreSQL <9.5)

Maksimalt antal optagefilsegmenter mellem automatiske WAL-kontrolpunkter (hvert segment er normalt 16 megabyte). Forøgelse af denne parameter kan øge den tid, der kræves for at retablere fejl. I et system med meget trafik kan det påvirke ydeevnen, hvis det er sat til en meget lav værdi. Det anbefales at øge værdien af ​​checkpoint_segments på systemer med mange dataændringer.

Det er også en god praksis at gemme WAL-filerne på en anden disk end PGDATA. Dette er nyttigt både til at balancere skrivningen og for sikkerheden i tilfælde af hardwarefejl.

Fra PostgreSQL 9.5 blev konfigurationsvariablen "checkpoint_segments" fjernet og blev erstattet af "max_wal_size" og "min_wal_size"

max_wal_size (PostgreSQL>=9.5)

Maksimal størrelse WAL'en må vokse mellem kontrolpunkterne. Størrelsen af ​​WAL kan overstige max_wal_size under særlige omstændigheder. Forøgelse af denne parameter kan øge den tid, der er nødvendig for at retablere fejl.

min_wal_size (PostgreSQL>=9.5)

Når WAL-filen holdes under denne værdi, genbruges den til fremtidig brug ved et kontrolpunkt i stedet for at blive slettet. Dette kan bruges til at sikre, at der er reserveret nok WAL-plads til at håndtere spidser i brugen af ​​WAL, for eksempel ved udførelse af store batchjobs.

wal_sync_method

Metode, der bruges til at tvinge WAL-opdateringer til disken. Hvis fsync er deaktiveret, har denne indstilling ingen effekt.

wal_buffere

Mængden af ​​delt hukommelse, der bruges til WAL-data, som endnu ikke er blevet skrevet til disken. Standardindstillingen er omkring 3 % af shared_buffers, ikke mindre end 64KB eller mere end størrelsen af ​​et WAL-segment (normalt 16MB). Indstilling af denne værdi til mindst et par MB kan forbedre skriveydelsen på en server med mange samtidige transaktioner.

effective_cache_size

Denne værdi bruges af forespørgselsplanlæggeren til at tage hensyn til planer, der måske eller måske ikke passer i hukommelsen. Dette er taget i betragtning i omkostningsestimaterne ved brug af et indeks; en høj værdi gør det mere sandsynligt, at der bruges indeksscanninger, og en lav værdi gør det mere sandsynligt, at sekventielle scanninger vil blive brugt. En rimelig værdi ville være 50 % af RAM.

default_statistics_target

PostgreSQL indsamler statistik fra hver af tabellerne i sin database for at bestemme, hvordan forespørgsler vil blive udført på dem. Som standard indsamler den ikke for meget information, og hvis du ikke får gode eksekveringsplaner, bør du øge denne værdi og derefter køre ANALYSE i databasen igen (eller vente på AUTOVACUUM).

synchronous_commit

Angiver, om transaktionsbekræftelsen vil vente på, at WAL-posterne bliver skrevet til disken, før kommandoen returnerer en "succes"-indikation til klienten. De mulige værdier er:"on", "remote_apply", "remote_write", "local" og "off". Standardindstillingen er "on". Når den er deaktiveret, kan der være en forsinkelse mellem det tidspunkt, hvor klienten vender tilbage, og når transaktionen er garanteret sikker mod en serverlås. I modsætning til fsync skaber deaktivering af denne parameter ingen risiko for databaseinkonsekvens:et nedbrud af operativsystemet eller databasen kan resultere i tab af nogle nylige transaktioner, der angiveligt er begået, men databasens tilstand vil være nøjagtig den samme, som hvis disse transaktioner var blevet aflyst rent. Derfor kan deaktivering af synchronous_commit være et nyttigt alternativ, når ydeevne er vigtigere end den nøjagtige sikkerhed for en transaktions holdbarhed.

Logføring

Der er flere typer data at logge, som kan være nyttige eller ej. Lad os se nogle af dem:

  • log_min_error_statement:Indstiller minimumslogningsniveauet.
  • log_min_duration_statement:Bruges til at registrere langsomme forespørgsler i systemet.
  • log_line_prefix:Overholder oplysninger i begyndelsen af ​​hver loglinje.
  • log_statement:Du kan vælge mellem NONE, DDL, MOD, ALL. Brug af "alle" kan forårsage ydeevneproblemer.

Design

I mange tilfælde kan designet af vores database påvirke ydeevnen. Vi skal være forsigtige i vores design, normalisere vores skema og undgå overflødige data. I mange tilfælde er det praktisk at have flere små borde i stedet for et stort bord. Men som vi sagde før, afhænger alt af vores system, og der er ikke en eneste mulig løsning.

Vi skal også bruge indekserne ansvarligt. Vi bør ikke oprette indekser for hvert felt eller kombination af felter, da vi, selvom vi ikke behøver at rejse hele tabellen, bruger diskplads og tilføjer overhead til skriveoperationer.

Et andet meget nyttigt værktøj er styringen af ​​forbindelsespuljen. Hvis vi har et system med meget belastning, kan vi bruge dette til at undgå at mætte forbindelserne i databasen og for at kunne genbruge dem.

Hardware

Som vi nævnte i begyndelsen af ​​denne blog, er hardware en af ​​de vigtige faktorer, der direkte påvirker ydeevnen af ​​vores database. Lad os se nogle punkter, du skal huske på.

  • Hukommelse:Jo mere RAM vi har, jo flere hukommelsesdata kan vi håndtere, og det betyder bedre ydeevne. Hastigheden af ​​at skrive og læse på disken er meget langsommere end i hukommelsen, derfor, jo mere information vi kan have i hukommelsen, jo bedre ydeevne vil vi have.
  • CPU:Måske giver det ikke meget mening at sige dette, men jo mere CPU vi har, jo bedre. Under alle omstændigheder er det ikke det vigtigste med hensyn til hardware, men hvis vi kan have en god CPU, vil vores behandlingskapacitet forbedres, og det påvirker vores database direkte.
  • Harddisk:Vi har flere typer diske, som vi kan bruge, SCSI, SATA, SAS, IDE. Vi har også solid state-diske. Vi skal sammenligne kvalitet / pris, som vi skal bruge til at sammenligne dens hastighed. Men typen af ​​disk er ikke den eneste ting at overveje, vi skal også se, hvordan man konfigurerer dem. Hvis vi vil have god ydeevne, kan vi bruge RAID10, og holde WAL'erne på en anden disk uden for RAID'en. Det anbefales ikke at bruge RAID5, da ydeevnen af ​​denne type RAID til databaser ikke er god.

Konklusion

Efter at have taget højde for de punkter, der er nævnt i denne blog, kan vi udføre et benchmark for at verificere databasens adfærd.

Det er også vigtigt at have vores database overvåget for at afgøre, om vi står over for et præstationsproblem, og for at kunne løse det så hurtigt som muligt. Til denne opgave er der flere værktøjer såsom Nagios, ClusterControl eller Zabbix, blandt andre, der giver os mulighed for ikke kun at overvåge, men med nogle af dem, giver os mulighed for at tage proaktiv handling, før problemet opstår. Med ClusterControl kan vi udover overvågning, administration og flere andre hjælpeprogrammer modtage anbefalinger om, hvilke handlinger vi kan tage, når vi modtager præstationsalarmer. Dette giver os mulighed for at få en idé om, hvordan man løser potentielle problemer.

Denne blog er ikke beregnet til at være en udtømmende guide til, hvordan man forbedrer databasens ydeevne. Forhåbentlig giver det et klarere billede af, hvilke ting der kan blive vigtige og nogle af de grundlæggende parametre, der kan konfigureres. Tøv ikke med at give os besked, hvis vi er gået glip af vigtige.


  1. Hvordan kan jeg se, hvilket tegnsæt en MySQL-database/tabel/kolonne er?

  2. En oversigt over cachelagring til PostgreSQL

  3. Sådan forhindrer du databasekorruption i Microsoft Access

  4. MySQL Alter Stored Procedure