Postgres CTE会读取所有行,即使它没有吗?

时间:2017-09-11 11:09:37

标签: postgresql

这样的查询会读取big_table中的所有行还是实际需要的行?

WITH tmp AS (SELECT * FROM big_table)
SELECT * FROM
    small_table st
JOIN tmp ON tmp.Id = st.BigTableId
WHERE st.Id = 45

子选择会更好吗?

SELECT * FROM
    small_table st
JOIN (SELECT * FROM big_table) as tmp ON tmp.Id = st.BigTableId
WHERE st.Id = 45

我喜欢使用WITH编写更具可读性的查询,但如果成本更差,则不行。

1 个答案:

答案 0 :(得分:2)

CTE中的查询是自动执行的(没有连续查询的任何条件)在问题中描述的情况下,使用CTE的查询将比另一个慢得多。

如果您有疑问,请使用EXPLAIN ANALYZE。你应该得到类似以下的计划。

使用CTE(大表有100000行,所有行都将以cte扫描):

 Hash Join  (cost=1580.96..4269.53 rows=565 width=12) (actual time=10.349..42.718 rows=1 loops=1)
   Hash Cond: (tmp.id = st.bigtableid)
   CTE tmp
     ->  Seq Scan on big_table  (cost=0.00..1572.65 rows=112965 width=4) (actual time=0.011..11.813 rows=100000 loops=1)
   ->  CTE Scan on tmp  (cost=0.00..2259.30 rows=112965 width=4) (actual time=0.013..33.524 rows=100000 loops=1)
   ->  Hash  (cost=8.30..8.30 rows=1 width=8) (actual time=0.013..0.013 rows=1 loops=1)
         Buckets: 1024  Batches: 1  Memory Usage: 9kB
         ->  Index Scan using small_table_pkey on small_table st  (cost=0.28..8.30 rows=1 width=8) (actual time=0.009..0.009 rows=1 loops=1)
               Index Cond: (id = 45)

没有CTE:

 Nested Loop  (cost=0.57..16.61 rows=1 width=12) (actual time=0.069..0.071 rows=1 loops=1)
   ->  Index Scan using small_table_pkey on small_table st  (cost=0.28..8.29 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=1)
         Index Cond: (id = 45)
   ->  Index Only Scan using big_table_pkey on big_table  (cost=0.29..8.31 rows=1 width=4) (actual time=0.056..0.056 rows=1 loops=1)
         Index Cond: (id = st.bigtableid)
         Heap Fetches: 1

请注意,第二个查询中不需要子查询。它会自动优化到这个:

SELECT * 
FROM small_table st
JOIN big_table as tmp ON tmp.Id = st.BigTableId
WHERE st.Id = 45