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

Forståelse af PostgreSQL-forespørgselsydeevne

Det kan nogle gange være en udfordring at finde ud af, hvorfor en forespørgsel, der klarer sig godt i udvikling og test, blæser op i produktionen. Læs videre for at lære mere om nogle få funktioner, der kan give indsigt i, hvordan dine forespørgsler klarer sig i produktionen.

Aktuelt kørende forespørgsler

Når en klient forbinder en PostgreSQL-server, er den primære Postgres-serverproces (historisk kaldet postmaster ) afføder en ny proces (kaldetbackend ) for at servicere kundens forespørgsler. Hver backend venter derfor enten på, at dens klient sender en forespørgsel eller forsøger at udføre en.

Systemvisningen pg_stat_activity viser information om hver backend, der kører i øjeblikket. Det viser især den forespørgsel, som backenden udfører i øjeblikket, hvis den er aktiv, eller den sidste forespørgsel, den udførte, hvis den venter på, at klienten sender en anden forespørgsel.

Her er to backends, der betjener klienter forbundet til databasen testdb , hvor de begge aktivt udfører deres forespørgsler:

testdb=# select usename,datname,state,query from pg_stat_activity where datname='testdb';
-[ RECORD 1 ]-----------------------------------------------------------------------------
usename | postgres
datname | testdb
state   | active
query   | SELECT pg_sleep(10);
-[ RECORD 2 ]-----------------------------------------------------------------------------
usename | postgres
datname | testdb
state   | active
query   | select usename,datname,state,query from pg_stat_activity where datname='testdb';

Nogle gange kan forespørgslen vente på en lås, og dette viser også inpg_stat_activity. Du kan se en INSERT, der venter på en relationslås her:

testdb=# select wait_event_type, wait_event, left(query, 60) from pg_stat_activity where datname='testdb';
-[ RECORD 1 ]---+-------------------------------------------------------------
wait_event_type | Client
wait_event      | ClientRead
left            | lock table t in access exclusive mode;
-[ RECORD 2 ]---+-------------------------------------------------------------
wait_event_type |
wait_event      |
left            | select wait_event_type, wait_event, left(query, 60) from pg_
-[ RECORD 3 ]---+-------------------------------------------------------------
wait_event_type | Lock
wait_event      | relation
left            | insert into t values (1);

For mere information om pg_stat_activity, se docs.

Selvom denne visning er nyttig til at forstå, hvad Postgres laver i øjeblikket, giver den ikke oplysninger om statistikker om udførelse af forespørgsler eller oplysninger om forespørgsler, der er afsluttet.

Alle forespørgsler er kørt i fortiden

Til det, udvidelsen pg_stat_statements er uvurderlig. Denne udvidelse er inkluderet i kernepostgreSQL-distributionen og er også tilgængelig på administrerede tjenester som AWS RDS og GCP SQL.

pg_stat_statements (PSS) er en "udvidelse" i PostgreSQL-termer og skal først installeres:

  • Konsulter din Linux-distro-dokumentation for at se, om udvidelsen er forudinstalleret, eller om den kræver installation af en anden pakke. For eksempel skal du på Centos 7 sudo yum install postgresql-contrib .
  • Rediger hovedkonfigurationsfilen postgresql.conf (typisk under /etc , som/etc/postgresql/10/main/postgresql.conf på Debian) og ændre værdien afshared_preload_libraries til "pg_stat_statements". Dette er en kommasepareret liste over værdier, så hvis der allerede er noget der, skal du tilføje et komma og derefter "pg_stat_statements".
  • For AWS RDS skal du ændre din aktive parametergruppe og indstille værdien.
  • Når du har redigeret "shared_preload_libraries", skal du genstarte PostgreSQL-dæmonen. Desværre er der ingen vej udenom. På AWS RDS skal du genstarte RDS-forekomsten.
  • Efter en genstart ville PostgreSQL-serveren have indlæst det delte bibliotek, og vi kan installere udvidelsen ved at køre CREATE EXTENSION pg_stat_statements . Du skal være superbruger for at køre denne kommando.
  • Du kan faktisk installere udvidelsen i enhver database, og alligevel se forespørgslerne på tværs af alle databaser.

