PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Zrozumienie wydajności zapytań PostgreSQL

Ustalenie, dlaczego zapytanie, które dobrze sprawdza się podczas programowania i testowania, przerasta w środowisku produkcyjnym, może czasem stanowić wyzwanie. Czytaj dalej, aby dowiedzieć się więcej o kilku funkcjach, które mogą zapewnić wgląd w to, jak Twoje zapytania radzą sobie w środowisku produkcyjnym.

Aktualnie uruchomione zapytania

Kiedy klient łączy się z serwerem PostgreSQL, główny proces serwera Postgres (historycznie nazywany postmasterem ) tworzy nowy proces (nazywanybackendem ) w celu obsługi zapytań Klienta. Dlatego każdy backend albo czeka na wysłanie zapytania przez klienta, albo próbuje je wykonać.

Widok systemowy pg_stat_activity pokazuje informacje o każdym aktualnie uruchomionym backendzie. W szczególności pokazuje zapytanie, które backendis aktualnie wykonuje, jeśli jest aktywne, lub ostatnie zapytanie, które wykonało, jeśli czeka na wysłanie przez klienta innego zapytania.

Oto dwa backendy obsługujące klientów podłączonych do bazy danych testdb , przy czym obaj aktywnie wykonują swoje zapytania:

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

Czasami zapytanie może czekać na blokadę i to również pokazuje inpg_stat_activity. Tutaj możesz zobaczyć WSTAWKĘ czekającą na blokadę relacji:

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

Więcej informacji na temat pg_stat_activity można znaleźć w dokumentacji.

Chociaż ten widok jest pomocny w zrozumieniu, co obecnie robi Postgres, nie dostarcza informacji o statystykach wykonywania zapytań ani informacji o zapytaniach, które zakończyły wykonywanie.

Wszystkie zapytania uruchomione w przeszłości

W tym celu rozszerzenie pg_stat_statements jest bezcenne. To rozszerzenie jest zawarte w podstawowej dystrybucji PostgreSQL, a także dostępne w usługach zarządzanych, takich jak AWS RDS i GCP SQL.

pg_stat_statements (PSS) to „rozszerzenie” w terminologii PostgreSQL i należy je najpierw zainstalować:

  • Zapoznaj się z dokumentacją dystrybucji Linuksa, aby sprawdzić, czy rozszerzenie jest wstępnie zainstalowane, czy też wymaga instalacji innego pakietu. Na przykład na Centos 7 będziesz musiał sudo yum install postgresql-contrib .
  • Edytuj główny plik konfiguracyjny postgresql.conf (zwykle w /etc , np./etc/postgresql/10/main/postgresql.conf w Debianie) i zmień wartość shared_preload_libraries do „pg_stat_statements”. Jest to lista wartości oddzielonych przecinkami, więc jeśli już coś tam jest, dołącz przecinek, a następnie „pg_stat_statements”.
  • W przypadku AWS RDS musisz zmodyfikować aktywną grupę parametrów i ustawić wartość.
  • Po edycji „shared_preload_libraries” musisz ponownie uruchomić demona PostgreSQL. Niestety nie da się tego obejść. W AWS RDS musisz ponownie uruchomić instancję RDS.
  • Po ponownym uruchomieniu serwer PostgreSQL załadowałby bibliotekę współdzieloną i możemy zainstalować rozszerzenie, uruchamiając CREATE EXTENSION pg_stat_statements . Aby uruchomić to polecenie, musisz być superużytkownikiem.
  • W rzeczywistości możesz zainstalować rozszerzenie w dowolnej bazie danych, a mimo to widzieć zapytania we wszystkich bazach danych.

Po zainstalowaniu rozszerzenia możesz wysłać zapytanie do widoku o nazwie pg_stat_statements aby uzyskać informacje o każdym zapytaniu wykonanym od momentu zainstalowania rozszerzenia.

Liczby, takie jak czas potrzebny na wykonanie zapytania, są sumowane. Dla samego czasu wykonania zapytania prezentowane są pewne statystyki (średnia, min, max, odchylenie standardowe). Te wartości można wyczyścić za pomocą funkcjipg_stat_statements_reset .

Oto jak wiersz z pg_stat_statements wygląda tak:

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

Oprócz parametrów identyfikujących (użytkownik, baza danych, zapytanie) możesz dowiedzieć się wielu interesujących rzeczy na temat swojego zapytania:

  • Jak długo trwa zwykle wykonanie (mean_time )
  • Ile wierszy zwraca średnio (rows / calls )
  • Ilość danych odczytanych ze współdzielonej pamięci podręcznej bufora oraz ilość danych odczytanych z dysku (shared_blks_read pokazuje całkowitą ilość danych odczytanych przez zapytanie, z czego shared_blks_hit pochodzi z pamięci podręcznej)
  • Ilość danych, które musiały zostać zapisane na dysku synchronicznie z powodu obciążenia pamięci podręcznej (shared_blks_written )
  • Ilość zapisanych danych jako liczba dotkniętych bloków (shared_blks_dirtied )
  • Ilość czasu spędzonego na odczytach i zapisach na dysku (blk_{read,write}_time )
  • Pliki tymczasowe zapisywane i odczytywane z (temp_blks_{read,written} )
  • Tymczasowe tabele zapisywane i odczytywane z (local_* )

