Сортировать буквы в строке по алфавиту в PostgreSQL - PullRequest
0 голосов
/ 18 мая 2018

В настоящее время я использую этот метод для сортировки букв в строке по алфавиту в PostgreSQL.Есть ли другие эффективные методы?

select string_agg(c, '') as s
from   (select unnest(regexp_split_to_array('ijsAafhareDbv', '')) as c 
        order  by c) as t; 

       s   
 --------------
 ADaabefhijrsv

Ответы [ 3 ]

0 голосов
/ 19 мая 2018

Я создал 3 функции, одну с помощью моего запроса, другую с помощью запроса Лоренца и еще одну: я создал функцию Python (plpythonu) для сортировки.Наконец, я создал таблицу из 100000 строк (я сделал это на своем ноутбуке Mac), каждая из которых содержит случайную строку из 15 символов, сгенерированную с помощью функции random_string в этой ссылке

create table t as select random_string(15) as s FROM generate_series(1,100000);

Вот 3 функции.

CREATE or REPLACE FUNCTION sort1(x TEXT) RETURNS TEXT AS $$
select string_agg(c, '') as s
from   (select unnest(regexp_split_to_array($1, '')) as c 
        order  by c) as t;
$$ LANGUAGE SQL IMMUTABLE;


CREATE or REPLACE FUNCTION sort2(x TEXT) RETURNS TEXT AS $$
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;

$$ LANGUAGE SQL IMMUTABLE;


create language plpythonu;
CREATE or REPLACE FUNCTION pysort(x text)
  RETURNS text
AS $$
  return ''.join(sorted(x))
$$ LANGUAGE plpythonu IMMUTABLE;

Это результаты EXPLAIN ANALYSE для всех трех.

knayak=# EXPLAIN ANALYSE select sort1(s)  FROM t;
                                                 QUERY PLAN                                                  
-------------------------------------------------------------------------------------------------------------
 Seq Scan on t  (cost=0.00..26541.00 rows=100000 width=32) (actual time=0.266..7097.740 rows=100000 loops=1)
 Planning time: 0.119 ms
 Execution time: 7106.871 ms
(3 rows)

knayak=# EXPLAIN ANALYSE select sort2(s)  FROM t;
                                                 QUERY PLAN                                                  
-------------------------------------------------------------------------------------------------------------
 Seq Scan on t  (cost=0.00..26541.00 rows=100000 width=32) (actual time=0.418..7012.935 rows=100000 loops=1)
 Planning time: 0.270 ms
 Execution time: 7021.587 ms
(3 rows)

knayak=# EXPLAIN ANALYSE select pysort(s) FROM t;
                                                 QUERY PLAN                                                 
------------------------------------------------------------------------------------------------------------
 Seq Scan on t  (cost=0.00..26541.00 rows=100000 width=32) (actual time=0.060..389.729 rows=100000 loops=1)
 Planning time: 0.048 ms
 Execution time: 395.760 ms
(3 rows)

Из этого анализаОказывается - Python sort был самым быстрым и без существенных различий между первыми 2. Хотя нужно проверять производительность в реальном времени для огромных таблиц в наших системах.

0 голосов
/ 21 мая 2018

Функция, реализованная в C, на существенно * на 1003 * быстрее, чем все, что мы можем достичь с помощью LANGUAGE sql или plpgsql.Таким образом, ваша plpythonu функция выигрывает в конкурсе на результат.

Но plpythonu - это ненадежный процедурный язык.По умолчанию он не установлен, и только суперпользователи могут создавать функции на ненадежных языках.Вы должны знать о последствиях безопасности.А ненадежные языки вообще недоступны в большинстве облачных сервисов.
Текущее руководство (цитата из стр. 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 
str             | sort1           | sort2           | sort3           | sort4           | sort5           | sort6           | sort7           | sort8          
:-------------- | :-------------- | :-------------- | :-------------- | :-------------- | :-------------- | :-------------- | :-------------- | :--------------
tUkmori4D1rHhI1 | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DhHiIkmorrtU | 114DHIUhikmorrt
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort1(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.053 ms                                                                  |
| Execution time: 2742.904 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort2(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.105 ms                                                                  |
| Execution time: 2579.397 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort3(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.079 ms                                                                  |
| Execution time: 2191.228 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort4(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.075 ms                                                                  |
| Execution time: 2194.780 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort5(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.083 ms                                                                  |
| Execution time: 1902.829 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort6(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.075 ms                                                                  |
| Execution time: 1866.407 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort7(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.067 ms                                                                  |
| Execution time: 1863.713 ms                                                              |
EXPLAIN (ANALYZE, TIMING OFF) SELECT sort8(str) FROM tbl;
| QUERY PLAN                                                                               |
| :--------------------------------------------------------------------------------------- |
| Seq Scan on tbl  (cost=0.00..26541.00 rows=100000 width=32) (actual rows=100000 loops=1) |
| Planning time: 0.074 ms                                                                  |
| Execution time: 1569.376 ms                                                              |

db <> скрипка здесь

Последний сортируется без COLLATION правил,это строго байтовые значения символов, что существенно дешевле.Но вам может или не может потребоваться порядок сортировки для другого языка.

Руководство по COLLATION выражениям.

0 голосов
/ 18 мая 2018

Если вам нужно решение без регулярных выражений, вы можете использовать это:

WITH t(s) AS (VALUES ('amfjwzeils'))
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;

 string_agg 
------------
 aefijlmswz
(1 row)

Я бы определил, какое решение быстрее.

...