2

我有一个(可能)关于 Postgres 如何执行包含WITH子句的查询的基本问题。我想知道是否在WITH子句中包含无关表实际上会减慢查询速度。也就是说,如果在WITH子句中创建的“临时”表从未在子句之外调用WITH,那么该“临时”表是否真的创建了?

在第一个示例中,我加入了两个使用WITH子句创建的“临时”表:

--Example 1
WITH temp1 as (
SELECT * from table_1
),
temp2 as (
select * from table_2
)
select * 
from temp1
join temp2;

在第二个示例中,我正在执行完全相同的查询,只是在WITH子句中创建了一个无关的表“temp3”。

--Example 2
WITH temp1 as (
SELECT * from table_1
),
temp2 as (
select * from table_2
),
temp3 as (
select * from table_3
)
select * 
from temp1
join temp2;

这两个查询之间有任何性能差异吗?如果table_3是一个巨大的表,这会减慢示例 2 与示例 1 中的查询吗?如果不是,为什么不呢?

好像影响查询时间。不过我还是很好奇为什么...

4

2 回答 2

6

您可以使用 Explain 来显示查询优化器将如何处理您的查询。

http://www.postgresql.org/docs/9.2/static/sql-explain.html

在上面的例子中,PSQL 应该看到 temp3 没有被使用并且没有包含它。

在我的一个数据库上使用上面的示例。

explain with temp1 as (select * from cidrs), temp2 as (select * from contacts), temp3 as ( select * from accounts )  select * from temp1 join temp2 on temp1.id = temp2.id;
                             QUERY PLAN
---------------------------------------------------------------------
 Hash Join  (cost=22.15..25.44 rows=20 width=4174)
   Hash Cond: (temp1.id = temp2.id)
   CTE temp1
     ->  Seq Scan on cidrs  (cost=0.00..11.30 rows=130 width=588)
   CTE temp2
     ->  Seq Scan on contacts  (cost=0.00..10.20 rows=20 width=3586)
   ->  CTE Scan on temp1  (cost=0.00..2.60 rows=130 width=588)
   ->  Hash  (cost=0.40..0.40 rows=20 width=3586)
         ->  CTE Scan on temp2  (cost=0.00..0.40 rows=20 width=3586)
(9 rows)

你会注意到没有提到 temp3。在回答您的编辑时,关于为什么它不影响查询时间,优化器足够聪明,可以看到它没有被使用并且不会打扰计算它。因此它是一个优化器的原因。

于 2013-12-30T16:07:26.217 回答
5

你已经从@Doon那里得到了主要答案。

由于您对性能感兴趣,请注意在大多数情况下子查询通常比CTE 快。公用表表达式(WITH 查询)构成优化障碍。有关详细信息,请阅读有关 pgsql-performance 的此线程

使用 CTE ...

  • ..如果一个子查询在多个地方使用,避免重复执行。
  • .. 防止优化器出于某种原因(性能,避免对函数的副作用的影响)尝试组合子查询和主查询。
  • .. 对复杂查询进行分区(可读性、可维护性)
  • .. 用于递归查询。
于 2013-12-30T17:49:45.480 回答