czwartek, 16 stycznia 2014

EXPLAIN plan w PostgreSQL v9.1 - Wprowadzenie

Jakiś czas temu omawiałam jak wygląda EXPLAIN plan w MySQL-u (http://db-diary.blogspot.com/2014/01/exaplain-plan-w-mysql-v55.html). Teraz przyszedł czas na PostgreSQL-a. Będę używać wersji 9.1, która dla instrukcji EXPLAIN, nieznacznie różni się od innych wersji 9.x i ma dodatkowe opcje w stosunku do wersji 8.x.

Poniżej opiszę tylko wywołanie instrukcji EXPLAIN, a do opracowania informacji, jak czytać wynik tego polecenia, aby optymalizować naszej komendy, przejdę w następnym poście. Wszystkie te informacje możecie także znaleźć w dokumentacji :http://www.postgresql.org/docs/9.1/static/sql-explain.html.

Wywołanie instrukcji EXPLAIN:
EXPLAIN [ ( option [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement

where option can be one of:

    ANALYZE [ boolean ]
    VERBOSE [ boolean ]
    COSTS [ boolean ]
    BUFFERS [ boolean ]
    FORMAT { TEXT | XML | JSON | YAML } 

Opcje instrukcji EXPLAIN z przykładami:
  • ANALYZE - wykonuje polecenie i zwraca rzeczywisty czas wykonania komendy. Domyślana wartość parametru: FALSE
postgres@test(127.0.0.1) # explain (ANALYZE, costs false) select * from t1 where c1 IN (1,7);
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Bitmap Heap Scan on t1 (actual time=0.023..0.025 rows=2 loops=1)
   Recheck Cond: (c1 = ANY ('{1,7}'::integer[]))
   ->  Bitmap Index Scan on t1_pkey (actual time=0.017..0.017 rows=2 loops=1)
         Index Cond: (c1 = ANY ('{1,7}'::integer[]))
 Total runtime: 0.054 ms
(5 rows)

  • VERBOSE - wyświetla dodatkowe informacje. Domyślna wartość parametru: FALSE
postgres@test(127.0.0.1) # explain (VERBOSE, costs false) select * from t1 where c1 IN (1,7);
                       QUERY PLAN                       
--------------------------------------------------------
 Bitmap Heap Scan on public.t1
   Output: c1, c2
   Recheck Cond: (t1.c1 = ANY ('{1,7}'::integer[]))
   ->  Bitmap Index Scan on t1_pkey
         Index Cond: (t1.c1 = ANY ('{1,7}'::integer[]))
(5 rows)

  • COSTS - wyświetla informacje o :
    • szacowanym koszcie (np. cost=0.00..10.44 to cost=[koszta startowy]..[koszt całkowity jeśli wszystkie wiersze zostaną zwrócone]) dla każdego fragmentu planu
    • szacowanej ilość wierszy zwróconych
    • średniej długości (w bajtach) każdego wiersza
    Domyślna wartość parametru: TRUE
  • BUFFERS - zwraca informację o użyciu bufora. Zawiera:
    • Shared Hit Blocks: liczbę 'trafionych' bloków współdzielonych, np. użytych do łączenia
    • Shared Read Blocks: liczbę przeczytanych bloków współdzielonych
    • Shared Written Blocks: liczbę zapisanych bloków współdzielonych
    • Local Hit Blocks: liczbę bloków lokalnych użytych np. do łączenia
    • Local Read Blocks: liczbę przeczytanych bloków lokalnych
    • Local Written Blocks: liczbę zapisanych bloków lokalnych
    • Temp Read Blocks: liczbę czytanych bloków tymczasowych
    • Temp Written Blocks: liczbę zapisanych bloków tymczasowych
    Wyświetla tylko wartości niezerowe dla formatu TEXT. Wartość domyślna parametru: FALSE. Ta opcja wymaga odpalenia polecenia, dlatego trzeba ją wykonać z opcją ANALYZE.
postgres@test(127.0.0.1) # explain (ANALYZE,VERBOSE, buffers true, FORMAT TEXT, costs false) select * from t1, t3 where t1.c1 = t3.c1;
                                 QUERY PLAN                                  
-----------------------------------------------------------------------------
 Hash Join (actual time=0.039..0.045 rows=2 loops=1)
   Output: t1.c1, t1.c2, t3.c1, t3.c2
   Hash Cond: (t3.c1 = t1.c1)
   Buffers: shared hit=2
   ->  Seq Scan on public.t3 (actual time=0.006..0.008 rows=2 loops=1)
         Output: t3.c1, t3.c2
         Buffers: shared hit=1
   ->  Hash (actual time=0.019..0.019 rows=6 loops=1)
         Output: t1.c1, t1.c2
         Buckets: 1024  Batches: 1  Memory Usage: 1kB
         Buffers: shared hit=1
         ->  Seq Scan on public.t1 (actual time=0.003..0.008 rows=6 loops=1)
               Output: t1.c1, t1.c2
               Buffers: shared hit=1
 Total runtime: 0.081 ms
(15 rows)

  • FORMAT - wyróżnia format wyjściowy. Domyślna wartość parametru: TEXT. Poniżej przykład instrukcji EXPLAIN w formacie JSON:
postgres@test(127.0.0.1) # explain (ANALYZE,VERBOSE, buffers true, FORMAT JSON) select * from t1 where c1 IN (1,7);
                          QUERY PLAN                           
---------------------------------------------------------------
 [                                                            +
   {                                                          +
     "Plan": {                                                +
       "Node Type": "Bitmap Heap Scan",                       +
       "Relation Name": "t1",                                 +
       "Schema": "public",                                    +
       "Alias": "t1",                                         +
       "Startup Cost": 8.52,                                  +
       "Total Cost": 13.86,                                   +
       "Plan Rows": 2,                                        +
       "Plan Width": 42,                                      +
       "Actual Startup Time": 0.027,                          +
       "Actual Total Time": 0.030,                            +
       "Actual Rows": 2,                                      +
       "Actual Loops": 1,                                     +
       "Output": ["c1", "c2"],                                +
       "Recheck Cond": "(t1.c1 = ANY ('{1,7}'::integer[]))",  +
       "Shared Hit Blocks": 3,                                +
       "Shared Read Blocks": 0,                               +
       "Shared Written Blocks": 0,                            +
       "Local Hit Blocks": 0,                                 +
       "Local Read Blocks": 0,                                +
       "Local Written Blocks": 0,                             +
       "Temp Read Blocks": 0,                                 +
       "Temp Written Blocks": 0,                              +
       "Plans": [                                             +
         {                                                    +
           "Node Type": "Bitmap Index Scan",                  +
           "Parent Relationship": "Outer",                    +
           "Index Name": "t1_pkey",                           +
           "Startup Cost": 0.00,                              +
           "Total Cost": 8.52,                                +
           "Plan Rows": 2,                                    +
           "Plan Width": 0,                                   +
           "Actual Startup Time": 0.019,                      +
           "Actual Total Time": 0.019,                        +
           "Actual Rows": 2,                                  +
           "Actual Loops": 1,                                 +
           "Index Cond": "(t1.c1 = ANY ('{1,7}'::integer[]))",+
           "Shared Hit Blocks": 2,                            +
           "Shared Read Blocks": 0,                           +
           "Shared Written Blocks": 0,                        +
           "Local Hit Blocks": 0,                             +
           "Local Read Blocks": 0,                            +
           "Local Written Blocks": 0,                         +
           "Temp Read Blocks": 0,                             +
           "Temp Written Blocks": 0                           +
         }                                                    +
       ]                                                      +
     },                                                       +
     "Triggers": [                                            +
     ],                                                       +
     "Total Runtime": 0.058                                   +
   }                                                          +
 ]
(1 row)

statement:  jest dowolnym poleceniem SELECT, INSERT, UPDATE, DELETE, VALUES, EXECUTE, DECLATE, CREATE TABLE AS ...

Musimy pamiętać, że użycie opcji ANALYZE do polecień INSERT, UPDATE, DELETE, CREATE TABLE AS albo EXECUTE spowoduje zmiany w naszej bazie. Aby się przed tym uchronić, musimy nasze poleceni zawrzeć w transakcji, która zostanie później ROLLBACK-owana.
postgres@test(127.0.0.1) # select * from t1;
 c1 |   c2    
----+---------
  1 | 
  2 | 
  3 | asdfsdf
  5 | asdfsdf
(4 rows)

postgres@test(127.0.0.1) # explain (Analyze,buffers true) insert into t1 (c1,c2) values (6,'test'), (7,'test');
                                                  QUERY PLAN                                                  
--------------------------------------------------------------------------------------------------------------
 Insert on t1  (cost=0.00..0.03 rows=2 width=42) (actual time=0.044..0.044 rows=0 loops=1)
   Buffers: shared hit=6
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=42) (actual time=0.003..0.005 rows=2 loops=1)
 Total runtime: 0.076 ms
(4 rows)

postgres@test(127.0.0.1) # begin; explain (Analyze,buffers true) insert into t1 (c1,c2) values (8,'test'), (9,'test'); rollback;
BEGIN
                                                  QUERY PLAN                                                  
--------------------------------------------------------------------------------------------------------------
 Insert on t1  (cost=0.00..0.03 rows=2 width=42) (actual time=0.048..0.048 rows=0 loops=1)
   Buffers: shared hit=6
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=42) (actual time=0.003..0.006 rows=2 loops=1)
 Total runtime: 0.083 ms
(4 rows)

ROLLBACK
postgres@test(127.0.0.1) # select * from t1;
 c1 |   c2    
----+---------
  1 | 
  2 | 
  3 | asdfsdf
  5 | asdfsdf
  6 | test
  7 | test
(6 rows)

Zawarta tutaj informacja jest wstępem do analizowania, co się dzieje z naszym zapytaniem. Znając te podstawy, będziemy mogli przejść dalej.

Powodzenia w nauce :-)

Brak komentarzy:

Prześlij komentarz