Når udvidelsen er installeret, kan du forespørge i visningen kaldetpg_stat_statements for at få information om hver enkelt forespørgsel, der er udført siden udvidelsen blev installeret.

Tallene, ligesom tiden det tager at udføre forespørgslen, akkumuleres som en sum. Alene for forespørgselsudførelsestiden præsenteres nogle statistikker (gennemsnit, min, maks., standardafvigelse). Disse værdier kan ryddes ved hjælp af funktionenpg_stat_statements_reset .

Her er hvordan en række fra pg_stat_statements ser ud som:

testdb=# select * from pg_stat_statements where query like '%pg_sleep%' and dbid=42548;
-[ RECORD 1 ]-------+--------------------
userid              | 10
dbid                | 42548
queryid             | 2649515222348904837
query               | SELECT pg_sleep($1)
calls               | 1
total_time          | 10016.782625
min_time            | 10016.782625
max_time            | 10016.782625
mean_time           | 10016.782625
stddev_time         | 0
rows                | 1
shared_blks_hit     | 0
shared_blks_read    | 0
shared_blks_dirtied | 0
shared_blks_written | 0
local_blks_hit      | 0
local_blks_read     | 0
local_blks_dirtied  | 0
local_blks_written  | 0
temp_blks_read      | 0
temp_blks_written   | 0
blk_read_time       | 0
blk_write_time      | 0

Bortset fra de identificerende parametre (bruger, database, forespørgsel), kan du finde ud af mange interessante ting om din forespørgsel:

  • Hvor lang tid tager det typisk at udføre (mean_time )
  • Hvor mange rækker den returnerer i gennemsnit (rows / calls )
  • Mængden af ​​data læst fra den delte buffercache og mængden af ​​data læst fra disken (shared_blks_read viser den samlede mængde data, som forespørgslen læste, hvoraf shared_blks_hit kom fra cachen)
  • Mængden af ​​data, der skulle skrives til disken synkront på grund af cachetryk (shared_blks_written )
  • Mængden af ​​skrevet data, som antallet af berørte blokke(shared_blks_dirtied )
  • Mængden af ​​tid brugt på diskens læsning og skrivning (blk_{read,write}_time )
  • Midlertidige filer skrevet til og læst fra (temp_blks_{read,written} )
  • Midlertidige tabeller skrevet til og læst fra (local_* )

Diskens læse- og skrivetider er kun tilgængelige, hvis konfigurationsparameterentrack_io_timing er tændt. Som standard er det ikke. På de fleste moderne Linux-systemer burde det være ok at slå denne parameter til. Læs mere.

Det er umagen værd at tage et øjebliksbillede af pg_stat_statements data løbende med jævne intervaller for at se, hvordan disse parametre trender pr. forespørgsel. Open source-værktøjet pgmetrics kan udtrække og afsløre pg_stat_statements data som JSON for lettere automatisering.

Forespørgsler køres i et tidsinterval

Når først du har et sådant system på plads, bliver det nemt at spore de forespørgsler, der udføres i en given tidsramme. Dette gør det nemt at fejlfinde problemer som hvorfor et batchjob tog længere tid end forventet.

Ved at trække tællerne fra mellem to givne tidsstempler, kan du finde det yderste af tallene som før, bortset fra min, max og standardafvigelse. Dette er tilstrækkeligt til at identificere de forespørgsler, der blev udført inden for tidsintervallet, og de ressourcer, de brugte.

Logning af langsomme forespørgsler

En anden måde at hurtigt identificere forespørgsler, der tager længere tid end forventet, er at aktivere logning af udsagn. Du kan angive en tærskelvarighed, og hvis forespørgslen tager længere tid end dette, bliver den logget. (I den almindelige PostgreSQL-logfil er der ingen separat til langsomme forespørgsler.)

For at aktivere denne funktion skal du redigere konfigurationen som nedenfor:

