0

在工作中,我们目前有一个 PostgreSQL 数据库,我们通过一些 Perl 绑定来访问它,以访问数据库并编组对 Perl 类型的响应。这可以正常工作,但由于各种原因,我们对 Perl 越来越不满意。我们一直在考虑的一种选择是将这个 API 中的大部分工作作为plpgsql存储过程转移到数据库本身。

简要示例

例如,我们可能在数据库中有以下内容:

-- This matches our 'Entity::Artist' object
CREATE TYPE loaded_artist (
  artist_id uuid,
  revision_id integer,
  artist_tree_id integer,
  name text,
  sort_name text,
  artist_type_id integer,
  -- etc
);

-- This gets the latest 'master' version of an artist and joins in basic data
-- from the artist tree
CREATE FUNCTION get_latest_artist_by_mbid(in_mbid UUID)
RETURNS SETOF loaded_artist AS $$
  BEGIN
    RETURN QUERY
    SELECT
      artist_id, revision_id, artist_tree_id, name.name,
      sort_name.name AS sort_name, artist_type_id
    FROM artist
    JOIN artist_revision USING (artist_id)
    JOIN artist_tree USING (artist_tree_id)
    JOIN artist_data USING (artist_data_id)
    WHERE artist.master_revision_id = revision_id
      AND artist_id = in_mbid;
  END;
$$ LANGUAGE 'plpgsql';

现在我们当前的 Perl API 可以有效地简化为以下内容:# 而在 Perl

package Data::Artist;
sub get_latest_by_mbid {
    my ($self, $mbid) = @_;
    return $self->new_from_row(
        $self->sql->select_single_row_hash(
            'SELECT * FROM get_latest_artist_by_mbid(?)',
            $mbid));
}

这是明智的吗?

从表面上看,我喜欢这个。我们:

  • 远离 Perl,但不要承诺使用另一种语言。这意味着我们可以将我们的实际应用程序迁移到 Python/任何未来,并且我们的大部分 API 已经完成。
  • 由于指定了类似的东西,从 PostgreSQL 获得额外的类型安全性RETURNS SETOF loaded_artist
  • 仍然通过 PGTAP 进行单元测试和东西。

有几个缺点:

  • 由于我们现在必须替换数据库中的功能,因此可能会降低开发周期。不是世界末日,但这有效地在我们的工作流程中引入了以前不存在的“编译”步骤。
  • 可能更困难的版本控制,但肯定有办法做到这一点

有没有人做过这样的工作?你会鼓励它,还是充满危险?


脚注:更多关于我们的案例

这是一个开源网站。我们分发我们数据库的转储,供人们导入 PostgreSQL 数据库。我们没有计划在短期内离开 PG,因此与数据库无关的决定并不真正适用于我们。我们是一个非常小的团队(2 个付费开发人员,更多的开源贡献者),这让我们在部署策略方面非常灵活。

4

2 回答 2

4

优点:

  • 数据库架构/布局/存储更改对应用程序完全隐藏;
  • 你有一个统一的 API 来处理数据库;
  • 您可以对数据库中完成的所有操作(包括所有SELECT查询)进行大量日志记录。

缺点:

  • 对优秀 DBA 的需求增加;
  • 数据库开发人员对数据库如何处理数据以及 DB 端程序如何工作的深入了解的需求增加;
  • 数据库端和应用端团队之间需要更多的协调;
  • ORM 集成的困难;
  • 使用存储过程限制了数据库的优化可能性,并且某些查询(尤其是报告)会产生性能问题,最好使用视图,因为优化器可以将谓词下推到视图中并正确利用索引。

最好的组合是在数据库端实现大量业务逻辑,而不仅仅是包装函数。

架构版本控制是可能的。对配置表中的数据进行版本控制更加棘手。在我参与的一个项目中,这是通过为我们处理这部分的外部工具(基于 perl)完成的:

  • 首先将数据加载/提取到中间表中;
  • 然后分析 RI 约束和所有可能的违规行为;
  • 在将数据加载到活动表之前可以进行数据操作;
  • 可以一次性定义和提取生成多个表的业务对象;
  • 存在几种处理匹配实体的方法,例如:覆盖、合并、复制。

我们正在对提取文件进行版本控制(这是一个普通的 SQL),并且在安装脚本中有一个特殊的步骤来加载新配置。

于 2012-07-05T10:28:27.673 回答
0

关于便携性:

  • 正如您已经指出的,通过使用存储过程,您在客户端上更加便携。
  • 通过使用存储过程,您在服务器上的可移植性更高(您可以更轻松地移动到不同的 DBMS)。
于 2012-07-05T10:53:16.020 回答