PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да идентифицираме проблеми с производителността на PostgreSQL с бавни заявки

Когато работите с OLTP (OnLine Transaction Processing) бази данни, производителността на заявките е от първостепенно значение, тъй като пряко влияе върху потребителското изживяване. Бавните заявки означават, че приложението не реагира и се чувства бавно и това води до лоши проценти на реализация, недоволни потребители и всякакви проблеми.

OLTP е един от често срещаните случаи на използване на PostgreSQL, затова искате вашите заявки да работят възможно най-плавно. В този блог бихме искали да поговорим за това как можете да идентифицирате проблеми с бавните заявки в PostgreSQL.

Разбиране на бавния журнал

Общо казано, най-типичният начин за идентифициране на проблеми с производителността с PostgreSQL е събирането на бавни заявки. Има няколко начина да го направите. Първо, можете да го активирате в една база данни:

pgbench=# ALTER DATABASE pgbench SET log_min_duration_statement=0;

ALTER DATABASE

След това всички нови връзки към базата данни „pgbench“ ще бъдат регистрирани в дневника на PostgreSQL.

Възможно е също да активирате това глобално, като добавите:

log_min_duration_statement = 0

към PostgreSQL конфигурация и след това презаредете конфигурацията:

pgbench=# SELECT pg_reload_conf();

 pg_reload_conf

----------------

 t

(1 row)

Това позволява регистриране на всички заявки във всички бази данни във вашия PostgreSQL. Ако не виждате никакви регистрационни файлове, може да искате да активирате и logging_collector =on. Регистраторите ще включват целия трафик, идващ към системните таблици на PostgreSQL, което го прави по-шумен. За нашите цели нека се придържаме към регистрирането на ниво база данни.

Това, което ще видите в регистъра, са записи, както следва:

2020-02-21 09:45:39.022 UTC [13542] LOG:  duration: 0.145 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 29817899;

2020-02-21 09:45:39.022 UTC [13544] LOG:  duration: 0.107 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 11782597;

2020-02-21 09:45:39.022 UTC [13529] LOG:  duration: 0.065 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 16318529;

2020-02-21 09:45:39.022 UTC [13529] LOG:  duration: 0.082 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + 3063 WHERE tid = 3244;

2020-02-21 09:45:39.022 UTC [13526] LOG:  duration: 16.450 ms statement: UPDATE pgbench_branches SET bbalance = bbalance + 1359 WHERE bid = 195;

2020-02-21 09:45:39.023 UTC [13523] LOG:  duration: 15.824 ms statement: UPDATE pgbench_accounts SET abalance = abalance + -3726 WHERE aid = 5290358;

2020-02-21 09:45:39.023 UTC [13542] LOG:  duration: 0.107 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + -2716 WHERE tid = 1794;

2020-02-21 09:45:39.024 UTC [13544] LOG:  duration: 0.112 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + -3814 WHERE tid = 278;

2020-02-21 09:45:39.024 UTC [13526] LOG:  duration: 0.060 ms statement: INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (4876, 195, 39955137, 1359, CURRENT_TIMESTAMP);

2020-02-21 09:45:39.024 UTC [13529] LOG:  duration: 0.081 ms statement: UPDATE pgbench_branches SET bbalance = bbalance + 3063 WHERE bid = 369;

2020-02-21 09:45:39.024 UTC [13523] LOG:  duration: 0.063 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 5290358;

2020-02-21 09:45:39.024 UTC [13542] LOG:  duration: 0.100 ms statement: UPDATE pgbench_branches SET bbalance = bbalance + -2716 WHERE bid = 210;

2020-02-21 09:45:39.026 UTC [13523] LOG:  duration: 0.092 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + -3726 WHERE tid = 67;

2020-02-21 09:45:39.026 UTC [13529] LOG:  duration: 0.090 ms statement: INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (3244, 369, 16318529, 3063, CURRENT_TIMESTAMP);

Можете да видите информация за заявката и нейната продължителност. Не много друго, но определено е добро място за начало. Основното нещо, което трябва да имате предвид, е, че не всяка бавна заявка е проблем. Понякога заявките трябва да имат достъп до значително количество данни и се очаква да им отнеме повече време за достъп и анализ на цялата информация, поискана от потребителя. Друг въпрос е какво означава "бавно"? Това зависи най-вече от приложението. Ако говорим за интерактивни приложения, най-вероятно се забелязва всичко по-бавно от секунда. В идеалния случай всичко се изпълнява в рамките на 100 - 200 милисекунди.

Разработване на план за изпълнение на заявка

След като установим, че дадената заявка наистина е нещо, което искаме да подобрим, трябва да разгледаме плана за изпълнение на заявката. На първо място, може да се случи, че не можем да направим нищо по въпроса и ще трябва да приемем, че дадената заявка е просто бавна. Второ, плановете за изпълнение на заявки могат да се променят. Оптимизаторите винаги се опитват да изберат най-оптималния план за изпълнение, но те вземат своите решения въз основа само на извадка от данни, поради което може да се случи планът за изпълнение на заявката да се промени във времето. В PostgreSQL можете да проверите плана за изпълнение по два начина. Първо, прогнозният план за изпълнение, като се използва EXPLAIN:

pgbench=# EXPLAIN SELECT abalance FROM pgbench_accounts WHERE aid = 5290358;

                                          QUERY PLAN