log_min_duration_statement = 1000 # in milliseconds

og genindlæs Postgres. Du kan også bruge ALTER SYSTEM :

ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds

Med dette logges enhver erklæring (inklusive ikke-DML), der tager mere end et sekund at afslutte:

2019-12-02 16:57:05.727 UTC [8040] postgres@testdb LOG:  duration: 10017.862 ms  statement: SELECT pg_sleep(10);

Den faktiske tid, det tager forespørgslen, såvel som den fulde SQL-tekst, logges.

Hvis du har et logovervågningssystem og kan spore antallet af langsomme forespørgsler pr. time/per dag, kan det tjene som en god indikator for applikationens ydeevne.

Forespørgselsudførelsesplaner

Når du har fundet en forespørgsel, som du føler burde køre hurtigere, er næste trin at se på dens forespørgselsplan. Typisk har du brug for den faktiske forespørgselsplan fra produktionsservere at arbejde med. Hvis du er i stand til at køre EXPLAIN på produktionsservere så fantastisk, ellers skal du stole påauto_explain .

auto_explain er en anden kerne PostgreSQL-udvidelse, enten allerede installeret eller tilgængelig som en "bidrag"-pakke til din distro. Den er også tilgængelig på AWSRDS. auto_explain er en smule enklere at installere end pg_stat_statements :

  • Rediger postgres-konfigurationen (eller RDS-parametergruppen)shared_preload_libraries for at inkludere auto_explain .
  • Du behøver dog ikke at genstarte Postgres, du kan i stedet bare køre:LOAD 'auto_explain'; .
  • Du skal konfigurere dens indstillinger, i det mindste denne:
    • auto_explain.log_min_duration = 1000 # seconds

I bund og grund, når en forespørgsel tager længere tid endauto_explain.log_min_duration antal sekunder at fuldføre, auto_explain logger forespørgslen og dens forespørgselsudførelsesplan i logfilen, sådan her:

2019-12-04 09:23:05.130 UTC [12823] postgres@testdb LOG:  duration: 11025.765 ms  plan:
        Query Text: select pg_sleep(11);
        Result  (cost=0.00..0.01 rows=1 width=4) (actual time=11025.716..11025.718 rows=1 loops=1)
          Output: pg_sleep('11'::double precision)

Den kan også logge planen i JSON-format, hvis du har scripts, der kan behandle den:

2019-12-02 17:30:53.676 UTC [8040] postgres@testdb LOG:  duration: 10000.230 ms  plan:
        {
          "Query Text": "SELECT pg_sleep(10);",
          "Plan": {
            "Node Type": "Result",
            "Parallel Aware": false,
            "Startup Cost": 0.00,
            "Total Cost": 0.01,
            "Plan Rows": 1,
            "Plan Width": 4,
            "Actual Startup Time": 10000.205,
            "Actual Total Time": 10000.206,
            "Actual Rows": 1,
            "Actual Loops": 1,
            "Output": ["pg_sleep('10'::double precision)"],
            "Shared Hit Blocks": 0,
            "Shared Read Blocks": 0,
            "Shared Dirtied Blocks": 0,
            "Shared Written Blocks": 0,
            "Local Hit Blocks": 0,
            "Local Read Blocks": 0,
            "Local Dirtied Blocks": 0,
            "Local Written Blocks": 0,
            "Temp Read Blocks": 0,
            "Temp Written Blocks": 0,
            "I/O Read Time": 0.000,
            "I/O Write Time": 0.000
          },
          "Triggers": [
          ]
        }

I Postgres er der ingen anden måde end auto_explain at se på eksekveringsplanen for en forespørgsel, der allerede er udført, hvilket gør auto_explain til et vigtigt værktøj i din værktøjskasse.


  1. Understøtter Microsoft OLE DB Provider til SQL Server TLS 1.2

  2. Filtrere efter COUNT(*)?

  3. Sådan rejser du en fejl i en MySQL-funktion

  4. Hvorfor rækkerne returnerer ved explain er ikke lig med count()?