PostgreSQL: как выполнить запрос параллельно в функции? - PullRequest
1 голос
/ 24 сентября 2019

У меня есть простой запрос

select bod_vykonu_kod, count(1)
from cdc_s5_zdroj
group by 1
order by 1 desc;

, который выполняется параллельно, как и должно.
Объясните, проанализируйте: https://explain.depesz.com/s/auVt

Тогда, если я помещу тот же запрос в функцию, онне работает параллельно.Я пробовал это как STABLE или VOLATILE и все еще не проводил параллели.Я также добавил PARALLEL SAFE , но без разницы.

CREATE OR REPLACE FUNCTION 
test_par () 
returns table (
t_column1 bigint,
t_column2 bigint
)

volatile
PARALLEL SAFE
AS $dbvis$

BEGIN

RETURN QUERY
select bod_vykonu_kod, count(1)
from cdc_s5_zdroj
group by 1
order by 1 desc;

END;
$dbvis$ LANGUAGE plpgsql

Объяснить анализ летучих: https://explain.depesz.com/s/glFO
Объяснить анализ стабильных: https://explain.depesz.com/s/vnXO
Explain analyze stable and parallel safe: https://explain.depesz.com/s/QlKM

PostgreSQL 11.5 для x86_64-pc-linux-gnu, скомпилированный gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-битный
max_parallel_workers = 8
max_parallel_workers_per_gather = 4

Я делаю что-то не так или функции не поддерживают параллельное выполнение, как это?

Ответы [ 2 ]

2 голосов
/ 24 сентября 2019

У меня была такая же проблема с функцией plpgsql.ВОЗВРАТ ЗАПРОСА никогда не работал параллельно.Единственное решение, которое я смог найти, - это сделать что-то подобное, потому что CREATE TABLE AS будет использовать параллельную обработку:

CREATE OR REPLACE FUNCTION 
test_par () 
returns table (
t_column1 bigint,
t_column2 bigint
)

volatile
AS $dbvis$

BEGIN
CREATE TEMPORARY TABLE my_temp ON COMMIT DROP AS
select bod_vykonu_kod, count(1)
from cdc_s5_zdroj
group by 1
order by 1 desc;

RETURN QUERY SELECT * FROM my_temp;
DROP TABLE IF EXISTS my_temp;
END;
$dbvis$ LANGUAGE plpgsql

Это не идеально, но для моей ситуации это все еще былонамного быстрее, чем без параллельной обработки.

1 голос
/ 24 сентября 2019

Я копался в коде, чтобы понять, почему RETURN QUERY не поддерживает параллельное выполнение.

Причина в том, что он использует курсор для получения результата запроса в пакетах по 50, а запросы, выполняемые с использованием курсора,не запускается параллельно (поскольку выполнение может быть приостановлено).

Это соответствующий код в функции exec_stmt_return_query из src/pl/plpgsql/src/pl_exec.c:

exec_stmt_return_query(PLpgSQL_execstate *estate,
                       PLpgSQL_stmt_return_query *stmt)
{
[...]
    if (stmt->query != NULL)
    {
        /* static query */
        exec_run_select(estate, stmt->query, 0, &portal);
    }
[...]
    while (true)
    {
        uint64      i;

        SPI_cursor_fetch(portal, true, 50);

[...]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...