実行プランを比較することから始めましょう:
tinker=> EXPLAIN ANALYZE SELECT * FROM generate_series(1,1e7);
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Function Scan on generate_series (cost=0.00..10.00 rows=1000 width=32) (actual time=2382.582..4291.136 rows=10000000 loops=1)
Planning time: 0.022 ms
Execution time: 5539.522 ms
(3 rows)
tinker=> EXPLAIN ANALYZE SELECT generate_series(1,1e7);
QUERY PLAN
-------------------------------------------------------------------------------------------------
Result (cost=0.00..5.01 rows=1000 width=0) (actual time=0.008..2622.365 rows=10000000 loops=1)
Planning time: 0.045 ms
Execution time: 3858.661 ms
(3 rows)
わかりましたので、今はそれが知っているSELECT * FROM generate_series()
使用して実行されFunction Scan
ている間、ノードをSELECT generate_series()
使用して実行されるResult
ノードを。これらのクエリが異なる方法で実行される原因は何であれ、これらの2つのノードの違いに要約され、どこを見ればよいかが正確にわかります。
EXPLAIN ANALYZE
出力のもう1つの興味深いこと:タイミングに注意してください。SELECT generate_series()
ですがactual time=0.008..2622.365
、SELECT * FROM generate_series()
ですactual time=2382.582..4291.136
。Function Scan
ノードが起動する頃にレコードを返すResult
ノードが終了したレコードを返します。
PostgreSQLは間は何をやっていたt=0
し、t=2382
中にFunction Scan
計画?どうやらそれは実行にかかる時間に関するものなgenerate_series()
ので、私はそれがまさにそれがやっていたことを賭けます。答えが形になり始めResult
ます:結果はすぐに返されるようですがFunction Scan
、結果を具体化してスキャンするようです。
EXPLAIN
道のうち、の実装をチェックしてみましょう。Result
ノードはに住んでいるnodeResult.c
:言っています、
* DESCRIPTION
*
* Result nodes are used in queries where no relations are scanned.
コードは十分に単純です。
Function Scan
はに住んでnodeFunctionScan.c
おり、実際には2フェーズの実行戦略をとっているようです。
/*
* If first time through, read all tuples from function and put them
* in a tuplestore. Subsequent calls just fetch tuples from
* tuplestore.
*/
そして、明確にするために、a tuplestore
が何であるかを見てみましょう:
* tuplestore.h
* Generalized routines for temporary tuple storage.
*
* This module handles temporary storage of tuples for purposes such
* as Materialize nodes, hashjoin batch files, etc. It is essentially
* a dumbed-down version of tuplesort.c; it does no sorting of tuples
* but can only store and regurgitate a sequence of tuples. However,
* because no sort is required, it is allowed to start reading the sequence
* before it has all been written. This is particularly useful for cursors,
* because it allows random access within the already-scanned portion of
* a query without having to process the underlying scan to completion.
* Also, it is possible to support multiple independent read pointers.
*
* A temporary file is used to handle the data if it exceeds the
* space limit specified by the caller.
仮説が確認されました。Function Scan
事前に実行して関数の結果を具体化します。結果セットが大きい場合、ディスクに流出します。Result
何も具体化しませんが、簡単な操作のみをサポートします。