Я потратил более часа сегодня, озадачивая себя планом запросов, который я не мог понять. Запрос был UDPATE
, и он просто не запускался AT ALL. Полностью зашел в тупик: pg_locks
показал, что ничего не ждет. Теперь я не считаю себя лучшим или худшим человеком для чтения плана запросов, но я считаю, что это исключительно сложно. Мне интересно, как это читать? Существует ли методология, согласно которой Pg-асы следуют, чтобы точно определить ошибку?
Я планирую задать еще один вопрос о том, как обойти эту проблему, но прямо сейчас я говорю конкретно о о том, как читать эти типы планов. Пожалуйста, не указывайте на какой-либо общий учебник, если он специально не устраняет эту проблему, выделенную ниже плана запроса.
QUERY PLAN
--------------------------------------------------------------------------------------------
Nested Loop Anti Join (cost=47680.88..169413.12 rows=1 width=77)
Join Filter: ((co.fkey_style = v.chrome_styleid) AND (co.name = o.name))
-> Nested Loop (cost=5301.58..31738.10 rows=1 width=81)
-> Hash Join (cost=5301.58..29722.32 rows=229 width=40)
Hash Cond: ((io.lot_id = iv.lot_id) AND ((io.vin)::text = (iv.vin)::text))
-> Seq Scan on options io (cost=0.00..20223.32 rows=23004 width=36)
Filter: (name IS NULL)
-> Hash (cost=4547.33..4547.33 rows=36150 width=24)
-> Seq Scan on vehicles iv (cost=0.00..4547.33 rows=36150 width=24)
Filter: (date_sold IS NULL)
-> Index Scan using options_pkey on options co (cost=0.00..8.79 rows=1 width=49)
Index Cond: ((co.fkey_style = iv.chrome_styleid) AND (co.code = io.code))
-> Hash Join (cost=42379.30..137424.09 rows=16729 width=26)
Hash Cond: ((v.lot_id = o.lot_id) AND ((v.vin)::text = (o.vin)::text))
-> Seq Scan on vehicles v (cost=0.00..4547.33 rows=65233 width=24)
-> Hash (cost=20223.32..20223.32 rows=931332 width=44)
-> Seq Scan on options o (cost=0.00..20223.32 rows=931332 width=44)
(17 rows)
Проблема с этим планом запроса - я считаю, что я понимаю - лучше всего сказать RhodiumToad
(он определенно лучше в этом, поэтому я ставлю на его объяснение лучше) irc://irc.freenode.net/#postgresql
:
ой, этот план потенциально опасен проблема с этим планом заключается в том, что он запускает чрезвычайно дорогое hashjoin для каждой строки проблема заключается в оценке строк = 1 от другого объединения и планировщик думает, что это нормально, чтобы поставить очень дорогостоящий запрос во внутреннем пути nestloop, где, по оценкам, внешний путь возвращает только одну строку. так как, очевидно, по оценке планировщика дорогостоящая часть будет выполняться только один раз но у этого есть очевидная тенденция действительно испортиться на практике проблема заключается в том, что планировщик считает свои собственные оценки в идеале планировщик должен знать разницу между "оценкой, чтобы возвратить 1 строку" и "невозможно вернуть более 1 строки", но это совсем не ясно, как включить это в существующий код
Далее он говорит:
это может повлиять на любое соединение, но обычно объединение с подзапросами является наиболее вероятным
Теперь, когда я прочитал этот план, первое, что я заметил, это Nested Loop Anti Join
, это стоило 169,413
(я буду придерживаться верхних границ). Эта Anti-Join распадается на результат Nested Loop
по цене 31,738
и результат Hash Join
по цене 137,424
. Теперь 137,424
намного больше, чем 31,738
, поэтому я знал, что проблема связана с Hash Join. Затем переходим к EXPLAIN ANALYZE
сегменту Hash Join вне запроса. Это выполнено за 7 секунд. Я убедился, что есть индексы (lot_id, vin) и (co.code, и v.code) - было. Я отключил seq_scan
и hashjoin
индивидуально и заметьте увеличение скорости менее 2 секунд. Не достаточно близко, чтобы объяснить, почему он не прогрессирует через час.
Но, после всего этого, я совершенно неправ! Да, это была медленная часть запроса, но из-за бит rows="1"
(я предполагаю, что он был на Nested Loop Anti Join
). Есть ли урок, который поможет мне идентифицировать эти типы проблем. Здесь ошибка (отсутствие способности) в планировщике неверно оценивает количество строк? Как я должен читать это, чтобы прийти к такому же выводу RhodiumToad
did?
Это просто rows="1"
, который должен заставить меня понять это?
Я запускал VACUUM FULL ANALYZE
для всех задействованных таблиц, и это Postgresql 8.4.