【问题标题】:How to dynamically SELECT from manually partitioned table如何从手动分区表中动态选择
【发布时间】:2021-11-26 03:54:06
【问题描述】:

假设我有这样的租户表;

CREATE TABLE tenants (
  name varchar(50)
)

对于每个租户,我都有一个名为{tenants.name}_entities 的对应表,因此例如对于tenant_a,我将有下表。

CREATE TABLE tenant_a_entities {
  id uuid,
  last_updated timestamp
}

有没有一种方法可以创建具有以下结构的查询? (使用 create table 语法来显示我要查找的内容)

CREATE TABLE all_tenant_entities {
  tenant_name varchar(50),
  id uuid,
  last_updated timestamp
}

--

我明白这是一个奇怪的数据库布局,我在 Postgres 中使用 foreign data 来联合外国数据库。

【问题讨论】:

  • 你为什么不用partitioning
  • 假设每个租户设置一个数据库,并且我想监控此设置,我有一个数据库通过外部表联合其他数据库。每个租户都有一个entities 表。因此,我在这个 federated view 数据库 中有许多以租户名称(或原始数据库)为前缀的表

标签: sql postgresql dynamic-sql union-all table-partitioning


【解决方案1】:

您是否考虑将declarative partitioning 用于您的关系设计?为您的案例列出分区,使用PARTITION BY LIST ...


回答手头的问题:

您根本不需要表tenants 进行查询,只需要详细表。无论如何,您最终会使用UNION ALL 将它们拼接在一起。

SELECT 'a' AS tenant_name, id, last_updated FROM tenant_a_entities 
UNION ALL SELECT 'b', id, last_updated FROM tenant_b_entities 
...

可以动态添加名称,例如:

SELECT tableoid::regclass::text, id, last_updated FROM tenant_a_entities 
UNION ALL SELECT tableoid::regclass::text, id, last_updated FROM tenant_a_entities
...

见:

但在您的情况下(第一个代码示例)动态构建查询时添加常量名称会更便宜 - 例如:

SELECT string_agg(format('SELECT %L AS tenant_name, id, last_updated FROM %I' 
                        , split_part(tablename, '_', 2)
                        , tablename)
                  , E'\nUNION ALL '
                 ORDER BY tablename)  -- optional order
FROM   pg_catalog.pg_tables
WHERE  schemaname = 'public'  -- actual schema name
AND    tablename LIKE 'tenant\_%\_entities';

租户名称不能包含_,否则您必须做更多。

相关:

您可以将其包装在自定义函数中以使其完全动态:

CREATE OR REPLACE FUNCTION public.f_all_tenant_entities()
  RETURNS TABLE(tenant_name text, id uuid, last_updated timestamp)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE
   (
   SELECT string_agg(format('SELECT %L AS tn, id, last_updated FROM %I' 
                           , split_part(tablename, '_', 2)
                           , tablename)
                     , E'\nUNION ALL '
                    ORDER BY tablename)  -- optional order
   FROM   pg_tables
   WHERE  schemaname = 'public'  -- your schema name here
   AND    tablename LIKE 'tenant\_%\_entities'
   );
END
$func$;

呼叫:

SELECT * FROM public.f_all_tenant_entities();

您可以像在 SQL 中的大多数上下文中使用表一样使用此 set-returning 函数(又名“表函数”)。

相关:

请注意,RETIRN QUERY 在 Postgres 14 之前不允许并行查询。The release notes:

允许 plpgsql 的 RETURN QUERY 使用并行性执行其查询 (Tom Lane)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-28
    • 2012-07-26
    • 2011-03-19
    • 2014-04-28
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    相关资源
    最近更新 更多