在工作中,我们目前有一个 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 个付费开发人员,更多的开源贡献者),这让我们在部署策略方面非常灵活。