sql >> Databasteknik >  >> RDS >> PostgreSQL

Förstå PostgreSQL-frågeprestanda

Att ta reda på varför en fråga som presterar bra i utveckling och testning blåser upp i produktionen kan ibland vara en utmaning. Läs vidare för att lära dig mer om några funktioner som kan ge insikter om hur dina frågor går i produktion.

Frågor som körs för närvarande

När en klient ansluter en PostgreSQL-server, är den huvudsakliga Postgres-serverprocessen (historiskt kallad postmaster ) skapar en ny process (kallad backend ) för att betjäna kundens frågor. Varje backend väntar därför antingen på att sin klient ska skicka in en fråga eller försöker köra en.

Systemvyn pg_stat_activity visar information om varje backend som körs för närvarande. I synnerhet visar den frågan som backendisen kör för närvarande om den är aktiv, eller den senaste frågan den körde om den väntar på att klienten ska skicka in en annan fråga.

Här är två backends som betjänar klienter anslutna till databasen testdb , med båda aktivt köra sina frågor:

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';

Ibland kan frågan väntar på ett lås, och även detta visar inpg_stat_activity. Du kan se en INSERT som väntar på ett relationslås här:

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);

För mer information om pg_stat_activity, se dokumenten.

Även om den här vyn är användbar för att förstå vad Postgres gör för närvarande, tillhandahåller den ingen information om exekveringsstatistik för frågor eller information om sökningar som har avslutats.

Alla frågor körs i det förflutna

För det, tillägget pg_stat_statements är ovärderlig. Denna tillägg ingår i kärndistributionen för PostgreSQL och är även tillgänglig på hanterade tjänster som AWS RDS och GCP SQL.

pg_stat_statements (PSS) är en "tillägg" i PostgreSQL-termer, och måste installeras först:

  • Konsultera din Linux-distrodokumentation för att se om tillägget är förinstallerat eller om det kräver installation av ett annat paket. Till exempel, på Centos 7 måste du sudo yum install postgresql-contrib .
  • Redigera huvudkonfigurationsfilen postgresql.conf (vanligtvis under /etc , som/etc/postgresql/10/main/postgresql.conf på Debian) och ändra värdet på shared_preload_libraries till "pg_stat_statements". Detta är en kommaseparerad lista med värden, så om det redan finns något där, lägg till ett kommatecken och sedan "pg_stat_statements".
  • För AWS RDS måste du ändra din aktiva parametergrupp och ställa in värdet.
  • När du har redigerat "shared_preload_libraries" måste du starta om PostgreSQL-demonen. Tyvärr finns det ingen väg runt detta. På AWS RDS måste du starta om RDS-instansen.
  • Efter en omstart skulle PostgreSQL-servern ha laddat det delade biblioteket, och vi kan installera tillägget genom att köra CREATE EXTENSION pg_stat_statements . Du måste vara en superanvändare för att köra det här kommandot.
  • Du kan faktiskt installera tillägget i vilken databas som helst, och ändå se frågorna i alla databaser.

När tillägget är installerat kan du fråga vyn som heterpg_stat_statements för att få information om varje enskild fråga som körs sedan tillägget installerades.

Siffrorna, liksom tiden det tar att utföra frågan, ackumuleras som en summa. Enbart för frågekörningstiden presenteras viss statistik (genomsnitt, min, max, standardavvikelse). Dessa värden kan raderas med funktionenpg_stat_statements_reset .

Här är hur en rad från pg_stat_statements ser ut 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

Förutom de identifierande parametrarna (användare, databas, fråga), kan du lista ut många intressanta saker om din fråga:

  • Hur lång tid det tar att köra normalt (mean_time )
  • Hur många rader den returnerar i genomsnitt (rows / calls )
  • Mängden data som läses från den delade buffertcachen och mängden data som läses från disken (den shared_blks_read visar den totala mängden data som frågan läste, varav shared_blks_hit kom från cachen)
  • Mängden data som måste skrivas till disken synkront på grund av cachetryck (shared_blks_written )
  • Mängden skrivna data, som antalet block som berörts (shared_blks_dirtied )
  • Mängden tid som spenderas på disk läser och skriver (blk_{read,write}_time )
  • Tillfälliga filer skrivna till och lästa från (temp_blks_{read,written} )
  • Tillfälliga tabeller skrivna till och lästa från (local_* )