Czasy odczytu i zapisu na dysku są dostępne tylko wtedy, gdy parametr konfiguracyjny track_io_timing jest włączony. Domyślnie tak nie jest. W większości nowoczesnych systemów Linux włączenie tego parametru powinno być w porządku. Czytaj więcej.

Warto zrobić zrzut pg_stat_statements dane stale w regularnych odstępach czasu, aby zobaczyć, jak te parametry zmieniają się w zależności od zapytania. Narzędzie pgmetrics o otwartym kodzie źródłowym może wyodrębniać i ujawniać pg_stat_statements dane w formacie JSON dla łatwiejszej automatyzacji.

Zapytania uruchamiane w określonym przedziale czasu

Gdy już masz taki system, śledzenie zapytań wykonywanych w określonym czasie staje się łatwe. Ułatwia to debugowanie problemów, takich jak dlaczego conocne zadanie wsadowe trwało dłużej niż oczekiwano.

Odejmując liczniki między dwoma podanymi znacznikami czasu, możesz znaleźć większość liczb, tak jak poprzednio, z wyjątkiem min, maks i odchylenia standardowego. Jest to wystarczające do zidentyfikowania zapytań, które zostały wykonane w podanym zakresie czasowym i zużytych przez nie zasobów.

Rejestrowanie powolnych zapytań

Innym sposobem szybkiego identyfikowania zapytań, które zajmują więcej czasu niż oczekiwano, jest włączenie rejestrowania instrukcji. Możesz określić czas trwania progu, a jeśli zakończenie zapytania trwa dłużej, zostanie ono zarejestrowane. (W zwykłym pliku dziennika PostgreSQL nie ma oddzielnego dla wolnych zapytań.)

Aby włączyć tę funkcję, edytuj konfigurację jak poniżej:

log_min_duration_statement = 1000 # in milliseconds

i przeładuj Postgres. Możesz także użyć ALTER SYSTEM :

ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds

Dzięki temu każda instrukcja (w tym te nieobsługujące DML), której zakończenie trwa dłużej niż sekundę, jest rejestrowana:

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

Rejestrowany jest rzeczywisty czas potrzebny na zapytanie, a także cały tekst SQL.

Jeśli masz system monitorowania dzienników i możesz śledzić liczbę powolnych zapytań na godzinę / dzień, może to służyć jako dobry wskaźnik wydajności aplikacji.

Plany wykonania zapytań

Gdy już znajdziesz zapytanie, które Twoim zdaniem powinno działać szybciej, następnym krokiem jest przyjrzenie się jego planowi zapytań. Zazwyczaj do pracy potrzebny jest rzeczywisty plan zapytań z serwerów produkcyjnych. Jeśli jesteś w stanie uruchomić EXPLAIN na tak świetnych serwerach produkcyjnych, w przeciwnym razie musisz polegać na auto_explain .

auto_explain jest kolejnym podstawowym rozszerzeniem PostgreSQL, już zainstalowanym lub dostępnym jako pakiet „contrib” dla twojej dystrybucji. Jest również dostępny na AWSRDS. auto_explain jest nieco prostszy w instalacji niż pg_stat_statements :

  • Edytuj konfigurację postgresa (lub grupę parametrów RDS)shared_preload_libraries aby dołączyć auto_explain .
  • Nie musisz jednak ponownie uruchamiać Postgresa, możesz zamiast tego uruchomić:LOAD 'auto_explain'; .
  • Będziesz chciał skonfigurować jego ustawienia, przynajmniej to:
    • auto_explain.log_min_duration = 1000 # seconds

Zasadniczo, gdy zapytanie trwa dłużej niż auto_explain.log_min_duration liczba sekund do zakończenia, auto_explain zapisuje zapytanie i jego plan wykonania w pliku dziennika, tak jak poniżej:

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)

Może również rejestrować plan w formacie JSON, jeśli masz skrypty, które mogą go przetworzyć:

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": [
          ]
        }

W Postgresie nie ma innego sposobu niż auto_explain, aby spojrzeć na plan wykonania zapytania, które już zostało wykonane, co czyni auto_explain ważnym narzędziem w twoim zestawie narzędzi.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak stworzyć użytkownika dla bazy danych w postgresql?

  2. Idź postgresql LIKE zapytania

  3. Postgres UNIKALNE OGRANICZENIE dla tablicy

  4. django.db.utils.ProgrammingError:relacja już istnieje

  5. INSERT COMMAND ::BŁĄD:wartość kolumny nie istnieje