【问题标题】:in postgres, is it possible to optimize a VIEW of UNIONs在 postgres 中,是否可以优化 UNION 的视图
【发布时间】:2012-01-06 03:15:47
【问题描述】:

在数据库中有很多相同的模式,cmp01..cmpa0

每个架构都有一个users

每个架构的users 表的主键都有自己的唯一范围

例如,在cmp01.users 中,usr_id0x01000000 and 0x01ffffffff 之间。

有什么方法可以定义一个 VIEW global.users,它是每个 cmp*.union 表的联合,如果通过 usr_id 查询,优化器将前往正确的模式?

当时在想这样的事情:

create view global.users as
select * from cmp01.users where usr_id between 0x01000000 and 0x01ffffffff
union all
select * from cmp02.users where usr_id between 0x02000000 and 0x02ffffffff
....

这行得通吗?不。 EXPLAIN ANALYZE 显示所有使用的架构。

是否有一种方法可以为优化器提供良好的提示?

【问题讨论】:

  • usr_id的数据类型是什么?
  • 根据您的描述,您查询中的 WHERE 子句是多余的。无论如何,您将它们放在那里作为查询计划器的提示,对吗?可能有效,只需使用EXPLAIN ANALYZE 进行测试即可。
  • @ErwinBrandstetter 重新解释分析 - 好主意。需要插入一些虚拟数据并试一试。需要一段时间。
  • @ErwinBrandstetter - 不高兴。 EXPLAIN ANALYZE 按顺序遍历每个模式。

标签: sql postgresql view query-optimization


【解决方案1】:

为什么不在一个包含所有用户的公共架构中创建一个表,可能还有一个额外的列来存储源架构。由于 id 是全局唯一的,您可以保持 id 列唯一:

create table all_users (
source_schema varchar(32),
usr_id int primary key,
-- other columns as per existing table(s)
);

通过插入所有行来填充表格:

insert into all_users
select 'cmp01', * from cmp01.users union
select 'cmp02', * from cmp02.users union ...; -- etc

使用触发器使表保持最新。

设置起来并不难,而且性能很好

【讨论】:

  • 真的。最好的主意。两个问题:1)规范化,2)将触发对用户表的许多更新。一大优势:普通查询要快得多,例如,email 有一个索引,而不是 152 个索引。
  • 似乎我们真正追求的是甲骨文的物化视图。不要认为 pg 会朝那个方向发展——视图会按需实例化为表格。
  • @ccyoung:您可以使用触发器和 cron 作业来模拟 Oracle 的 MVIEW。有关可能的解决方案,请查看此处:tech.jonathangardner.net/wiki/PostgreSQL/Materialized_Views 和此处:pgcon.org/2008/schedule/events/69.en.html
  • @a_horse_with_no_name - 非常好的链接,谢谢。因为所有的 dml 都是通过存储过程,所以这将是一个很好的切片。
  • @ccyoung:你说“两个问题:1)规范化,......”这个设计确实是规范化的。一张用户表,而不是您拥有的 150 个用户表。为什么会有这样的问题?
【解决方案2】:

创建分区表怎么样?主表将创建为global.users,并将按模式名称进行分区。

如果您可以创建 PostgreSQL 可以优化的查询,即在 where 条件中包含架构名称,那么您将在每个架构中获得小型用户表(包括快速检索)。您还可以在每个模式中创建一个视图,该视图将隐藏查询分区表所需的模式名称。我认为仅指定 user_id 是行不通的。我担心 PostgreSQL 的分区功能还不够聪明。

或者只使用一个表,并在每个模式中创建视图,并使用一个代替触发器并将结果限制为该模式的用户。

【讨论】:

  • 这听起来很有希望。会试一试的。
  • 我对模式分区的研究越多,我就越喜欢它。真的很喜欢使用模式来隔离用户。还是有优化问题。在美学上更令人愉悦 - 本质上是通过祖先表创建的视图。
【解决方案3】:

尝试类似:

create view global.users as
select *
from (select 'cmp01' sel_schema, 0x01000000 usr_id_start, 0x01ffffffff usr_id_end
      union all
      select 'cmp02' sel_schema, 0x02000000 usr_id_start, 0x02ffffffff usr_id_end) s
join (select u1.*, 'cmp01' schema from cmp01.users u1
      union all
      select u2.*, 'cmp02' schema from cmp02.users u2) u
on s.sel_schema = u.schema 

并在通过指定用户 ID 查询视图时包含类似 specified_usr_id between usr_id_start and usr_id_end 的条件。

【讨论】:

  • 也许是这样!将进行测试,但需要一段时间。
猜你喜欢
  • 2018-11-20
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 2014-01-03
  • 2013-03-28
  • 1970-01-01
相关资源
最近更新 更多