Що саме мені пояснює PostgreSQL?


116

Пояснення результатів MySQL досить просте. PostgreSQL трохи складніше. Я не зміг знайти хорошого ресурсу, який би це пояснив.

Чи можете ви описати, що саме пояснює мовлення, або принаймні вказати мене у напрямку хорошого ресурсу?

Відповіді:


50

Пояснення_EXPLAIN.pdf теж може допомогти.


64
Я загадкований, чому люди думають, що слайди роблять хорошу технічну документацію. Відео з розмови може бути корисним, але щільність інформації цієї слайд-колоди дуже близька до нуля. У перших шести слайдах (1/5 від загальної кількості) є рівно 1 речення технічного змісту: "• EXPLAIN працює на будь-якому DML не просто SELECT (тобто UPDATE, DELETE та INSERT)". Моє найбільше непорозуміння - це те, що означає "час запуску", і це не пояснюється ніде в цих ~ 30 слайдах.
Марк Е. Хааз

80

Частина, яку я завжди вважав заплутаною, - це вартість запуску та загальна вартість. Я Google це кожен раз, коли я забуваю про це, що повертає мене сюди, що не пояснює різниці, саме тому я пишу цю відповідь. Це те, що я зрозумів із документації PostgresEXPLAIN , пояснивши, як я це розумію.

Ось приклад програми, яка керує форумом:

EXPLAIN SELECT * FROM post LIMIT 50;

Limit  (cost=0.00..3.39 rows=50 width=422)
  ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

Ось графічне пояснення від PgAdmin:

графічне пояснення першого запиту

(Коли ви використовуєте PgAdmin, ви можете навести мишу на компонент, щоб прочитати деталі витрат.)

Вартість представлена у вигляді кортежу, наприклад , витрати на LIMITце cost=0.00..3.39і вартість сканування послідовно postзнаходиться cost=0.00..15629.12. Перше число в кортежі - це вартість запуску, а друге - загальна вартість . Оскільки я використовував EXPLAINі ні EXPLAIN ANALYZE, ці витрати є кошторисом, а не фактичними заходами.

  • Вартість запуску - хитра концепція. Він не просто відображає кількість часу до запуску цього компонента . Він представляє кількість часу, коли компонент починає виконувати (читання даних) і коли компонент виводить перший рядок .
  • Загальна вартість - це весь час виконання компонента, починаючи з того, коли він починає зчитувати дані, і закінчуючи написанням свого виводу.

Як ускладнення, витрати кожного "батьківського" вузла включають витрати його дочірніх вузлів. У текстовому поданні дерево представлене відступом, наприклад, LIMITє батьківським вузлом і Seq Scanє його дочірньою. У представленні PgAdmin стрілки вказують від дитини до батьків - напрям потоку даних - що може бути контрінтуїтивним, якщо ви знайомі з теорією графіків.

У документації зазначено, що витрати включають усі дочірні вузли, але зауважте, що загальна вартість батьків 3.39значно менша, ніж загальна вартість його дитини 15629.12. Загальна вартість не включена, тому що такий компонент LIMITне потребує опрацювання всього його вводу. Дивіться EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;приклад у документації PostgresEXPLAIN .

У наведеному вище прикладі час запуску для обох компонентів дорівнює нулю, тому що жоден компонент не потребує жодної обробки перед тим, як він починає писати рядки: послідовне сканування зчитує перший рядок таблиці та випускає його. LIMITЧитає перший рядок , а потім випромінює його.

Коли компонент повинен зробити багато обробки, перш ніж він може почати виводити будь-які рядки? Можливих причин дуже багато, але давайте розглянемо один чіткий приклад. Ось такий самий запит, який раніше, але тепер містить ORDER BYпункт:

EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;

Limit  (cost=23283.24..23283.37 rows=50 width=422)
  ->  Sort  (cost=23283.24..23859.27 rows=230412 width=422)
        Sort Key: body
        ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

І графічно:

графічне пояснення другого запиту

Ще раз повторне сканування postне має вартості запуску: воно починає виводити рядки негайно. Але сорт має значну вартість запуску, 23283.24оскільки він повинен сортувати всю таблицю, перш ніж вона зможе вивести навіть один рядок . Загальна вартість сортування 23859.27лише трохи вища, ніж вартість запуску, що відображає той факт, що після сортування всього набору даних, відсортовані дані можуть видаватися дуже швидко.

Зауважте, що час запуску пристрою LIMIT 23283.24точно рівно часу запуску сортування. Це не тому, що LIMITсама по собі має високий час запуску. Він фактично має нульовий час запуску сам по собі, але EXPLAINзгортає всі витрати дитини на кожного з батьків, тому час LIMITзапуску включає суму часу запуску його дітей.

