выполнить несколько независимых запросов в postgresql - PullRequest
0 голосов
/ 07 марта 2020

Скажем, у нас есть запрос SELECT, который принимает некоторые параметры и возвращает не более одной строки

SELECT c FROM Foo WHERE a = 'a' AND b = 'b' LIMIT 1;

(этот запрос является лишь примером и может быть произвольно сложным)

Мы можем поставить это за CREATE PROCEDURE, которое мы можем затем назвать, как

CALL get_foo_c('a', 'b');

Все замечательно, но, скажем, у меня нет только одной пары (a, b), но у меня есть список из них, и я хочу получить список c ответов.

CALL get_foo_c('a1', 'b1');
CALL get_foo_c('a2', 'b2');
CALL get_foo_c('a3', 'b3');
...

, получающих обратно объединение всех запросов, в порядке их запроса

'c1'
'c2'
'c3'

Задержка при выполнении запроса довольно высока, поэтому одновременная выдача одного запроса невозможна.

Очевидно, что мы можем просто выполнять запросы параллельно на стороне клиента. Однако я ищу альтернативы по причинам, которые не имеют отношения к данному вопросу, например, представьте, что язык клиента является однопоточным.

Это возвращает нас к вопросу: можем ли мы выполнить несколько независимых (в смысл, что они не влияют друг на друга) запросы в postgresql? Возможно, с API, который выглядит как

CALL get_many_foo_c(('a1','b1'),('a2','b2'),('a3','b3'));

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

Я исследовал возможность использования FOR LOOP над входными параметрами, но я не мог понять, как заставить его работать, и в любом случае было бы идеально, если бы postgresql internall должен был иметь возможность распараллеливать каждый независимый запрос.

Ответы [ 3 ]

1 голос
/ 07 марта 2020

Попробуйте CREATE FUNCTION, которая намного гибче и лучше интегрируется с механизмом исполнения SQL. Мне нужно больше подробностей, но теперь вы можете легко «передавать» данные в функции.

Если вы пытаетесь оптимизировать стоимость вызова FUNCTION / PROCEDURE, то по определению это будет неудобно ... рассмотрите возможность принятия типа данных не-Atomi c, такого как массив.

Если вы пытаетесь оптимизировать издержки клиент-сервер, загрузите входные данные в таблицу (или временную таблицу) и используйте SELECT myfun c (a) FROM temp_table; позвонить myfun c несколько раз. Очевидно, что temp_table может быть подзапросом ...

1 голос
/ 07 марта 2020

Создайте скалярную функцию вместо хранимой процедуры. Тогда вы можете назвать это как:

select v.*, get_foo_c(a, b)
from (values ('a1', 'b1'), ('a2', 'b2'), ('a3', 'b3')
     ) v(a, b);
1 голос
/ 07 марта 2020

Начиная с PostgreSQL версии 12, имеется функция параллельного запроса. Вам просто нужно сообщить серверу, что ваша функция параллельна, и вы можете наслаждаться тем, что ваш одиночный запрос потребляет столько процессорных ядер, сколько вам потребуется sh.

Далее следует рецепт.

Создать набор тестовых входных данных. В моем случае это 100 M строк:

CREATE UNLOGGED TABLE test1tab (a int, b int);
INSERT INTO test1tab SELECT 1, x FROM generate_series(1,100000000) x;

Создайте свою функцию, отметьте ее PARALLEL SAFE:

CREATE OR REPLACE FUNCTION test1fun(a integer, b integer) RETURNS integer
LANGUAGE plpgsql as $$
BEGIN
  RETURN 345 * a + b / 2;
END;
$$
PARALLEL SAFE
IMMUTABLE;

Сообщите серверу, сколько параллельных потоков вы хотите запустить:

SET max_parallel_workers_per_gather TO 4;

Запустите SELECT на нескольких входах и увидите, как горят ваши процессоры:

EXPLAIN /* remove me to light up the fireplace */
SELECT test1fun(a,b)
FROM test1tab;

Примечание: по умолчанию для параллельного выполнения будет некоторое пороговое значение, ie. он не запустится, когда слишком мало входов.

Все это настраивается и документируется - включая ограничения параллельных запросов , всю главу о параллельных запросах , а также список GUC, связанных с асинхронным обработка .

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