有没有办法强制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
答案 0 :(得分:3)
在PostgreSQL中,CTE是一种强制实施CTE术语的优化障碍。这有望在将来的版本中进行更改,但如果有的话,将提供向后兼容性选项。
如果您对查询执行了explain analyze
,则会发现dept_count
字词在单独的计划树中作为CTE Scan
执行。它就像物化结果IIRC一样积累到了一个大都市。
更新:作者实际上正在使用Greenplum。对于Greenplum来说,上述陈述似乎并非如此,他们在PostgreSQL 8.2代码库之上实现了他们自己的CTE支持,或者对具有重大变化的8.4 CTE功能进行了非直接的反向移植。在Greenplum看起来你可能不得不使用临时表,除非有其他可用的Greenplum功能。
答案 1 :(得分:1)
如果您要查找在会话期间持续存在的临时表,请使用实际的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
的临时表,因为无论如何都会回滚所有内容。