用于PostgreSQL编写操作的CTE并行查询

用于PostgreSQL编写操作的CTE并行查询,postgresql,postgresql-9.6,postgresql-parallel-query,Postgresql,Postgresql 9.6,Postgresql Parallel Query,发件人: 只有通过顺序扫描访问驱动表的严格只读查询才能并行化 我的问题是:如果CTE(WITH子句)只包含读取操作,但其结果用于为写入操作(如insert或update)提供数据,是否也不允许并行顺序扫描 我的意思是,由于CTE很像一个临时表,它只存在于当前执行的查询中,我可以假设它的内部查询可以利用PostgreSQL 9.6全新的并行序列扫描吗?或者,它被视为使用子查询,无法执行并行扫描 例如,考虑这个查询: WITH foobarbaz AS ( SELECT foo FROM bar

发件人:

只有通过顺序扫描访问驱动表的严格只读查询才能并行化

我的问题是:如果CTE(
WITH
子句)只包含读取操作,但其结果用于为写入操作(如insert或update)提供数据,是否也不允许并行顺序扫描

我的意思是,由于CTE很像一个临时表,它只存在于当前执行的查询中,我可以假设它的内部查询可以利用PostgreSQL 9.6全新的并行序列扫描吗?或者,它被视为使用子查询,无法执行并行扫描

例如,考虑这个查询:

WITH foobarbaz AS (
  SELECT foo FROM bar
  WHERE some_expensive_function(baz)
)
DELETE FROM bar
USING foobarbaz
WHERE bar.foo = foobarbaz.foo
;
foobarbaz计算是预期能够并行化,还是因为删除语句而不允许

如果不允许,我认为可以用CREATE TEMPORATE TABLE语句替换CTE。但我想我会陷入同样的问题,因为createtable是一个写操作。我错了吗

最后,我可以尝试的最后一个机会是将其作为纯读取操作执行,并将其结果用作插入和/或更新操作的输入。在事务之外,它应该可以工作。但问题是:如果读取操作和插入/更新介于
begin
commit
语句之间,那么无论如何都不允许这样做?我知道它们是两个完全不同的操作,但在同一个事务和Postgres中

需要明确的是,我担心的是,我有大量难以阅读和难以重新设计的SQL查询,这些查询涉及多个顺序扫描和低性能函数调用,并且在两个表上执行复杂的更改。整个流程在一个事务中运行,因为如果不是这样,故障情况下的混乱将完全无法恢复

我的希望是能够并行化一些顺序扫描,以利用机器的8个cpu内核,更快地完成该过程

请不要回答我需要完全重新设计这个烂摊子:我知道,我正在努力。但这是一个伟大的项目,我们需要同时继续努力

不管怎样,任何建议都是值得感激的

编辑:

我添加了一份简短的报告,介绍到目前为止我所能发现的情况:

  • 正如@a_horse_with_no_name在他的评论中所说的(谢谢),CTE和查询的其余部分是一个DML语句,如果它有一个写操作,即使在CTE之外,CTE也无法并行化(我也测试了它)

  • 此外,我发现这比我在发行说明链接中发现的关于并行扫描的信息更简洁

  • 多亏了这个wiki页面,我可以检查一个有趣的地方,那就是我需要将涉及的函数声明为并行安全的。我做到了,并且(在一个没有文字的测试中)工作了

  • 另一个有趣的观点是@a_horse_with_no_name在他的第二条评论中所说的:使用DbLink执行纯只读查询。但是,调查一下,我发现,维基中明确提到,这是不支持并行扫描的

    • 另一方面,即使它能起作用,我最终还是从交易之外获取数据,在某些情况下,这对我来说是可以接受的,但我认为,这不如一般解决方案好
  • 最后,我检查了是否可以在事务内部的只读查询中执行并行扫描,即使它以后执行写入操作(没有触发异常,我可以提交)

…总之,我认为我的最佳选择(如果不是唯一的选择)是重构脚本,使其在同一事务中执行写入操作之前将数据读取到内存中


它会增加I/O开销,但是,考虑到我管理的延迟,它会更好。

“我可以假设它的内部查询可以利用全新的并行顺序扫描吗”不,你不能。该语句被视为DML,不是并行执行的候选语句。不要忘记9.6中对并行查询的支持是第一个实现,仍然有很多限制。解决这个问题的一种方法可能是通过数据库链接(到同一服务器)运行
select
,然后将其视为纯只读查询。