Такий набір витрат може ускладнити розуміння вартості виконання кожного окремого компонента. Наприклад, у нас LIMITнульовий час запуску, але це не очевидно на перший погляд. З цієї причини ще декілька людей, пов’язані з тлумаченням.depesz.com , - інструмент, створений Губертом Любачевським (він же depesz), який допомагає зрозуміти EXPLAIN, серед іншого, - відняття дитячих витрат від батьківських витрат. У деяких коротких публікаціях про свій інструмент він згадує деякі інші складності .


4
Дякую за це. Я також хотів би додати візуалізатор, що пояснює, що робить ще кращу роботу з відображенням результатів (imo). tatiyants.com/pev
Джонатан Портер

Чудова відповідь. І ваш коментар, що вартість запуску включає час повернення першого рядка, допоміг мені зрозуміти, чому вартість запуску для сортування не була лише 15629.12.
Джоел Вігтон

43

Він виконується від більшості відступів до найменших відступів, і я вважаю, що знизу плану до верху. (Отже, якщо є два відступних розділи, перший, який знаходиться внизу сторінки, виконується спочатку, потім, коли вони зустрічаються з іншими, виконується правило, тоді виконується правило, яке приєднується до них.)

Ідея полягає в тому, що на кожному кроці є 1 або 2 набори даних, які надходять і обробляються за деяким правилом. Якщо лише один набір даних, ця операція робиться для цього набору даних. (Наприклад, скануйте індекс, щоб визначити, які рядки ви хочете, відфільтруйте набір даних або відсортуйте його.) Якщо два, два набори даних - це дві речі, які відступають далі, і до них приєднується правило, яке ви бачите. Про значення більшості правил можна легко здогадатися (особливо, якщо ви прочитали купу планів пояснення раніше), однак ви можете спробувати перевірити окремі пункти або заглянувши в документацію, або (простіше), просто вписавши фразу в Google разом із кількома ключовими словами EXPLAIN.

Це, очевидно, не повне пояснення, але воно забезпечує достатній контекст, щоб ви могли зрозуміти, що хочете. Наприклад, розгляньте цей план із фактичної бази даних:

explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';

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

 Merge Join  (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
   Merge Cond: (a.orderid = b.orderid)
   ->  Sort  (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
         Sort Key: a.orderid
         Sort Method:  quicksort  Memory: 1695kB
         ->  Bitmap Heap Scan on orderitemattribute a  (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
               Recheck Cond: ((attributeid)::text = 'display-album'::text)
               ->  Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
                     Index Cond: ((attributeid)::text = 'display-album'::text)
   ->  Sort  (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
         Sort Key: b.orderid
         Sort Method:  quicksort  Memory: 76kB
         ->  Bitmap Heap Scan on orderitem b  (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
               Recheck Cond: ((productid)::text = 'ModernBook'::text)
               ->  Bitmap Index Scan on id_orderitem_productid  (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
                     Index Cond: ((productid)::text = 'ModernBook'::text)
 Total runtime: 842.134 ms
(17 rows)

Спробуйте прочитати це для себе і подивіться, чи є сенс.

Що я читав, це те, що база даних спочатку сканує id_orderitem_productidіндекс, використовуючи його, щоб знайти потрібні рядки orderitem, потім сортує цей набір даних за допомогою quicksort (тип, який використовується, зміниться, якщо дані не вміщуються в оперативній пам'яті), а потім відкладає цю сторону.

Далі він сканує orditematt_attributeid_idxзнайти рядки, від яких хоче, orderitemattributeа потім сортує цей набір даних за допомогою швидкості.

Потім він бере два набори даних і об'єднує їх. (Об'єднання злиття - це свого роду "блискавкова" операція, коли вона проводить паралельно два відсортовані набори даних, випромінюючи з'єднаний рядок, коли вони збігаються.)

Як я вже говорив, ви працюєте через внутрішню частину плану до зовнішньої частини, знизу вгору.


22

Існує також онлайн-інструмент для помічників Depesz , який підкреслить, де є дорогі частини результатів аналізу.

також є один, ось такі самі результати , які мені роблять зрозумілішими, де проблема.


20
Здається, що пояснюється роз'яснення-analyze.info , але я погоджуюся з тим, що тлумач.depesz.com дуже корисний.
benvolioT

13

PgAdmin покаже вам графічне зображення плану пояснення. Перемикання між цими двома можливостями допоможе вам зрозуміти, що означає текстове подання. Однак, якщо ви просто хочете дізнатися, що це відбувається, ви можете завжди завжди використовувати графічний інтерфейс.



0

Якщо ви встановите pgadmin, є кнопка Пояснити, яка, як і даючи текстовий вихід, малює діаграми того, що відбувається, показуючи фільтри, сортування та злиття підмножини, які мені здаються дуже корисними, щоб побачити, що відбувається.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.