在 Greenplum 中实现公用表表达式

Posted

技术标签:

【中文标题】在 Greenplum 中实现公用表表达式【英文标题】:Materialize Common Table Expression in Greenplum 【发布时间】:2013-03-09 01:40:59 【问题描述】:

有没有办法强制 Greenplum PostgreSQL 在 WITH 子句中实现子查询,就像 MATERIALIZEINLINE optimizer hints 在 Oracle 中执行以下操作一样?

WITH dept_count AS (
  SELECT /*+ MATERIALIZE */ deptno, COUNT(*) AS dept_count
  FROM   emp
  GROUP BY deptno)
SELECT ...

我已经搜索了一段时间,只是在 Oracle 中找到了这个功能。

我知道我可以使用CREATE TABLE AS,但是我有几个类似的查询,迫使我在每次查询后都删除临时表,这非常不方便,可能效率低下。

更新: 我测试了下表:

CREATE TABLE test (id: INT);

EXPLAIN WITH test2 AS (SELECT id FROM test)
SELECT COUNT(*) FROM test2;

                                 QUERY PLAN                                     
------------------------------------------------------------------------------------
Aggregate  (cost=0.36..0.37 rows=1 width=8)
   ->  Gather Motion 32:1  (slice1; segments: 32)  (cost=0.01..0.35 rows=1 width=8)
         ->  Aggregate  (cost=0.01..0.01 rows=1 width=8)
               ->  Subquery Scan test2  (cost=0.00..0.00 rows=1 width=0)
                     ->  Seq Scan on test  (cost=0.00..0.00 rows=1 width=4)

我正在使用 Greenplum Postgresql 8.2

【问题讨论】:

请张贴explain analyze 输出。 PostgreSQL 8.2? CTE 已在 Postgres 8.4 中引入。你是说9.2吗? 现在是 8.2。我在 Greenplum 上运行,Greenplum 只支持旧版本的 Postgres 我很困惑。如何在 8.2 中运行 CTE?或者这是 Oracle 的 EXPLAIN 输出?此外,在不是我的帖子下,您需要在 cmets 中使用 @-reply 以确保我收到通知。 @Yang 另外,如果您使用的是 Greenplum 或类似产品,请提前说明。当人们发布有关 3rd 方 PostgreSQL 变体而没有说明时,这非常令人困惑,因为已经进行了各种修改。 PostgreSQL 甚至没有Gather Motion 计划节点,根本没有这样的东西; Pg 8.2 也没有 CTE 支持。 所以你的问题根本不是关于 PostgreSQL... 【参考方案1】:

在 PostgreSQL 中,CTE 是强制实现 CTE 术语的优化障碍。这有望在未来的版本中有所改变,但如果有的话,将提供向后兼容选项。

如果您对查询执行explain analyze,您会发现dept_count 术语正在单独的计划树中作为CTE Scan 执行。它像物化结果一样累积到元组存储中,IIRC。

更新:作者实际使用的是Greenplum。上述声明对于 Greenplum 来说似乎并不正确,Greenplum 在 PostgreSQL 8.2 代码库之上实现了自己的 CTE 支持,或者对 8.4 CTE 特性进行了非直接的反向移植,并进行了重大更改。在 Greenplum 中,除非有额外的 Greenplum 特定功能可用,否则您可能必须使用临时表。

【讨论】:

@Yang 答案已更新。简而言之,您问了一个标记为 PostgreSQL 的问题,而您实际上使用的是 Greenplum 而不是 PostgreSQL,所以我无法真正帮助您解决 Greenplum 特定的问题;也许问greenplum.com/communities/forums。我怀疑你运气不好,需要使用临时表。【参考方案2】:

临时表

如果您正在寻找在您的会话期间持续存在的临时表,请使用实际的TEMPORARY TABLE

CREATE TEMPORARY TABLE t AS
SELECT deptno, COUNT(*) AS dept_count
FROM   emp
GROUP  BY deptno;

SELECT ...
FROM t ...

CREATE [TEMPORARY] TABLE AS in the manual.

但是,PostgreSQL 中没有“全局”临时表。临时表仅对创建它的用户可见,并且仅在创建它的会话期间可见。

CTEs 仅在它们所属的查询中可见。永不止步。

单个查询专有的临时表

要将临时表的可见性限制为单个查询,请将它们放入事务中并添加 ON COMMIT DROP,这会在事务结束时自动删除临时表:

BEGIN;
CREATE TEMP TABLE t ON COMMIT DROP AS
SELECT ...

我能想到的唯一用例,这是有意义的:如果你想在一个巨大的临时表上创建索引:

CREATE INDEX ON t(col1);

SELECT ..
FROM t ...;

ROLLBACK;

或者(在这里没有区别):

COMMIT;

如果您使用ROLLBACK,您也可以只使用没有ON COMMIT DROP 的临时表,因为无论如何都会回滚。

【讨论】:

是的,这可以解决我的问题,但是如果我可以让一个临时表仅在一个查询中可见会更好,因为我有多个查询,每个查询都需要一个临时表。频繁地创建和删除表会很不方便。 @Yang:好的,但这就是 CTE 开箱即用的功能:a temporary table visible only within one query。与子查询不同,CTE 在该查询的 any 查询级别可见。这里有什么困惑? CTE 没有具体化表格。我正在加入三个非常大的表 Postgresql 没有实现第一个连接就耗尽了存储空间。 @Yang:我添加了仅为 one 查询创建临时表的方法。但我不确定这是否会给您带来任何优于仅使用 CTE 的优势。

以上是关于在 Greenplum 中实现公用表表达式的主要内容,如果未能解决你的问题,请参考以下文章

如何在 postgresQL 查询中实现数学表达式?

T-SQL 公用表表达式(CTE)

公用表表达式,为啥要分号?

SQL Server 公用表表达式(CTE)实现递归

SQL Server 公用表表达式(CTE)实现递归

公用表表达式(CTE)