0

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

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

4

1 回答 1

1

You are wondering whether to have application logic inside the database or not. This is to a great extent a matter of taste. In the days of yore, the approach to implement application logic in database functions was more popular, but today it is usually frowned upon.

Extreme positions in this debate are

  • The application is implemented in the database to the extent that the database functions produce the HTML code that is sent to the client.

  • The database is just a dumb collection of tables with no triggers or constraints beyond a primary key, and the application tries to maintain data integrity.

The best solution is typically somewhere in the middle, but where is largely a matter of taste. You see that this is a typical opinion-based question. However, let me supply some arguments that help you make a decision.

Points speaking against application logic in the database:

  • It makes it more difficult to port to another database.

  • It is more complicated to develop and debug database functions than client code. For example, you won't have as advanced debugging tools.

  • That database machine has to perform not only the normal database workload, but also the application code workload. But databases are harder to scale than application servers (you can't just spin up a second database to handle part of the workload).

  • PostgreSQL-specific: all database functions run inside a single database transaction, so you cannot implement functionality that requires more complicated transaction management.

Points speaking for application logic in the database:

  • It becomes easier to port to another application server or client programming language.

  • Less data has to be transferred between client and server, which can make processing more efficient.

  • The software stack becomes shorter and the overall software architecture simpler.

My personal opinion is that anything that has to do with basic data integrity should be implemented in the database:

  • Have foreign keys and check constraints in the database. The application will of course also respect these rules (no point in triggering a database error), but it is good for data integrity to have a safety net.

  • If you have to keep redundant information in the database, use triggers to make sure that all copies of a datum are kept synchronized. This implicitly makes use of transactional atomicity.

  • Anything that is more complicated is best done in the application. Be wary of database functions that are very long or complicated. Exceptions can be made for performance reasons: perhaps some complicated report could not easily be written in pure SQL, and shipping all the raw data to the client is prohibitively expensive.

于 2021-02-25T03:12:53.110 回答