在C 中实现的功能大大比我们用LANGUAGE sql 或plpgsql 实现的任何功能都要快。所以your plpythonu function在表演比赛中大胜。
但plpythonu 是一种不受信任的程序语言。默认情况下不安装它,只有超级用户可以使用不受信任的语言创建函数。您需要了解安全隐患。而且大多数云服务根本不提供不受信任的语言。
The current manual (quote from pg 10):
PL/Python 只能作为“不受信任”的语言使用,这意味着它
不提供任何限制用户可以在其中做什么的方式,并且是
因此命名为plpythonu。受信任的变体plpython 可能会变成
如果开发了安全的执行机制,将来可以使用
在 Python 中。不受信任的 PL/Python 中函数的编写者必须采取
注意该功能不能用于做任何不需要的事情,因为
它将能够执行登录用户可以执行的任何操作
作为数据库管理员。只有超级用户可以在
不受信任的语言,例如plpythonu。
您测试的 SQL 函数没有得到很好的优化。有一千零一种提高性能的方法,然而:
演示
-- func to create random strings
CREATE OR REPLACE FUNCTION f_random_string(int)
RETURNS text AS
$func$
SELECT array_to_string(ARRAY(
SELECT substr('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', (ceil(random()*62))::int, 1)
FROM generate_series(1, $1)
), '')
$func$ LANGUAGE sql VOLATILE;
-- test tbl with 100K rows
CREATE TABLE tbl(str text);
INSERT INTO tbl
SELECT f_random_string(15)
FROM generate_series(1, 100000) g;
VACUUM ANALYZE tbl;
-- 1: your test function 1 (inefficient)
CREATE OR REPLACE FUNCTION sort1(text) RETURNS text AS
$func$ -- your test function 1 (very inefficient)
SELECT string_agg(c, '')
FROM (SELECT unnest(regexp_split_to_array($1, '')) AS c ORDER BY c) t;
$func$ LANGUAGE sql IMMUTABLE;
-- 2: your test function 2 ( inefficient)
CREATE OR REPLACE FUNCTION sort2(text) RETURNS text AS
$func$
WITH t(s) AS (VALUES ($1))
SELECT string_agg(substr(t.s, g.g, 1), '' ORDER BY substr(t.s, g.g, 1))
FROM t
CROSS JOIN LATERAL generate_series(1, length(t.s)) g;
$func$ LANGUAGE sql IMMUTABLE;
-- 3: remove pointless CTE from sort2
CREATE OR REPLACE FUNCTION sort3(text) RETURNS text AS
$func$
SELECT string_agg(substr($1, g, 1), '' ORDER BY substr($1, g, 1))
FROM generate_series(1, length($1)) g;
$func$ LANGUAGE sql IMMUTABLE;
-- 4: use unnest instead of calling substr N times
CREATE OR REPLACE FUNCTION sort4(text) RETURNS text AS
$func$
SELECT string_agg(c, '' ORDER BY c)
FROM unnest(string_to_array($1, NULL)) c
$func$ LANGUAGE sql IMMUTABLE;
-- 5: ORDER BY in subquery
CREATE OR REPLACE FUNCTION sort5(text) RETURNS text AS
$func$
SELECT string_agg(c, '')
FROM (
SELECT c
FROM unnest(string_to_array($1, NULL)) c
ORDER BY c
) sub
$func$ LANGUAGE sql IMMUTABLE;
-- 6: SRF in SELECT list
CREATE OR REPLACE FUNCTION sort6(text) RETURNS text AS
$func$
SELECT string_agg(c, '')
FROM (SELECT unnest(string_to_array($1, NULL)) c ORDER BY 1) sub
$func$ LANGUAGE sql IMMUTABLE;
-- 7: ARRAY constructor instead of aggregate func
CREATE OR REPLACE FUNCTION sort7(text) RETURNS text AS
$func$
SELECT array_to_string(ARRAY(SELECT unnest(string_to_array($1, NULL)) c ORDER BY c), '')
$func$ LANGUAGE sql IMMUTABLE;
-- 8: The same with COLLATE "C"
CREATE OR REPLACE FUNCTION sort8(text) RETURNS text AS
$func$
SELECT array_to_string(ARRAY(SELECT unnest(string_to_array($1 COLLATE "C", NULL)) c ORDER BY c), '')
$func$ LANGUAGE sql IMMUTABLE;
SELECT str, sort1(str), sort2(str), sort3(str), sort4(str), sort5(str), sort6(str), sort7(str), sort8(str) FROM tbl LIMIT 1; -- result sample
字符串 |排序1 |排序2 |排序3 |排序4 |排序5 |排序6 |排序7 |排序8
:---------------- | :---------------- | :---------------- | :---------------- | :---------------- | :---------------- | :---------------- | :---------------- | :--------------
tUkmori4D1rHhI1 | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DHIUhikmorrt
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort1(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.053 ms |
|执行时间:2742.904 毫秒 |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort2(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.105 ms |
|执行时间:2579.397 ms |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort3(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.079 ms |
|执行时间:2191.228 毫秒 |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort4(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.075 ms |
|执行时间:2194.780 ms |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort5(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.083 ms |
|执行时间:1902.829 ms |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort6(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.075 ms |
|执行时间:1866.407 ms |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort7(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.067 ms |
|执行时间:1863.713 ms |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort8(str) FROM tbl;
|查询计划 |
| :------------------------------------------------ -------------------------------------------------- |
| Seq Scan on tbl (cost=0.00..26541.00 rows=100000 width=32) (实际 rows=100000 loops=1) |
|规划时间:0.074 ms |
|执行时间:1569.376 毫秒 |
db小提琴here
最后一种没有COLLATION 规则,严格按字符的字节值排序,这要便宜得多。但您可能需要不同区域设置的排序顺序。
The manual about COLLATION expressions.