【问题标题】:Can this self-join be optimized further?这种自加入可以进一步优化吗?
【发布时间】:2019-08-22 03:26:38
【问题描述】:

我正在尝试了解是否可以优化包含自联接的查询,以及是否可以 - 怎么做。

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

我有一张名为parties 的表。它包含超过 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 Scans?

【问题讨论】:

  • 请在代码问题中给出minimal reproducible example--剪切&粘贴&可运行代码;具有期望和实际输出的示例输入(包括逐字错误消息);标签和版本;明确的规范和解释。对于包含 DBMS/产品和 DDL 的 SQL,其中包括约束和索引以及表格格式的基表初始化。对于包括 EXPLAIN 结果和统计信息的 SQL 性能。 (约束、索引和计划对性能至关重要。)

标签: postgresql query-optimization self-join


【解决方案1】:

我在您的解释计划中看不到任何索引的存在,因此请指定您尚未考虑使用索引,这里有一个建议:

CREATE INDEX idx ON parties (contract_id, id);

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多