Postgresql-自连接性能差

Postgresql-自连接性能差,postgresql,self-join,postgresql-12,Postgresql,Self Join,Postgresql 12,我的第一个问题,所以,请提前道歉 我的Postgresql(12.2)在Windows Server 2016上运行,在两个数字列上进行简单的自连接时,性能很差。表格本身(form_content)由27列和约23200000行组成。该表存储用户使用表单的响应。每个表单将生成多行,并且有一个重要的层次结构,例如第5行可能是第6-10行(可能与特定问题的回答相关)的“父级”(与表单上的某个部分相关)。我对如何在这个表中存储数据有些限制。每行有一个“事件id”和一个“父事件id”。在上面的示例中,第

我的第一个问题,所以,请提前道歉

我的Postgresql(12.2)在Windows Server 2016上运行,在两个数字列上进行简单的自连接时,性能很差。表格本身(form_content)由27列和约23200000行组成。该表存储用户使用表单的响应。每个表单将生成多行,并且有一个重要的层次结构,例如第5行可能是第6-10行(可能与特定问题的回答相关)的“父级”(与表单上的某个部分相关)。我对如何在这个表中存储数据有些限制。每行有一个“事件id”和一个“父事件id”。在上面的示例中,第5行的“事件id”将是第6-10行的“父事件id”

因此,为了提取响应,我正在运行以下查询(出于本Q的目的,我只在select语句中包含一些列:

select
   fc.event_id,
   fc1.result_val
from
   form_content fc
join
   form_content fc1
on
   fc.event_id = fc1.parent_event_id
where
   fc.performed_dt_tm >= '2020-06-01'::timestamp
上面的查询运行需要2-3分钟,大约有300000行执行的\u dt\u tm>=2020-06-01。我已经为事件id和父事件id列(以及:(事件id,父事件id)和(父事件id,事件id)建立了索引)。我已对上述查询运行了“解释分析”,似乎没有使用表索引:

QUERY PLAN                                                                                                                                                                                       |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
Gather  (cost=1485180.36..2252551.11 rows=933343 width=16) (actual time=222023.060..224259.345 rows=415750 loops=1)                                                                              |
  Workers Planned: 2                                                                                                                                                                             |
  Workers Launched: 2                                                                                                                                                                            |
  ->  Parallel Hash Join  (cost=1484180.36..2158216.81 rows=388893 width=16) (actual time=221939.001..223549.551 rows=138583 loops=3)                                                            |
        Hash Cond: (fc1.parent_event_id = fc.event_id)                                                                                                                                           |
        ->  Parallel Index Only Scan using idx_pf_rfg_content_parenteventid on form_content fc1  (cost=0.56..559818.60 rows=9697340 width=8) (actual time=19.702..34247.142 rows=7761647 loops=3)|
              Heap Fetches: 99129                                                                                                                                                                |
        ->  Parallel Hash  (cost=1482201.74..1482201.74 rows=120564 width=8) (actual time=174513.622..174513.624 rows=98016 loops=3)                                                             |
              Buckets: 131072  Batches: 4  Memory Usage: 4544kB                                                                                                                                  |
              ->  Parallel Seq Scan on form_content fc  (cost=0.00..1482201.74 rows=120564 width=8) (actual time=8.798..174288.343 rows=98016 loops=3)                                           |
                    Filter: (performed_dt_tm >= '2020-06-01 00:00:00'::timestamp without time zone)                                                                                              |
                    Rows Removed by Filter: 7663631                                                                                                                                              |
Planning Time: 27.449 ms                                                                                                                                                                         |
Execution Time: 224663.439 ms 
我对Postgresql比较陌生,在MSSQL上运行类似查询时,性能要好得多


非常感谢!

对索引进行几十万次的命中并不是免费的。散列连接实际上可能比这更快

这里最慢的一步是根据时间戳获取行。也许在
(peformed\u dt\u tm)
上建立索引会有所帮助。更好的是,要获得仅索引的扫描,请在
(已执行的\u dt\u tm,事件id)
上尝试一次

此外,您还应该对表进行真空分析。它的真空度不明显(7761647行中的Heap Fetches:99129不明显不好,但可能更好),但很高兴知道在进行分析工作时它的真空度确实很好,因为它又删除了一个未知变量


知道它在MSSQL中更快对我们没有帮助,除非您可以向我们展示在那里使用的计划。

将索引命中几十万次并不是免费的。哈希连接实际上可能比这更快

这里最慢的一步是根据时间戳获取行。也许在
(peformed\u dt\u tm)
上建立索引会有所帮助。更好的是,要获得仅索引的扫描,请在
(已执行的\u dt\u tm,事件id)
上尝试一次

此外,您还应该对表进行真空分析。它的真空度不明显(7761647行中的Heap Fetches:99129不明显不好,但可能更好),但很高兴知道在进行分析工作时它的真空度确实很好,因为它又删除了一个未知变量


知道它在MSSQL中更快对我们没有帮助,除非您可以向我们展示在那里使用的计划。

您是否有
(事件id,父事件id)
的索引?是的,我有(解释分析输出或查询性能没有变化)。感谢您的回答-我将编辑初始问题以反映!您如何处理400K行结果集?您是否执行与SQL Server中相同的操作?您是指日期>=6月1日的300K行吗?如果是这样,我将按照实践中的方式包括日期,我将运行此查询,并带有日期限制。我提到了要查询的行数e日期为6月1日或之后,以了解自联接的大小。请在代码问题中给出一个--包括剪切和粘贴&可运行的最小代码和作为代码给出的最小代表性数据。对于包含DBMS和DDL的SQL,包括约束、索引和表格初始化。对于包含解释结果和统计信息的SQL性能cs.请研究和总结。对于包含优化/性能基础知识的SQL,立即生成索引、计划、统计数据和可搜索性。在学习和应用这些基础知识后,要求重新优化。您是否在
(事件id、父事件id)
上有索引?是的(解释分析输出或查询性能没有变化)。感谢您的回答-我将编辑初始问题以反映!您如何处理400K行结果集?您是否执行与SQL Server中相同的操作?您是指日期>=6月1日的300K行吗?如果是这样,我将按照实践中的方式包括日期,我将运行此查询,并带有日期限制。我提到了要查询的行数e日期为6月1日或之后,以了解自联接的大小。请在代码问题中给出一个--包括剪切和粘贴&可运行的最小代码和作为代码给出的最小代表性数据。对于包含DBMS和DDL的SQL,包括约束、索引和表格初始化。对于包含解释结果和统计信息的SQL性能cs.请研究和总结。对于SQL,包括优化/性能的基础知识——立即导致索引、计划、统计和可搜索性。在学习和应用这些基础知识后,要求重新优化。