Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
617 views
in Technique[技术] by (71.8m points)

postgresql - Function executes faster without STRICT modifier?

I stumbled upon a slump in performance when a simple SQL function is declared STRICT while answering this question.

For demonstration, I created two variants of a function ordering two elements of an array in ascending order.

Test setup

Table with 10000 random pairs of integer (

CREATE TABLE tbl (arr int[]);

INSERT INTO tbl 
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM   generate_series(1,10000);

Function without STRICT modifier:

CREATE OR REPLACE FUNCTION f_sort_array(int[])
  RETURNS int[]
  LANGUAGE sql IMMUTABLE AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;

Function with STRICT modifier (otherwise identical):

CREATE OR REPLACE FUNCTION f_sort_array_strict(int[])
  RETURNS int[]
  LANGUAGE sql IMMUTABLE STRICT AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;

Results

I executed each around 20 times and took the best result from EXPLAIN ANALYZE.

SELECT f_sort_array(arr)        FROM tbl;  -- Total runtime:  43 ms
SELECT f_sort_array_strict(arr) FROM tbl;  -- Total runtime: 103 ms

These are the results from Postgres 9.0.5 on Debian Squeeze. Similar results on 8.4.

In a test with all NULL values both functions perform the same: ~37 ms.

I did some research and found an interesting gotcha. Declaring an SQL function STRICT disables function-inlining in most cases. More about that in the PostgreSQL Online Journal or in the pgsql-performance mailing list or in the Postgres Wiki.

But I am not quite sure how this could be the explanation. Not inlining the function causes a performance slump in this simple scenario? No index, no disc read, no sorting. Maybe an overhead from the repeated function call that is streamlined away by inlining the function?

Retests

Same test, same hardware, Postgres 9.1. Even bigger differences:

SELECT f_sort_array(arr)        FROM tbl;  -- Total runtime:  27 ms
SELECT f_sort_array_strict(arr) FROM tbl;  -- Total runtime: 107 ms

Same test, new hardware, Postgres 9.6. The gap is even bigger, yet:

SELECT f_sort_array(arr)        FROM tbl;  -- Total runtime:  10 ms
SELECT f_sort_array_strict(arr) FROM tbl;  -- Total runtime:  60 ms
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Maybe an overhead from the repeated function call that is streamlined away by inlining the function?

That's what I'd guess. You've got a very simple expression there. An actual function-call presumably involves stack setup, passing parameters etc.

The test below gives run-times of 5ms for inlined and 50ms for strict.

BEGIN;

CREATE SCHEMA f;

SET search_path = f;

CREATE FUNCTION f1(int) RETURNS int AS $$SELECT 1$$ LANGUAGE SQL;
CREATE FUNCTION f2(int) RETURNS int AS $$SELECT 1$$ LANGUAGE SQL STRICT;

iming on
SELECT sum(f1(i)) FROM generate_series(1,10000) i;
SELECT sum(f2(i)) FROM generate_series(1,10000) i;
iming off

ROLLBACK;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...