db=> explain analyze with data as (select a, b, c from D where e='something') select * from Data;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on D (cost=0.00..3060987.06 rows=1955179 width=42) (actual time=0.022..81146.222 rows=2027407 loops=1)
Filter: ((e)::text = 'something'::text)
Rows Removed by Filter: 9757878
Planning Time: 0.083 ms
Execution Time: 89924.754 ms
(5 rows)
db=> explain analyze select * from (select a, b, c from D where e='something') x;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on documentsubjecthistory (cost=0.00..3060987.06 rows=1955179 width=42) (actual time=0.025..81148.606 rows=2027407 loops=1)
Filter: ((subjectentitycodesystem)::text = '2.16.840.1.113883.6.69'::text)
Rows Removed by Filter: 9757878
Planning Time: 0.105 ms
Execution Time: 89925.772 ms
(5 rows)
然而,当我实际运行第一个带有with Data (...) select * from Data
CTE 的程序时,结果实际上只在这 89 秒之后才出现,而当我运行时select * from (...) x
,我很快就得到了初始页面。
我\set FETCH_COUNT 1000
在.psqlrc中有
psql17之前的版本会忽略
FETCH_COUNT
那些不以关键字开头的查询select
(v16文档中说:SELECT 查询的结果会被取出并按多行分组显示,并且这个 SELECT 必须按字面意思来解释)。在此问题中,第一个语句以 开头
with
,第二个语句以 开头select
,因此 psql v16 或更早版本会发送未修改的第一个查询,并在一个步骤中处理其所有结果。 仅当在内存中检索了整个结果集后,第一个结果才可用。 另一方面,第二个查询转换为:每次迭代后,每个结果块都会立即可用
FETCH
。从 psql v17 开始,实现不再使用游标;它
FETCH_COUNT
使用新的分块行模式,该模式适用于所有查询。因此,您大概会看到两个查询都使用较新的 psql 快速发出第一个结果。此时,PostgreSQL v17 仅在两天前发布,但此功能不需要更新的服务器,只需要最新的客户端。