Параллельный unnest() и порядок сортировки в PostgreSQL
Я понимаю, что с помощью
SELECT unnest(ARRAY[5,3,9]) as id
без ORDER BY
предложение, порядок результирующего набора не гарантируется. Я мог бы, например, получить:
id
--
3
5
9
но как насчет следующего запроса:
SELECT
unnest(ARRAY[5,3,9]) as id,
unnest(ARRAY(select generate_series(1, array_length(ARRAY[5,3,9], 1)))) as idx
ORDER BY idx ASC
гарантируется ли, что 2 unnest()
вызовы (которые имеют одинаковую длину) будут разворачиваться параллельно и что индекс idx
действительно будет соответствовать положению элемента в массиве?
Я использую PostgreSQL 9.3.3.
2 ответов
Да, это особенность Postgres и параллельная неустановка гарантированный для синхронизации (если все массивы имеют одинаковое количество элементов).
Postgres 9.4 добавляет чистое решение для параллельного unnest:
порядок результирующих строк не гарантируется. На самом деле, с таким простым утверждением as:
SELECT unnest(ARRAY[5,3,9]) AS id
результирующий порядок строк "гарантирован", но Postgres ничего не утверждает. Оптимизатор запросов может упорядочивать строки по своему усмотрению, если порядок явно не определен. Это может иметь побочные эффекты в более сложных запросов.
если второй запрос в вашем вопросе-это то, что вы на самом деле хотите (добавьте номер индекса к элементам unnested array), есть лучший способ с generate_subscripts ():
SELECT unnest(ARRAY[5,3,9]) AS id
, generate_subscripts(ARRAY[5,3,9], 1) AS idx
ORDER BY idx;
подробности в этом соответствующем ответе:
вам будет интересно WITH ORDINALITY
в Postgres 9.4:
затем вы можете использовать:
SELECT * FROM unnest(ARRAY[5,3,9]) WITH ORDINALITY tbl(id, idx);
короткий ответ:: нет, idx
не будет соответствовать позициям массива, при принятии предпосылки, что unnest()
выход может быть случайным образом.
демо:
с момента текущей реализации unnest
фактически выведите строки в порядке элементов, я предлагаю добавить слой поверх него, чтобы имитировать случайный порядок:
CREATE FUNCTION unnest_random(anyarray) RETURNS setof anyelement
language sql as
$$ select unnest() order by random() $$;
затем проверьте несколько исполнений вашего запроса с помощью unnest
заменить unnest_random
:
SELECT
unnest_random(ARRAY[5,3,9]) as id,
unnest_random(ARRAY(select generate_series(1, array_length(ARRAY[5,3,9], 1)))) as idx
ORDER BY idx ASC
пример вывода:
id | idx ----+----- 3 | 1 9 | 2 5 | 3
id=3
связан с idx=1
но 3
в 2-й позиции в массиве. Это все неправильно.
что не так в запросе: предполагается, что первый unnest
перетасует элементы, используя ту же перестановку, что и вторая unnest
(перестановка в математическом смысле: связь между порядком в массиве и порядком строк). Но это предположение противоречит предпосылке, что порядок вывода unnest
непредсказуемо для начала.
об этом вопросе:
гарантируется ли, что 2 вызова unnest () (которые имеют то же самое длина) будет разворачиваться параллельно
на select unnest(...) X1, unnest(...) X2
С X1
и X2
тип SETOF something
и имея такое же количество строк,X1
и X2
будет спарен в окончательном выходе так, что X1
значение на row N
ждет X2
значение в той же строке N
.
(это своего рода объединение для столбцов, в отличие от декартового произведения).
но я бы не сказала, что это спаривание, как разверните параллельно, так что я не уверен, что это то, что вы имели в виду.
в любом случае это сопряжение не помогает с проблемой, так как это происходит после того, как unnest вызовы потеряли позиции массива.
альтернатива: In этот нить из списка рассылки pgsql-sql предлагается следующая функция:
CREATE OR REPLACE FUNCTION unnest_with_ordinality(anyarray, OUT value
anyelement, OUT ordinality integer)
RETURNS SETOF record AS
$$
SELECT [i], i FROM
generate_series(array_lower(,1),
array_upper(,1)) i;
$$
LANGUAGE sql IMMUTABLE;
основываясь на этом, мы можем заказать второй выходной столбец:
select * from unnest_with_ordinality(array[5,3,9]) order by 2;
value | ordinality -------+------------ 5 | 1 3 | 2 9 | 3
С postgres 9.4 и выше: элемент WITH ORDINALITY
предложение, которое может следовать за вызовами возвращающей функции SET, обеспечит эту функциональность общим способом.