Да разберем защо заявка, която се представя добре при разработката и тестването, ускорява производството, понякога може да бъде предизвикателство. Прочетете, за да научите повече за няколко функции, които могат да дадат представа за това как вашите заявки се представят в производството.
Текущо изпълнявани заявки
Когато клиент свързва PostgreSQL сървър, основният процес на Postgres сървър (исторически наричан postmaster ) създава нов процес (нареченbackend ) за обслужване на заявките на клиента. Следователно всеки бекенд или чака клиентът му да изпрати заявка, или се опитва да изпълни такава.
Системният изглед pg_stat_activity показва информация за всеки бекенд, който се изпълнява в момента. По-специално, той показва заявката, която бекендисът изпълнява в момента, ако е активен, или последната заявка, която е изпълнила, ако чака клиентът да изпрати друга заявка.
Ето два бекенда, обслужващи клиенти, свързани към базата данни testdb
, като и двамата активно изпълняват своите заявки:
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';
Понякога заявката може да чака заключване и това също показва inpg_stat_activity. Тук можете да видите INSERT, чакащ заключване на релация:
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);
За повече информация относно pg_stat_activity вижте документите.
Въпреки че този изглед е полезен, за да разберете какво прави Postgres в момента, той не предоставя информация за статистически данни за изпълнението на заявки или информация за заявки, които са завършили изпълнението.
Всички заявки се изпълняват в миналото
За това разширението pg_stat_statements е безценен. Това разширение е включено в основната дистрибуция на PostgreSQL и също е достъпно в управлявани услуги като AWS RDS и GCP SQL.
pg_stat_statements (PSS) е „разширение“ в термините на PostgreSQL и първо трябва да бъде инсталирано:
- Направете справка с документацията на вашата дистрибуция на Linux, за да видите дали разширението е предварително инсталирано или изисква инсталиране на друг пакет. Например, на Centos 7 ще трябва да
sudo yum install postgresql-contrib
. - Редактирайте основния конфигурационен файл postgresql.conf (обикновено под
/etc
, като/etc/postgresql/10/main/postgresql.conf
на Debian) и променете стойността наshared_preload_libraries
към „pg_stat_statements“. Това е списък със стойности, разделени със запетая, така че ако вече има нещо, добавете запетая и след това „pg_stat_statements“. - За AWS RDS ще трябва да промените активната си група параметри и да зададете стойността.
- След като редактирате „shared_preload_libraries“, ще трябва да рестартирате демона на PostgreSQL. За съжаление няма начин да заобиколите това. На AWS RDS ще трябва да рестартирате екземпляра на RDS.
- След рестартиране сървърът на PostgreSQL би заредил споделената библиотека и можем да инсталираме разширението, като изпълним
CREATE EXTENSION pg_stat_statements
. Ще трябва да сте суперпотребител, за да изпълните тази команда. - Всъщност можете да инсталирате разширението във всяка база данни и въпреки това да виждате заявките във всички бази данни.
След като разширението е инсталирано, можете да заявите изгледа, нареченpg_stat_statements
за да получите информация за всяка една заявка, изпълнена след инсталирането на разширението.
Числата, като времето, необходимо за изпълнение на заявката, се натрупват като сума. Само за времето за изпълнение на заявката се представят някои статистически данни (средно, мин., максимално, стандартно отклонение). Тези стойности могат да бъдат изчистени с помощта на функциятаpg_stat_statements_reset
.
Ето как се получава ред от pg_stat_statements
изглежда така:
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
Освен идентифициращите параметри (потребител, база данни, заявка), можете да разберете много интересни неща за вашата заявка:
- Колко време обикновено отнема изпълнението (
mean_time
) - Колко реда средно връща (
rows
/calls
) - Количеството данни, прочетени от споделения буферен кеш, и количеството данни, прочетени от диска (
shared_blks_read
показва общото количество данни, прочетени от заявката, от коитоshared_blks_hit
идва от кеша) - Обемът данни, които трябваше да бъдат записани на диска синхронно поради натиска в кеша (
shared_blks_written
) - Обемът на записаните данни, като броя на докоснатите блокове (
shared_blks_dirtied
) - Количеството време, прекарано в диска за четене и запис (
blk_{read,write}_time
) - Временни файлове, записани и прочетени от (
temp_blks_{read,written}
) - Временни таблици, записани и прочетени от (
local_*
)
Времената за четене и запис на диска са налични само ако конфигурационният параметърtrack_io_timing
е включен. По подразбиране не е така. В повечето съвременни Linux системи трябва да е добре да включите този параметър. Прочетете повече.
Струва си да направите моментна снимка на pg_stat_statements
данни непрекъснато на редовни интервали, за да видите как тези параметри се развиват на база на заявка. Инструментът с отворен код pgmetrics може да извлича и излага pg_stat_statements
данни като JSON за по-лесна автоматизация.
Заявките се изпълняват през времеви диапазон
След като имате такава система, става лесно да проследявате заявките, изпълнени в даден период от време. Това улеснява отстраняването на проблеми, като например защо ежедневната групова работа отне повече от очакваното.
Чрез изваждане на броячите между две дадени времеви отпечатъци можете да намерите по-голямата част от числата както преди, с изключение на мин., макс. и стандартно отклонение. Това е достатъчно, за да идентифицирате заявките, които са били изпълнени в рамките на времевия диапазон, и ресурсите, които консумират.
Регистриране на бавни заявки
Друг начин за бързо идентифициране на заявки, които отнемат повече време от очакваното, е да включите регистрирането на изрази. Можете да посочите прагова продължителност и ако заявката отнеме повече време, за да завърши, тя се записва. (В обикновения регистрационен файл на PostgreSQL няма отделен за бавни заявки.)
За да включите тази функция, редактирайте конфигурацията, както следва:
log_min_duration_statement = 1000 # in milliseconds
и презаредете Postgres. Можете също да използвате ALTER SYSTEM
:
ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds
С това всяко изявление (включително тези без DML), което отнема повече от секунда, за да завърши, се регистрира:
2019-12-02 16:57:05.727 UTC [8040] postgres@testdb LOG: duration: 10017.862 ms statement: SELECT pg_sleep(10);
Реалното време, необходимо на заявката, както и пълният текст на SQL, се записват.
Ако имате система за наблюдение на регистрационни файлове и можете да проследявате броя на бавните заявки на час / на ден, това може да служи като добър индикатор за ефективността на приложението.
Планове за изпълнение на заявка
След като откриете заявка, която смятате, че трябва да се изпълнява по-бързо, следващата стъпка е да разгледате нейния план за заявка. Обикновено се нуждаете от действителния план за заявка от производствените сървъри, с който да работите. Ако можете да изпълнявате EXPLAIN на производствени сървъри толкова страхотно, в противен случай трябва да разчитате наauto_explain
.
auto_explain
е друго основно разширение на PostgreSQL, или вече инсталирано, или налично като пакет „contrib“ за вашата дистрибуция. Предлага се и на AWSRDS. auto_explain
е малко по-лесно за инсталиране от pg_stat_statements
:
- Редактирайте конфигурацията на postgres (или групата параметри на RDS)
shared_preload_libraries
за да включитеauto_explain
. - Не е нужно обаче да рестартирате Postgres, вместо това можете просто да изпълните:
LOAD 'auto_explain';
. - Ще искате да конфигурирате настройките му, поне тази:
auto_explain.log_min_duration = 1000 # seconds
По същество всеки път, когато една заявка отнема повече време отauto_explain.log_min_duration
брой секунди за завършване, auto_explain регистрира заявката и нейния план за изпълнение на заявката в регистрационния файл, както следва:
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)
Може да регистрира плана и във формат JSON, ако имате скриптове, които могат да го обработват:
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": [
]
}
В Postgres няма друг начин освен auto_explain да разгледате плана за изпълнение на заявка, която вече е изпълнена, което прави auto_explain важен инструмент във вашата кутия с инструменти.