我试图找出使用非 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)。这意味着如果我需要一些其他对与数据交互感兴趣的外部服务,我可以将其直接插入数据库,绕过应用程序层。
- 在模型级别上实现这一点似乎执行起来要简单得多
- 支持应用程序代码变体似乎也更容易,因为要记住的概念更少
这两种方法的其他优点和缺点是什么?(例如性能、可维护性)