Вопрос

Вывод объяснения MySQL довольно прост.PostgreSQL немного сложнее.Я также не смог найти хороший ресурс, который бы это объяснял.

Можете ли вы описать, что именно объясняется, или хотя бы указать мне направление на хороший ресурс?

Это было полезно?

Решение

Объяснение_EXPLAIN.pdf тоже может помочь.

Другие советы

Что меня всегда смущало, так это соотношение стоимости запуска и общей стоимости.Я гуглю это каждый раз, когда забываю об этом, что возвращает меня сюда, что не объясняет разницы, поэтому я пишу этот ответ.Это то, что я почерпнул из Постгрес EXPLAIN документация, объяснил, как я понимаю.

Вот пример приложения, которое управляет форумом:

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:

graphical explanation of first query

(Когда вы используете 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; пример в Постгрес EXPLAIN документация.

В приведенном выше примере время запуска для обоих компонентов равно нулю, поскольку ни одному из компонентов не требуется выполнять какую-либо обработку, прежде чем он начнет записывать строки:последовательное сканирование считывает первую строку таблицы и выдает ее.А 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)

И графически:

graphical explanation of second query

И снова последовательное сканирование post не имеет стартовой стоимости:он немедленно начинает выводить строки.Но этот сорт имеет значительные начальные затраты. 23283.24 потому что это должно отсортировать всю таблицу, прежде чем она сможет вывести хотя бы одну строку.Общая стоимость сорта 23859.27 лишь немного превышает стоимость запуска, что отражает тот факт, что после того, как весь набор данных будет отсортирован, отсортированные данные могут быть выданы очень быстро.

Обратите внимание, что время запуска LIMIT 23283.24 в точности равно времени запуска рода.Это не потому, что LIMIT сам по себе имеет большое время запуска.На самом деле у него нулевое время запуска, но EXPLAIN суммирует все дочерние расходы для каждого родителя, поэтому LIMIT время запуска включает в себя сумму времени запуска его дочерних элементов.

Такое объединение затрат может затруднить понимание стоимости выполнения каждого отдельного компонента.Например, наш LIMIT имеет нулевое время запуска, но это не очевидно на первый взгляд.По этой причине несколько других людей, связанных с объяснение.depesz.com, инструмент, созданный Хубертом Любачевским (он жедепес), который помогает понять EXPLAIN среди прочего, путем вычитания дочерних расходов из родительских затрат.Он упоминает некоторые другие сложности в короткая запись в блоге о своем инструменте.

Он выполняется от самого отступа к наименьшему, и я полагаю, от нижней части плана к вершине.(Таким образом, если есть два раздела с отступом, первым выполняется тот, который находится дальше по странице, затем, когда они встречаются, выполняется другой, а затем выполняется объединяющее их правило.)

Идея состоит в том, что на каждом этапе поступает 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, затем сортирует этот набор данных с помощью быстрой сортировки (используемая сортировка изменится, если данные не помещаются в ОЗУ), а затем откладывает его.

Далее он сканирует orditematt_attributeid_idx чтобы найти нужные строки orderitemattribute а затем сортирует этот набор данных с помощью быстрой сортировки.

Затем он берет два набора данных и объединяет их.(Соединение слиянием — это своего рода операция «сжатия», при которой два отсортированных набора данных обрабатываются параллельно, выдавая объединенную строку, когда они совпадают.)

Как я уже сказал, вы прорабатываете план от внутренней части к внешней части, снизу вверх.

Также доступен онлайн-помощник, Депеш, который покажет, где находятся дорогостоящие части результатов анализа.

тоже есть такой, вот те же результаты, что мне проясняет, в чем проблема.

ПгАдмин покажет вам графическое представление плана объяснения.Переключение между ними действительно может помочь вам понять, что означает текстовое представление.Однако, если вы просто хотите знать, что он собирается делать, вы можете всегда использовать графический интерфейс.

Официальная документация PostgreSQL предоставляет интересное и подробное объяснение того, как понимать вывод объяснения.

Если вы установите pgadmin, появится кнопка «Объяснение», которая не только предоставляет текстовый вывод, но и рисует диаграммы происходящего, показывая фильтры, сортировки и слияния подмножеств, которые я считаю действительно полезными для просмотра того, что происходит.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top