Diskens läs- och skrivtider är endast tillgängliga om konfigurationsparameterntrack_io_timing är påslagen. Som standard är det inte det. På de flesta moderna Linuxsystem borde det vara ok att aktivera denna parameter. Läs mer.

Det är värt besväret att ta en ögonblicksbild av pg_stat_statements data kontinuerligt med regelbundna intervall för att se hur dessa parametrar trendar per fråga. Verktyget med öppen källkod pgmetrics kan extrahera och exponera pg_stat_statements data som JSON för enklare automatisering.

Frågor körs under ett tidsintervall

När du väl har ett sådant system på plats blir det lätt att spåra de frågor som utförs inom en given tidsram. Detta gör det enkelt att felsöka problem som varför ett batchjobb tog längre tid än förväntat.

Genom att subtrahera räknarna mellan två givna tidsstämplar kan du hitta det yttersta av siffrorna som tidigare, förutom min, max och standardavvikelse. Detta är tillräckligt för att identifiera de frågor som kördes inom tidsintervallet och de resurser de förbrukade.

Logga långsamma frågor

Ett annat sätt att snabbt identifiera frågor som tar längre tid än förväntat är att aktivera loggning av uttalanden. Du kan ange en tröskelvaraktighet, och om frågan tar längre tid än detta att slutföras loggas den. (I den vanliga PostgreSQL-loggfilen finns det ingen separat för långsamma frågor.)

För att aktivera den här funktionen, redigera konfigurationen enligt nedan:

log_min_duration_statement = 1000 # in milliseconds

och ladda om Postgres. Du kan också använda ALTER SYSTEM :

ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds

Med detta loggas alla uttalanden (inklusive icke-DML) som tar mer än en sekund att avsluta:

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

Den faktiska tiden det tar för frågan, såväl som hela SQL-texten, loggas.

Om du har ett loggövervakningssystem och kan spåra antalet långsamma frågor per timme/per dag, kan det fungera som en bra indikator på applikationsprestanda.

Frågeexekveringsplaner

När du väl har hittat en fråga som du tycker borde köras snabbare, är nästa steg att ta en titt på dess frågeplan. Vanligtvis behöver du den faktiska frågeplanen från produktionsservrar att arbeta med. Om du kan köra EXPLAIN på produktionsservrar så bra, annars måste du lita på auto_explain .

auto_explain är ett annat centralt PostgreSQL-tillägg, antingen redan installerat eller tillgängligt som ett "bidrag"-paket för din distro. Den finns även tillgänglig på AWSRDS. auto_explain är lite enklare att installera än pg_stat_statements :

  • Redigera postgres-konfigurationen (eller RDS-parametergruppen)shared_preload_libraries för att inkludera auto_explain .
  • Du behöver dock inte starta om Postgres, du kan istället bara köra:LOAD 'auto_explain'; .
  • Du vill konfigurera dess inställningar, åtminstone den här:
    • auto_explain.log_min_duration = 1000 # seconds

Närhelst en fråga tar längre tid änauto_explain.log_min_duration antal sekunder att slutföra, auto_explain loggar frågan och dess exekveringsplan i loggfilen, så här:

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 logga planen i JSON-format också, om du har skript som kan bearbeta 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 finns det inget annat sätt än auto_explain att titta på exekveringsplanen för en fråga som redan har körts, vilket gör auto_explain till ett viktigt verktyg i din verktygslåda.


  1. Hur man använder Virtual Index i Oracle Database

  2. 5 misstag i databasdesign att undvika

  3. MySql summaelement i en kolumn

  4. PL/SQL-program för att ta bort posterna från tabellen