这个self-join可以进一步优化吗?

Can this self-join be optimized further?

我正在尝试了解是否可以优化包含自联接的查询,如果可以的话 - 如何优化。

我正在处理一个更大的现实生活任务,但在这里我从中提取了一个简单的子任务以专注于一个特定问题:优化自连接查询。

我有一个叫 parties 的 table。它包含超过 85k 条记录,如下所示:

# \d test.parties
                  Table "test.parties"
   Column    | Type | Collation | Nullable | Default
-------------+------+-----------+----------+---------
 id          | uuid |           |          |
 contract_id | uuid |           |          |

contract_id 上进行自我加入 我得到了这个计划:

# explain analyse select p1.id from test.parties p1 join test.parties p2 on p1.contract_id = p2.contract_id;
                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
 Merge Join  (cost=20207.87..628157.87 rows=40500000 width=16) (actual time=109.709..184.523 rows=197632 loops=1)
   Merge Cond: (p1.contract_id = p2.contract_id)
   ->  Sort  (cost=11181.94..11406.94 rows=90000 width=32) (actual time=55.560..66.173 rows=86332 loops=1)
         Sort Key: p1.contract_id
         Sort Method: external merge  Disk: 3560kB
         ->  Seq Scan on parties p1  (cost=0.00..1620.00 rows=90000 width=32) (actual time=0.018..14.518 rows=86332 loops=1)
   ->  Sort  (cost=9025.94..9250.94 rows=90000 width=16) (actual time=54.135..74.973 rows=197631 loops=1)
         Sort Key: p2.contract_id
         Sort Method: external sort  Disk: 2544kB
         ->  Seq Scan on parties p2  (cost=0.00..1620.00 rows=90000 width=16) (actual time=0.009..10.462 rows=86332 loops=1)
 Planning Time: 0.167 ms
 Execution Time: 199.677 ms
(12 rows)

contract_id 上添加索引 我得到这个计划:

# create index on test.parties(contract_id);
CREATE INDEX
# explain analyse select p1.id from test.parties p1 join test.parties p2 on p1.contract_id = p2.contract_id;
                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=3084.47..10570.76 rows=192484 width=16) (actual time=32.457..97.662 rows=197632 loops=1)
   Hash Cond: (p1.contract_id = p2.contract_id)
   ->  Seq Scan on parties p1  (cost=0.00..1583.32 rows=86332 width=32) (actual time=0.013..11.293 rows=86332 loops=1)
   ->  Hash  (cost=1583.32..1583.32 rows=86332 width=16) (actual time=32.133..32.133 rows=86332 loops=1)
         Buckets: 131072  Batches: 2  Memory Usage: 3048kB
         ->  Seq Scan on parties p2  (cost=0.00..1583.32 rows=86332 width=16) (actual time=0.007..12.815 rows=86332 loops=1)
 Planning Time: 0.444 ms
 Execution Time: 110.692 ms
(8 rows)

有什么办法可以摆脱那些 Seq Scan 吗?

我在你的解释计划中没有看到任何索引的存在,所以指定你没有尚未研究使用索引,这是一个建议:

CREATE INDEX idx ON parties (contract_id, id);

这应该会加快连接速度,它还涵​​盖 id 值,这在 SELECT 子句中是必需的。