【问题标题】:Why does a lateral joins with LIMIT increase execution time?为什么带有 LIMIT 的横向连接会增加执行时间?
【发布时间】:2019-06-17 15:06:51
【问题描述】:

当我运行带有横向连接和内部LIMIT 的查询时,它使用嵌套循环连接。但是当我删除LIMIT 时,它使用哈希右连接。为什么?

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)

【问题讨论】:

    标签: sql postgresql query-performance lateral-join


    【解决方案1】:

    优化器足够聪明,可以将您的第一个查询重写为

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

    但是LIMIT 子句无法进行这种优化,因此只能使用嵌套循环连接。

    【讨论】:

    • 我能做点什么吗,我真的需要对里面的查询进行限制和排序。
    • 我不认为你能做得比这更好。
    【解决方案2】:

    根据@LaurenzAlbe 的回答,我认为如果您显示完整的查询,我们可以提供更多帮助,因此我们知道您为什么需要 LATERAL 联接。对于您到目前为止提到的(简化的)要求,我认为等效的是

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

    此外,由于您仅输出来自 proxy 的列,因此您实际上只执行了一次 INNER JOIN,但需要更多的计算工作。

    【讨论】:

      猜你喜欢
      • 2020-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-29
      • 1970-01-01
      • 2016-09-22
      相关资源
      最近更新 更多