Postgres中用户定义的连接功能?
Posted
技术标签:
【中文标题】Postgres中用户定义的连接功能?【英文标题】:User-defined join function in Postgres? 【发布时间】:2020-02-04 16:09:13 【问题描述】:我有两个表 T1 和 T2,它们类似于 PostgreSQL 数据库中更宽的表 T 的垂直分区。
我想通过在每个表上使用表扫描操作来低成本地连接这些分区,类似于将行成对组合到新行的类似 MERGE-JOIN 的操作。我的方法会假设表可以按扫描顺序合并连接,而不需要排序或检查任何连接谓词。主要目标是避免使用一些行标识符进行显式连接,这些行标识符也需要复制到所有分区中,这似乎是 PG 中垂直分区的常见模式。
表 T1 和 T2 没有索引并且是严格只读的。因此,优化器将找不到以不同顺序访问它们的替代方法。并行查询被禁用以避免并行扫描操作。
[过时的 Q1) 鉴于这些预防措施,PG 中是否有任何保证始终按插入顺序返回行,例如吸尘后? ]
Q2) 是否可以编写一个实现类似 MERGE-JOIN 的操作的 UDF,即类似于:
SELECT T1.*, func('T2') FROM T1;
或
SELECT * FROM func('T1', 'T2');
似乎归结为为 PG 编写一个用户定义的连接运算符。
更多想法:我的理解是 PL/pgSQL 函数将结果累积在 RETURN NEXT 和 RETURN QUERY 中,如果 T 有很多行,这可能会很昂贵。不确定游标是否有类似的开销。所以我真的不知道从哪里开始寻找。
编辑: 问了两个问题,我犯了一个错误。请忽略第一个关于保证的内容。 - 我知道没有这样的保证,我只是好奇究竟是什么导致 PostgreSQL 出现问题,因为我不熟悉那个系统。
为了澄清用例:我打算将数据放入外部只读文件中,例如CSV,可通过外部表访问,我可以完全控制扫描顺序。将其视为一些数据存档。
问:是否可以在 PostgreSQL 中编写一个用户定义的函数来处理一个游标(示例 1)或两个游标(示例 2)以及由服务器端的两次顺序扫描发出的“拼接”行?
【问题讨论】:
如果您使用内置的声明性分区,Postgres 12 会自动为您执行此操作(“partition wise join”) "在 PG 中是否有任何保证,行总是按插入顺序返回" - 一个明确的 NO(不仅适用于 Postgres,但对于所有关系数据库)。保证结果顺序的唯一方法是使用ORDER BY
,别无选择。
感谢指向分区连接的指针。但据我了解,这都是关于水平分区的,例如按范围?
【参考方案1】:
这行不通。 SQL 语句结果的顺序是可变的,没有ORDER BY
:
每个UPDATE
都会改变表格行的物理位置。
不能保证INSERT
出现在表的末尾。
即使没有更改,顺序扫描也不会总是从头开始。
你可以让它工作的唯一方法是,如果你以正确的顺序将数据填充到一个空表中,永远不要再修改表并将synchronous_seqscan
设置为off
,但我想这不是什么你想做。
我认为您的想法是过早的优化,您应该创建一个外键并按照 Codd 想要的方式加入。或者,如果您的主要问题是列太多,也许您可以将不太重要的属性集中到一个 jsonb
列中,如果它变得太大,PostgreSQL 可以将其存储在 TOAST 表中。
【讨论】:
"你可以让它工作的唯一方法是如果你以正确的顺序将数据填充到一个空表中,永远不要再修改表并将 synchronous_seqscan 设置为关闭,但我想这是不是你想做的。” - 正如问题所述,这正是我想要的。假设我了解所涉及的风险,有没有办法做到这一点? 无法在数据库中以这种方式“加入”这些表。您可以在应用程序的不同线程中建立两个并发数据库会话,在两者中运行SELECT * FROM ...
,并在应用程序中按照它们到达的顺序将这些行拼接在一起。我认为这是一个脆弱的架构。以上是关于Postgres中用户定义的连接功能?的主要内容,如果未能解决你的问题,请参考以下文章
Docker Compose 无法从数据库 (jdbc:postgresql://db:5432/postgres) 为用户“postgres”获取连接:连接尝试失败