----------------------------------------------------------------------------------------------

 Index Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.56..8.58 rows=1 width=4)

   Index Cond: (aid = 5290358)

Както можете да видите, се очаква да имаме достъп до данни чрез търсене на първичен ключ. Ако искаме да проверим отново как точно ще бъде изпълнена заявката, можем да използваме EXPLAIN ANALYZE:

pgbench=# EXPLAIN ANALYZE SELECT abalance FROM pgbench_accounts WHERE aid = 5290358;

                                                               QUERY PLAN

----------------------------------------------------------------------------------------------------------------------------------------

 Index Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.56..8.58 rows=1 width=4) (actual time=0.046..0.065 rows=1 loops=1)

   Index Cond: (aid = 5290358)

 Planning time: 0.053 ms

 Execution time: 0.084 ms

(4 rows)

Сега PostgreSQL изпълни тази заявка и тя може да ни каже не само приблизителните стойности, но и точните числа, когато става въпрос за плана за изпълнение, броя на редовете, до които е достъпен и т.н. Моля, имайте предвид, че регистрирането на всички заявки може да се превърне в сериозен проблем за вашата система. Трябва също така да следите трупите и да се уверите, че са правилно завъртени.

Pg_stat_statements

Pg_stat_statements е разширението, което събира статистически данни за изпълнението за различни типове заявки.

pgbench=# select query, calls, total_time, min_time, max_time, mean_time, stddev_time, rows from public.pg_stat_statements order by calls desc LIMIT 10;

                                                query                                                 | calls | total_time | min_time | max_time |     mean_time | stddev_time | rows

------------------------------------------------------------------------------------------------------+-------+------------------+----------+------------+---------------------+---------------------+-------

 UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2                                  | 30437 | 6636.83641200002 | 0.006533 | 83.832148 | 0.218051595492329 | 1.84977058799388 | 30437

 BEGIN                                                                                                | 30437 | 231.095600000001 | 0.000205 | 20.260355 | 0.00759258796859083 | 0.26671126085716 | 0

 END                                                                                                  | 30437 | 229.483213999999 | 0.000211 | 16.980678 | 0.0075396134310215 | 0.223837608828596 | 0

 UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2                                  | 30437 | 290021.784321001 | 0.019568 | 805.171845 | 9.52859297305914 | 13.6632712046825 | 30437

 UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2                                   | 30437 | 6667.27243200002 | 0.00732 | 212.479269 | 0.219051563294674 | 2.13585110968012 | 30437

 SELECT abalance FROM pgbench_accounts WHERE aid = $1                                                 | 30437 | 3702.19730600006 | 0.00627 | 38.860846 | 0.121634763807208 | 1.07735927551245 | 30437

 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP) | 30437 | 2349.22475800002 | 0.003218 |  61.372127 | 0.0771831901304325 | 0.971590327400244 | 30437

 SELECT $1                                                                                            | 6847 | 60.785467 | 0.002321 | 7.882384 | 0.00887767883744706 | 0.105198744982906 | 6847

 insert into pgbench_tellers(tid,bid,tbalance) values ($1,$2,$3)                                      | 5000 | 18.592042 | 0.001572 | 0.741427 | 0.0037184084 | 0.0137660355678027 | 5000

 insert into pgbench_tellers(tid,bid,tbalance) values ($1,$2,$3)                                      | 3000 | 7.323788 | 0.001598 | 0.40152 | 0.00244126266666667 | 0.00834442591085048 | 3000

(10 rows)

Както можете да видите от данните по-горе, имаме списък с различни заявки и информация за времето на тяхното изпълнение - това е само част от данните, които можете да видите в pg_stat_statements, но е достатъчно за да разберем, че търсенето на първичния ни ключ понякога отнема почти 39 секунди, за да завърши – това не изглежда добре и определено е нещо, което искаме да проучим.

Ако не сте активирали pg_stat_statements, можете да го направите по стандартен начин. Или чрез конфигурационен файл и

shared_preload_libraries = 'pg_stat_statements'

Или можете да го активирате чрез командния ред на PostgreSQL:

pgbench=# CREATE EXTENSION pg_stat_statements;

CREATE EXTENSION

Използване на ClusterControl за елиминиране на бавни заявки

Ако случайно използвате ClusterControl за управление на вашата PostgreSQL база данни, можете да я използвате за събиране на данни за бавни заявки.

Както виждате, той събира данни за изпълнението на заявка - изпратени редове и проверени, статистика за времето на изпълнение и т.н. С него можете лесно да определите най-скъпите заявки и да видите как изглежда средното и максимално време за изпълнение. По подразбиране ClusterControl събира заявки, чието завършване е отнело повече от 0,5 секунди, можете да промените това в настройките:

Заключение

Този кратък блог в никакъв случай не обхваща всички аспекти и инструменти, полезни за идентифициране и решаване на проблеми с производителността на заявките в PostgreSQL. Надяваме се, че това е добро начало и че ще ви помогне да разберете какво можете да направите, за да определите първопричината за бавните заявки.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL, Postgres OID, какви са те и защо са полезни?

  2. Как работи функцията Radians() в PostgreSQL

  3. Естествен сорт, поддържащ големи числа

  4. Как да групирате времеви печати в острови (въз основа на произволна празнина)?

  5. Как работи make_timestamp() в PostgreSQL