在 Greenplum 中实现公用表表达式
Posted
技术标签:
【中文标题】在 Greenplum 中实现公用表表达式【英文标题】:Materialize Common Table Expression in Greenplum 【发布时间】:2013-03-09 01:40:59 【问题描述】:有没有办法强制 Greenplum PostgreSQL 在 WITH
子句中实现子查询,就像 MATERIALIZE
和 INLINE
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 中实现公用表表达式的主要内容,如果未能解决你的问题,请参考以下文章