【问题标题】:Postgres fast table splittingPostgres 快速表拆分
【发布时间】:2015-03-11 22:12:35
【问题描述】:

我正在将 python 代码重写为 plpgsql,它对表进行切片并将表的切片导入回数据库到不同的表中。假设Func(..) 是一个返回一些INT 的函数 Condition(..., ...) 是一些条件表达式。

Python

  • copy_expert COPY (SELECT *, (Func(B)) FROM TABLE A ORDER BY (SELECT Func(B) FROM B WHERE Condition(A,B)) TO STDOUT 到文件
  • 通过写入不同的转储切片文件,在 python 中将结果表切片为 n 部分
  • 为每个切片获取一个新游标并运行 copy_expert COPY some_table FROM STDIN

PL/Pgsql

  • 运行类似的东西

        DECLARE
           ...
           part_name VARCHAR[] = ARRAY[{part_names}];
           prep_stmt VARCHAR[] = ARRAY[{parts}];
        BEGIN 
            FOR i in 1..{parts} LOOP
                prep_stmt[i] := $$ INSERT INTO $$ || part_name[i] || $$
                       ({list_cols}) VALUES ({args}); $$;
            END LOOP;
            FOR row IN (SELECT *, (Func(B)) FROM TABLE A ORDER BY      
                          (SELECT Func(B) FROM B WHERE Condition(A,B))
            LOOP
                chosen_part := 0;
                FOR i IN 1..{parts} LOOP
                    -- choose some part based on Func(B)
                    -- this takes negligible amount of time
                    ... 
                END LOOP;
    
                EXECUTE prep_stmt[part] USING row;
            END LOOP;
        END
    

Python 方法可以更快地执行此任务。我的意思是速度要快几个数量级,尽管客户端和数据库是不同的机器。桌子 有~16M 行,每行有5-7 列。

有没有办法使用 plpgsql 让它运行得更快?

上下文

然后,切片将保留在一台机器上,并使用不同的光标和每个处理器进行处理。切片的原因是进一步的处理是CPU 而不是IO 密集型,因为它与多边形交集一起使用,切片带来了显着的性能优势(至少对于非切片实现而言)

编辑

我真的更喜欢实际回答问题的答案,而不是提出该方法是错误的。有时糟糕的设计会阻止轻松改变方法,这可能就是这种情况。问题是为什么 python 方法更快以及如何使 plpgsql 方法更快。

编辑 2

是否可以说WRITE TO FILE ...而不是INSERT ...,然后最后批量加载?

编辑 3

我想重申,设置是我无法避免将切片创建为单独的表。

我不能为每个切片说 CREATE TABLE AS 的原因是因为 我正在根据FUNC(B) 的输出为A 中的每一行“平衡”切片。该方法试图模仿min-make-span 问题。在CREATE TABLE AS 内不可能做这样的事情。

可能的解决方案:

这是我偶然发现的可能是解决方案的列表,你知道其他人吗?

  • DBLINK 扩展以在单独的连接中插入每个切片?
  • 先写入未记录的临时表,然后导入切片

【问题讨论】:

  • 为什么要对表进行切片?一些上下文会给你更好的答案。
  • @JonClements 我想在之后并行处理每个切片
  • “并行”是什么意思?
  • @JonClements “并行”我的意思是对每个切片和不同的处理器使用不同的光标
  • 对不起 - 只是忍不住觉得这是一个 XY 问题...

标签: python postgresql plpgsql


【解决方案1】:

问题是为什么 python 方法更快以及如何使 plpgsql 方法更快。

这不是由于 Python,而是 COPYINSERT。使用COPY 进行批量加载比使用INSERT 快得多

除此之外,您给定的查询似乎没有意义:

SELECT *, (Func(B))
FROM TABLE A
ORDER BY (SELECT Func(B) FROM B WHERE Condition(A,B)

在多种情况下语法无效。基于此很难说什么。

只要你留在同一个数据库中,我的第一个想法就是CREATE TABLE AS

CREATE TABLE slice_n AS
SELECT col1, col2, ...
FROM   big_table
ORDER  BY whatever  -- cluster data while being at it
WHERE  whatever;

根据所提供的信息不能说更多。
Craig 整理了一份一般性建议清单:

【讨论】:

  • 如我之前在 cmets 中提到的,我知道 COPY 比 INSERT 快,因此特定的查询示例不相关。这是为了给实际发生的事情留下印象。是否有可能使插入更快?通过说切片是暂时未记录的还是其他一些技术?或者通过从 plpgsql 写入文件?
  • @iggy:未记录的表更快,但目前没有办法将未记录的表转换为常规表。 (Probably going to be in pg 9.5!) 您将不得不创建另一个表。 “写入文件”是指COPY。单独插入比一次插入所有行要慢得多。最快的方法是CREATE TABLE AS。我不明白为什么这是不可能的。我觉得是这样的。你可以CREATE TABLE AS SELECT * FROM myfunc()。但是每行运行一个函数(在表函数内部)会很昂贵。
  • 我正在使用func(B) 的输出来执行类似于en.wikipedia.org/wiki/Bin_packing_problem 的第一个适合规则。我想不出一种在CREATE TABLE AS 的限制范围内对这个逻辑进行编码的方法,我想我需要逐行处理,但是可以先插入文件然后加载。以及使用单独的DBLINK 写入每个表。
  • 在您发布多行插入的链接中似乎很有希望。但是插入的执行计划缓存在 plpgsql 中,我猜准备它们应该没有太大区别?
猜你喜欢
  • 2010-10-05
  • 2019-04-30
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2022-07-14
  • 2015-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多