Tại sao Hàm Đặt lại (SRF) chạy chậm hơn trong mệnh đề TỪ?


8

Đây là một câu hỏi cơ sở dữ liệu. Tôi đang sử dụng PostgreSQL 9.5, tôi tự hỏi tại sao Đặt Hàm trả về (SRF), còn được gọi là Hàm giá trị bảng (TVF) chạy chậm hơn khi trong FROMmệnh đề, ví dụ như khi tôi thực thi các lệnh này,

CREATE TABLE foo AS SELECT * FROM generate_series(1,1e7);
SELECT 10000000
Time: 5573.574 ms

luôn luôn chậm hơn đáng kể so với,

CREATE TABLE foo AS SELECT generate_series(1,1e7);
SELECT 10000000
Time: 4622.567 ms

Có một quy tắc chung nào có thể được thực hiện ở đây không, như vậy chúng ta phải luôn luôn chạy các Hàm đặt lại bên ngoài một FROMmệnh đề?

Câu trả lời:


13

Hãy bắt đầu bằng cách so sánh các kế hoạch thực hiện:

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)

Được rồi, vì vậy bây giờ chúng ta biết rằng SELECT * FROM generate_series()được thực thi bằng một Function Scannút, trong khi SELECT generate_series()được thực hiện bằng một Resultnút. Bất cứ điều gì đang khiến các truy vấn này thực hiện khác nhau đều có sự khác biệt giữa hai nút này và chúng tôi biết chính xác nơi cần tìm.

Một điều thú vị khác trong EXPLAIN ANALYZEđầu ra: lưu ý thời gian. SELECT generate_series()actual time=0.008..2622.365, trong khi SELECT * FROM generate_series()actual time=2382.582..4291.136. Các Function Scannút bắt đầu quay trở lại các hồ sơ trong khoảng thời gian các Resultnút xong trở về hồ sơ.

PostgreSQL đã làm gì giữa t=0t=2382trong Function Scankế hoạch? Rõ ràng đó là khoảng thời gian để chạy generate_series(), vì vậy tôi cá rằng đó chính xác là những gì nó đang làm. Câu trả lời bắt đầu hình thành: có vẻ như Resulttrả về kết quả ngay lập tức, trong khi có vẻ như cụ thể Function Scanhóa kết quả và sau đó quét chúng.

Không EXPLAINcòn cách nào khác, hãy kiểm tra việc thực hiện. Các Resultnút sống trong nodeResult.c, mà nói:

 * DESCRIPTION
 *
 *      Result nodes are used in queries where no relations are scanned.

Mã này đủ đơn giản.

Function Scansống nodeFunctionScan.cvà thực sự có chiến lược thực hiện hai giai đoạn :

/*
 * If first time through, read all tuples from function and put them
 * in a tuplestore. Subsequent calls just fetch tuples from
 * tuplestore.
 */

Và để rõ ràng, chúng ta hãy xem a tuplestorelà gì :

 * 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.

Giả thuyết được xác nhận. Function Scanthực hiện trả trước, cụ thể hóa các kết quả của hàm, cho kết quả lớn sẽ dẫn đến kết quả tràn vào đĩa. Resultkhông cụ thể hóa bất cứ điều gì, nhưng cũng chỉ hỗ trợ các hoạt động tầm thường.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.