微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在应用程序代码上使用 Postgres 的外部过程语言

如何解决在应用程序代码上使用 Postgres 的外部过程语言

我试图找出使用非 plpgsql 过程语言(PL/Python、PL/Perl、PL/v8 等)在数据库级别实现数据操作逻辑的优缺点,而不是使用与数据库(Rails、实体框架、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)。这意味着,如果我需要一些其他有兴趣与数据交互的外部服务,我可以将其直接插入数据库,绕过应用层。
  • 在模型级别实现这一点在执行过程中似乎要简单得多
  • 支持应用程序代码变体似乎也更容易,因为要记住的概念较少

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

解决方法

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

这场辩论中的极端立场是

  • 应用程序在数据库中实现,以致于数据库函数生成发送到客户端的 HTML 代码。

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

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

反对数据库中的应用逻辑的要点:

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

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

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

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

数据库中应用逻辑的要点:

  • 移植到其他应用服务器或客户端编程语言变得更加容易。

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

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

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

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

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

  • 任何更复杂的事情最好在应用程序中完成。警惕很长或很复杂的数据库函数。出于性能原因可以例外:也许一些复杂的报告不能轻易地用纯 SQL 编写,并且将所有原始数据传送到客户端的成本高得令人望而却步。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?