Часть, которую я всегда находил непонятной, - это стоимость запуска против общей стоимости. Я Google это каждый раз, когда я забываю об этом, что возвращает меня сюда, что не объясняет разницу, поэтому я пишу этот ответ. Это то, что я почерпнул из документации Postgres 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:
(Когда вы используете 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;
в Postgres 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)
И графически:
Еще раз, последовательное сканирование на post
не требует затрат при запуске: оно сразу начинает выводить строки. Но такая сортировка требует значительных затрат на запуск 23283.24
, поскольку ей необходимо отсортировать всю таблицу, прежде чем она сможет вывести хотя бы одну строку . Общая стоимость сортировки 23859.27
лишь немного выше стоимости запуска, что отражает тот факт, что после сортировки всего набора данных отсортированные данные могут быть отправлены очень быстро.
Обратите внимание, что время запуска LIMIT
23283.24
точно равно времени запуска сортировки. Это не потому, что само по себе LIMIT
имеет большое время запуска. Фактически он сам по себе имеет нулевое время запуска, но EXPLAIN
сворачивает все дочерние затраты для каждого родителя, поэтому время запуска LIMIT
включает сумму времени запуска его дочерних элементов.
Такое накопление затрат может затруднить понимание стоимости выполнения каждого отдельного компонента. Например, у нашего LIMIT
нулевое время запуска, но это не очевидно с первого взгляда. По этой причине несколько других людей связались с объяснить.depesz.com , инструментом, созданным Юбертом Любачевским (он же depesz), который помогает понять EXPLAIN
, среди прочего - путем вычитания дочерних расходов из родительских расходов , Он упоминает о некоторых других сложностях в коротком блоге о своем инструменте.