Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 多租户环境中Postgresql存储过程/函数的性能,该环境具有一个数据库和多个模式(每个租户一个)_Database_Postgresql_Function_Multi Tenant_Postgresql Performance - Fatal编程技术网

Database 多租户环境中Postgresql存储过程/函数的性能,该环境具有一个数据库和多个模式(每个租户一个)

Database 多租户环境中Postgresql存储过程/函数的性能,该环境具有一个数据库和多个模式(每个租户一个),database,postgresql,function,multi-tenant,postgresql-performance,Database,Postgresql,Function,Multi Tenant,Postgresql Performance,我是Postgresql的新手,我正在尝试了解存储过程(我认为在pgsql中实际上称为函数)在多模式环境中使用时的一些细节 我想到的应用程序涉及多租户数据库设计,其中每个租户使用一个模式,所有具有相同表结构和名称的模式都是同一数据库的一部分。据我从DBs了解,存储过程/函数通常是预编译的,因此速度更快,因此我希望通过从应用服务器发送所需的参数,而不是发送SQL命令列表,来使用它们对每个模式的表执行操作。此外,我希望有一组单独的函数来实现每个模式表上的所有SELECT(包括JOIN类型)、INSE

我是Postgresql的新手,我正在尝试了解存储过程(我认为在pgsql中实际上称为函数)在多模式环境中使用时的一些细节

我想到的应用程序涉及多租户数据库设计,其中每个租户使用一个模式,所有具有相同表结构和名称的模式都是同一数据库的一部分。据我从DBs了解,存储过程/函数通常是预编译的,因此速度更快,因此我希望通过从应用服务器发送所需的参数,而不是发送SQL命令列表,来使用它们对每个模式的表执行操作。此外,我希望有一组单独的函数来实现每个模式表上的所有SELECT(包括JOIN类型)、INSERT、UPDATE等操作。这将允许在每个函数中轻松执行更改,并避免SQL代码复制和冗余。我发现,可以在模式
s0
中创建一组函数,然后创建使用这些函数的
s1、s2、
模式(具有所有相同的表)

例如,我可以创建一个名为
s0
(与所有其他模式相同)的模板模式,并创建一个属于此模式的SQL或pl/pgSQL函数,该函数包含对模式表的操作。在这个函数中,表名不带模式前缀,即。
first\u table
和not
s0.first\u table

一个示例函数可以是:

CREATE FUNCTION sel() RETURNS BIGINT 
AS 'SELECT count(a) from first_table;' 
LANGUAGE SQL;
正如我所测试的,这个函数运行良好。如果我通过输入以下内容移动到模式
s1

set search_path to s1;
然后再次调用该函数,该函数作用于
s1
schema的同名表
first\u table
。 该函数还可以包括参数
path
,以便使用架构名称调用该参数,并使用命令更改
search\upath
,如下所示:

CREATE OR REPLACE FUNCTION doboth(path TEXT, is_local BOOLEAN DEFAULT false) RETURNS BIGINT AS $$
    SELECT set_config('search_path', regexp_replace(path, '[^\w ,]', '', 'g'), is_local);
    SELECT count(a) from first_table;
 $$ LANGUAGE sql;
如中建议的解决方案所示

但是,当我尝试此操作并为模式调用函数时,我注意到函数的第二次选择是在第一次选择之前执行的,这导致在错误的模式上执行第二次选择!这真是出乎意料。有人知道这种行为的解释吗

为了绕过这个问题,我创建了一个plpgsql函数,它可以做同样的事情,并且可以在没有任何执行顺序问题的情况下工作:

CREATE OR REPLACE FUNCTION doboth(path TEXT, is_local BOOLEAN DEFAULT false) RETURNS BIGINT AS $$ 
DECLARE result BIGINT;
BEGIN
PERFORM set_config('search_path', regexp_replace(path, '[^\w ,]', '', 'g'), is_local);
SELECT count(a) from first_table INTO result;
RETURN result;
END
 $$ LANGUAGE plpgsql;
现在,关于这次的性能,有一些问题:

1) 除了a)在一个事务中选择要操作的模式和对模式的指定操作,这是我的多租户实现所必需的,以及b)将SQL命令组合在一起,避免在应用程序服务器和DB服务器之间进行一些额外的数据交换,这是有益的,Postgresql函数是否比在单独的SQL命令中执行相同的代码有任何性能优势

2) 在所描述的具有多个模式和一个DB的多租户场景中, 如果一个函数被定义一次并调用了与它所定义的模式相同的模式,它是否会失去任何性能优势(如果有的话)


3) SQL函数和包含相同操作的PL/pgSQL函数在性能上有什么区别吗?

首先,我并不认为函数中的行执行顺序会有任何问题。如果你有任何问题,这是你的代码不工作,而不是Postgres

其次,通过
将搜索路径设置为s1、s0,实现了多租户行为。通常不需要在程序内部切换任何内容

第三,使用存储过程除了最小化数据库和应用程序之间的数据流外,对性能没有任何好处。如果您考虑MyTabe中的“代码> >选择计数(*),其中SeCeCuLube=1美元< /代码>,在您知道<代码> 1美元< /代码>的值之前,绝对没有什么可以优化。

最后,不,SQL和PL/pgSQL中的函数之间没有显著差异。大部分的时间还是花在阅读表格上,所以专注于完善它


希望这能澄清情况。此外,您可能需要考虑存储过程的安全性好处。只是一个提示。

在我回答您的问题之前,请对您的SQL函数做一个注释

它不会因为语句执行顺序错误而失败,而是因为两个查询都是在第一个查询执行之前解析的。您得到的错误消息有点像

ERROR:  relation "first_table" does not exist
[...]
CONTEXT:  SQL function "doboth" during startup
注意“启动期间”

Aswers

  • 您可能会体验到轻微的性能提升,特别是在SQL语句比较复杂的情况下,因为PL/pgSQL函数中的SQL语句计划会在数据库会话期间或在它们失效之前被缓存

    如果查询的计划由PL/pgSQL函数缓存,但是每次都必须计划调用该函数的SQL语句,那么实际上从性能角度看,您可能会因为执行该函数的开销而变得更糟

  • 无论何时使用不同的模式名称调用函数,查询计划都将无效,并且必须重新创建。因此,如果更改每个调用的模式名称,则不会获得任何结果

  • SQL函数不缓存查询计划,因此它们的性能并不比普通SQL查询好

  • 但是,请注意,在函数中缓存简单SQL语句的好处并不是很大

    只有在使您的生活更简单的情况下,才使用仅充当SQL语句容器的函数,否则使用纯SQL

    不要只关注性能设计,还要关注好的体系结构和简单的设计

    如果相同的语句不断重复,你可能会