Почему боковые соединения с LIMIT увеличивают время выполнения? - PullRequest
0 голосов
/ 24 января 2019

когда я запускаю запрос с боковым соединением и LIMIT внутри, он использует вложенное соединение цикла. Но когда я удаляю LIMIT, он использует Hash Right Join. Зачем?

EXPLAIN ANALYSE
SELECT proxy.*
FROM jobs
LEFT  OUTER JOIN LATERAL (
        SELECT proxy.*
        FROM proxy
        WHERE jobs.id = proxy.job_id
) proxy ON true

Hash Right Join  (cost=2075.47..3029.05 rows=34688 width=12) (actual time=9.951..24.758 rows=35212 loops=1)
Hash Cond: (proxy.job_id = jobs.id)
  ->  Seq Scan on proxy  (cost=0.00..524.15 rows=34015 width=12) (actual time=0.011..2.502 rows=34028 loops=1)
  ->  Hash  (cost=1641.87..1641.87 rows=34688 width=4) (actual time=9.842..9.842 rows=34689 loops=1)
        Buckets: 65536  Batches: 1  Memory Usage: 1732kB
        ->  Index Only Scan using jobs_pkey on jobs  (cost=0.29..1641.87 rows=34688 width=4) (actual time=0.010..4.904 rows=34689 loops=1)
              Heap Fetches: 921

Но когда я добавляю ограничения к запросу, фактическое время изменяется с 24 до 150:

EXPLAIN ANALYSE
SELECT proxy.*
FROM jobs
LEFT OUTER JOIN LATERAL (
        SELECT proxy.*
        FROM proxy
        WHERE jobs.id = proxy.job_id
        limit 1
) proxy ON true

Nested Loop Left Join  (cost=0.58..290506.19 rows=34688 width=12) (actual time=0.024..155.753 rows=34689 loops=1)
  ->  Index Only Scan using jobs_pkey on jobs  (cost=0.29..1641.87 rows=34688 width=4) (actual time=0.014..3.984 rows=34689 loops=1)
        Heap Fetches: 921
  ->  Limit  (cost=0.29..8.31 rows=1 width=12) (actual time=0.001..0.001 rows=1 loops=34689)
        ->  Index Scan using index_job_proxy_on_job_id on loc_job_source_materials  (cost=0.29..8.31 rows=1 width=12) (actual time=0.001..0.001 rows=1 loops=34689)
              Index Cond: (jobs.id = job_id)

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Исходя из ответа @ LaurenzAlbe, я думаю, что мы можем помочь больше, если вы покажете полный запрос, поэтому мы знаем, почему вам нужно ПОЛУЧАТЕЛЬНОЕ объединение.Для (упрощенных) требований, которые вы упомянули до сих пор, я думаю, что эквивалент равен

SELECT DISTINCT ON(proxy.id) proxy.*
FROM proxy
   RIGHT OUTER JOIN jobs
   ON jobs.id = proxy.job_id;

Кроме того, поскольку вы выводите столбцы только из proxy, вы фактически выполняете только INNER JOIN, но сбольше вычислительных усилий.

0 голосов
/ 24 января 2019

Оптимизатор достаточно умен, чтобы переписать ваш первый запрос на

SELECT proxy.*
FROM proxy
   RIGHT OUTER JOIN jobs
      ON jobs.id = proxy.job_id;

Но эту оптимизацию нельзя выполнить с помощью условия LIMIT, поэтому возможно только соединение с вложенным циклом.

...