@mu 已经演示了index on an expression 如何解决您的问题。
我的注意力被使用过的功能所吸引。对于两个整数的数组来说,两者似乎都是多余的。这可能是对真实情况的简化。 (?)
无论如何,我很感兴趣并用几个变体进行了测试。
测试设置
-- temporary table with 10000 random pairs of integer
CREATE TEMP TABLE arr (i int[]);
INSERT INTO arr
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM generate_series(1,10000);
测试候选人用简短的评论来解释每个人:
-- 1) mu's query
CREATE OR REPLACE FUNCTION sort_array1(integer[]) RETURNS int[] AS
$$
SELECT array_agg(n) FROM (SELECT n FROM unnest($1) AS t(n) ORDER BY n) AS a;
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 2) simplified with ORDER BY inside aggregate (pg 9.0+)
CREATE OR REPLACE FUNCTION sort_array2(int[]) RETURNS int[] AS
$$
SELECT array_agg(n ORDER BY n) FROM unnest($1) AS t(n);
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 3) uralbash's query
CREATE OR REPLACE FUNCTION sort_array3(anyarray) RETURNS anyarray AS
$$
SELECT ARRAY(
SELECT $1[i]
FROM generate_series(array_lower($1,1), array_upper($1,1)) g(i)
ORDER BY 1)
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 4) change parameters to int[]
CREATE OR REPLACE FUNCTION sort_array4(int[]) RETURNS int[] AS
$$
SELECT ARRAY(
SELECT $1[i]
FROM generate_series(array_lower($1,1), array_upper($1,1)) g(i)
ORDER BY 1)
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 5) simplify array_lower() - it's always 1
CREATE OR REPLACE FUNCTION sort_array5(int[]) RETURNS int[] AS
$$
SELECT ARRAY(
SELECT $1[i]
FROM generate_series(1, array_upper($1,1)) g(i)
ORDER BY 1)
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 6) further simplify to case with 2 elements
CREATE OR REPLACE FUNCTION sort_array6(int[]) RETURNS int[] AS
$$
SELECT ARRAY(
SELECT i
FROM (VALUES ($1[1]),($1[2])) g(i)
ORDER BY 1)
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 7) my radically simple query
CREATE OR REPLACE FUNCTION sort_array7(int[]) RETURNS int[] AS
$$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 8) without STRICT modifier
CREATE OR REPLACE FUNCTION sort_array8(int[]) RETURNS int[] AS
$$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$$ LANGUAGE sql IMMUTABLE;
结果
我执行了大约 20 次,并从 EXPLAIN ANALYZE 中获得了最好的结果。
SELECT sort_array1(i) FROM arr -- Total runtime: 183 ms
SELECT sort_array2(i) FROM arr -- Total runtime: 175 ms
SELECT sort_array3(i) FROM arr -- Total runtime: 183 ms
SELECT sort_array4(i) FROM arr -- Total runtime: 183 ms
SELECT sort_array5(i) FROM arr -- Total runtime: 177 ms
SELECT sort_array6(i) FROM arr -- Total runtime: 144 ms
SELECT sort_array7(i) FROM arr -- Total runtime: 103 ms
SELECT sort_array8(i) FROM arr -- Total runtime: 43 ms (!!!)
这些是来自 Debian Squeeze 上的 v9.0.5 服务器的结果。 v.8.4 上的类似结果。
我还测试了 plpgsql 变体,这些变体与预期的一样慢:一个微小的操作开销太大,没有要缓存的查询计划。
简单函数(nr. 7)比其他函数快得多。这是意料之中的,其他变体的开销对于一个小数组来说实在是太大了。
但是,将STRICT 修饰符去掉超过加倍的速度是意料之中的。至少我没有。我发了question about this phenomenon here。