Паўгода таму
За мінулыя месяцы мы зрабілі пра яго
І зараз гатовы расказаць аб новых магчымасцях, якімі вы можаце карыстацца.
Падтрымка розных фарматаў планаў
План з лога, разам з запытам
Прама з кансолі вылучаем увесь блок, пачынальна з радка з Query Text, з усімі лідзіруючымі прабеламі:
Query Text: INSERT INTO dicquery_20200604 VALUES ($1.*) ON CONFLICT (query)
DO NOTHING;
Insert on dicquery_20200604 (cost=0.00..0.05 rows=1 width=52) (actual time=40.376..40.376 rows=0 loops=1)
Conflict Resolution: NOTHING
Conflict Arbiter Indexes: dicquery_20200604_pkey
Tuples Inserted: 1
Conflicting Tuples: 0
Buffers: shared hit=9 read=1 dirtied=1
-> Result (cost=0.00..0.05 rows=1 width=52) (actual time=0.001..0.001 rows=1 loops=1)
… і закідваем усё скапіяванае прама ў поле для плана, нічога не падзяляючы:
На выхадзе атрымліваем бонусам да разабранага плана яшчэ і ўкладку «кантэкст», дзе наш запыт прадстаўлены ва ўсёй красе:
JSON і YAML
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM pg_class;
"[
{
"Plan": {
"Node Type": "Seq Scan",
"Parallel Aware": false,
"Relation Name": "pg_class",
"Alias": "pg_class",
"Startup Cost": 0.00,
"Total Cost": 1336.20,
"Plan Rows": 13804,
"Plan Width": 539,
"Actual Startup Time": 0.006,
"Actual Total Time": 1.838,
"Actual Rows": 10266,
"Actual Loops": 1,
"Shared Hit Blocks": 646,
"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
},
"Planning Time": 5.135,
"Triggers": [
],
"Execution Time": 2.389
}
]"
Хоць з вонкавымі двукоссямі, як капіюе pgAdmin, хоць без - кідаем у тое ж поле, на выхадзе - прыгажосць:
Пашыраная візуалізацыя
Planning Time / Execution Time
Цяпер лепш відаць, куды сышоў дадатковы час пры выкананні запыту:
I/O Timing
Часам даводзіцца сутыкацца з сітуацыяй, калі ў плане накшталт і рэсурсаў чыталася-пісалася не занадта шмат, а накшталт і час выканання непараўнальна вялікае нейкае.
Тут даводзіцца казаць: "Ой, мусіць, у той момант кружэлка на серверы быў занадта перагружаны, таму чыталася так доўга!Але неяк гэта не занадта дакладна…
Але можна гэта вызначыць абсалютна дакладна. Справа ў тым, што сярод опцый канфігурацыі PG-сервера ёсць track_io_timing
Уключае замер часу аперацый уводу/высновы. Гэты параметр па змаўчанні адключаны, бо для гэтага патрабуецца ўвесь час запытваць бягучы час у аперацыйнай сістэмы, што можа значна запаволіць працу на некаторых платформах. Для ацэньвання выдаткаў замеру часу на вашай платформе можна скарыстацца ўтылітай pg_test_timing. Статыстыку ўводу/высновы можна атрымаць праз уяўленне pg_stat_database, у выснове EXPLAIN (калі выкарыстоўваецца параметр BUFFERS) і праз уяўленне pg_stat_statements.
Гэты параметр можна ўключыць і ў рамках лакальнай сесіі:
SET track_io_timing = TRUE;
Ну, а зараз самае прыемнае - мы навучыліся разумець і адлюстроўваць гэтыя дадзеныя з улікам усіх трансфармацый дрэва выканання:
Тут можна заўважыць, што з 0.790ms усяго часу выканання 0.718ms заняло чытанне адной старонкі дадзеных, 0.044ms - запіс яе ж, а на ўсю астатнюю карысную актыўнасць было выдаткавана ўсяго 0.028ms!
Будучыня з PostgreSQL 13
Азнаёміцца з поўным аглядам новаўвядзенняў можна
Planning buffers
Улік рэсурсаў, выдзеленых планавальніку, знайшоў сваё адлюстраванне яшчэ ў адным патчы, які не адносіцца да pg_stat_statements. EXPLAIN з опцыяй BUFFERS будзе паведамляць колькасць буфераў, скарыстаных на этапе планавання:
Seq Scan on pg_class (actual rows=386 loops=1) Buffers: shared hit=9 read=4 Planning Time: 0.782 ms Buffers: shared hit=103 read=11 Execution Time: 0.219 ms
Інкрыментальная сартаванне
У выпадках, калі неабходна сартаванне па шматлікіх ключах (k1, k2, k3…), планавальнік зараз можа скарыстацца веданнем аб тым, што дадзеныя ўжо адсартаваныя па некалькіх з першых ключоў (напрыклад, k1 і k2). У гэтым выпадку можна не перасартаваць усе дадзеныя нанова, а падзяліць іх на паслядоўныя групы з аднолькавымі значэннямі k1 і k2, і "дасартаваць" па ключы k3.
Такім чынам усё сартаванне распадаецца на некалькі паслядоўных сартаванняў меншага памеру. Гэта зніжае аб'ём неабходнай памяці, а яшчэ дазваляе выдаваць першыя дадзеныя раней, чым усё сартаванне будзе выканана цалкам.
Incremental Sort (actual rows=2949857 loops=1) Sort Key: ticket_no, passenger_id Presorted Key: ticket_no Full-sort Groups: 92184 Sort Method: quicksort Memory: avg=31kB peak=31kB -> Index Scan using tickets_pkey on tickets (actual rows=2949857 loops=1) Planning Time: 2.137 ms Execution Time: 2230.019 ms
Паляпшэнні UI/UX
Скрыншоты, яны ўсюды!
Цяпер на кожнай укладцы з'явілася магчымасць хутка ўзяць скрыншот ўкладкі ў буфер абмену на ўсю шырыню і глыбіню ўкладкі - "прыцэл" справа-зверху:
Уласна, большасць карцінак для гэтай публікацыі атрымана менавіта так.
Рэкамендацыі на вузлах
Іх не толькі стала больш, але і пра кожную можна
Выдаленне з архіва
Некаторыя вельмі прасілі дадаць магчымасць выдаляць "зусім" нават непублікаваныя ў архіве планы — калі ласка, дастаткова націснуць адпаведны абразок:
Ну, і не забываем, што ў нас ёсць
Крыніца: habr.com