在应用程序代码上使用 Postgres 的外部程序语言 [关闭]

Posted

技术标签:

【中文标题】在应用程序代码上使用 Postgres 的外部程序语言 [关闭]【英文标题】:Using Postgres' external procedural languages over application code [closed] 【发布时间】:2021-05-27 08:57:50 【问题描述】:

我正在尝试找出使用非 plpgsql 过程语言(PL/Python、PL/Perl、PL/v8 等)在数据库级别实现数据操作逻辑而不是向上的优缺点与数据库(Rails、Entity Framework、Django 等)交互并在那里实现的应用程序框架的模型级别/ORM。

举一个具体的例子,比如说,我有一个包含Mustache 模板的表,我想以某种方式“渲染”它们。 表定义:

create table templates (
  id serial primary key,
  content text not null,
  data jsonb not null
);

通常我会使用模型代码并添加额外的方法来呈现模板。 Rails 中的示例:

class Template < ApplicationRecord
  def rendered
    Mustache.render(content, data)
  end
end

但是,我也可以编写一个 PL/Python 函数,它可以做到这一点,但在数据库级别:

create or replace function fn_mustache(template text, data jsonb)
returns text 
language plpython3u
as $$
  import chevron
  import json
  return chevron.render(template, json.loads(data))
$$;

create view v_templates as 
  select id, content, data, fn_mustache(content, data) as rendered
    from templates;

这在功能方面产生了几乎相同的结果。这个例子是非常基本的,但想法是使用 PL/Python(或其他)以比 PL/pgsql 允许的更高级的方式操作数据。也就是说,PL/pgsql 没有今天任何通用编程语言提供的相同数量的库(在示例中,我依赖于 Mustache 模板系统的实现,在这种情况下在 PL/pgsql 中实现是不切实际的)。我显然不会将 PL/Python 用于任何类型的网络或其他操作系统级别的功能,但对于专门针对数据的操作,这似乎是一种不错的方法(改变我的想法)。

目前我能观察到的几点:

PL/Python 是一种“不受信任”的语言,我猜从定义上讲,编写函数会更加危险,因为您可以访问系统调用;至少感觉搞砸一个 PL/Python 函数的成本比在应用层出错的成本要高,因为前者是在数据库的上下文中执行的 数据库方法更具可扩展性,因为我正在处理最接近数据的级别,即我不会将表示逻辑分散到多个“层”(在本例中为 ORM 和 DB)。这意味着,如果我需要其他对与数据交互感兴趣的外部服务,我可以将其直接插入数据库,绕过应用层。 在模型级别实现这一点似乎执行起来要简单得多 支持应用程序代码变体似乎也更容易,因为需要记住的概念更少

这两种方法的其他优点和缺点是什么? (例如性能、可维护性)

【问题讨论】:

【参考方案1】:

您想知道数据库中是否有应用程序逻辑。这在很大程度上是一个品味问题。在过去,在数据库函数中实现应用程序逻辑的方法比较流行,但现在它通常不受欢迎。

这场辩论中的极端立场是

应用程序在数据库中实现,数据库函数生成发送给客户端的 html 代码。

数据库只是一个愚蠢的表集合,除了主键之外没有触发器或约束,应用程序试图保持数据完整性。

最好的解决方案通常在中间的某个地方,但在很大程度上取决于口味。您会看到这是一个典型的基于意见的问题。不过,让我提供一些论据来帮助您做出决定。

针对数据库中的应用程序逻辑的观点:

这使得移植到另一个数据库变得更加困难。

开发和调试数据库功能比客户端代码更复杂。例如,您不会拥有高级调试工具。

该数据库机器不仅必须执行正常的数据库工作负载,还必须执行应用程序代码工作负载。但是数据库比应用程序服务器更难扩展(您不能只启动第二个数据库来处理部分工作负载)。

特定于 PostgreSQL:所有数据库函数都在单个数据库事务中运行,因此您无法实现需要更复杂事务管理的功能。

关于数据库中应用程序逻辑的要点:

移植到另一种应用服务器或客户端编程语言变得更加容易。

在客户端和服务器之间传输的数据更少,这可以提高处理效率。

软件堆栈变得更短,整体软件架构更简单。

我个人的看法是,任何与基本数据完整性有关的事情都应该在数据库中实现:

在数据库中有外键并检查约束。应用程序当然也会遵守这些规则(触发数据库错误没有意义),但有一个安全网对数据完整性有好处。

如果您必须在数据库中保留冗余信息,请使用触发器确保数据的所有副本保持同步。这隐含地利用了事务原子性。

任何更复杂的事情最好在应用程序中完成。警惕那些很长或很复杂的数据库函数。出于性能原因可能会出现例外情况:也许一些复杂的报告无法用纯 SQL 轻松编写,并且将所有原始数据发送到客户端的成本非常高。

【讨论】:

以上是关于在应用程序代码上使用 Postgres 的外部程序语言 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

无法在Postgres中实例化外部Hive Metastore /在类路径中找不到驱动程序

使用 postgres_fdw 创建外部表时翻译主机名时出错

如何在超过 12 的 postgres 版本上自动生成 Oid

如何将 Docker 内部的 Spring Boot 应用程序连接到 PostgreSQL 外部

Postgresql 外部表插件postgres_fdw的安装和使用

带有 Redshift 的 Postgres 外部模式:我可以使用外部数据包装器吗?