Try:
WITH arrays AS(
SELECT * from
unnest(
ARRAY[20, 30],
ARRAY[275, 375]
) as xy(x,y)
)
UPDATE t1
SET c3 = a.y
FROM arrays a
WHERE c2 = a.x;
Смотрите описание unnest
функции здесь: click
EDIT
@kordiroko К сожалению. Я пробовал целый день, изменяя ваше решение. Не удалось заставить его работать.
Возможно, у вас установлена более старая версия PostgreSQL. Я тестировал на версии 9.5, он взял меня всего пару минут, чтобы получить его работу, просто копировать/вставить и изменить два параметра в запросе:
create table t1(
c2 BIGINT,
c3 bigint
);
insert into t1(c2, c3)
select x, x * 100
from generate_series(1,1000000) x;
CREATE OR REPLACE FUNCTION updatefunc1(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
FOR i IN array_lower($1, 1) .. array_upper($1, 1)
LOOP
update t1
SET c3 = $2[i]
WHERE c2 = $1[i];
END LOOP;
END;
$$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION updatefunc2(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
WITH arrays AS(
SELECT * from
unnest($1, $2 ) as xy(x,y)
)
UPDATE t1
SET c3 = a.y
FROM arrays a
WHERE c2 = a.x;
END;
$$
LANGUAGE plpgsql;
select updatefunc1(ARRAY[20], ARRAY[275]);
select updatefunc2(ARRAY[30], ARRAY[555]);
select * from t1 where c2 in (20,30);
Позвольте мне знать, если это правильно или есть лучшее решение.
Это очень правильно, но ... это немного медленно.
Я проверил вашу функцию только 100 записей:
select updatefunc1(
array(select * from generate_series(1,100)),
array(select 22222 from generate_series(1,100))
);
потребовалось более 12 секунд:
Результат (стоимость = 20.00..20.31 строк = 1 ширина = 0) (фактическая время = 12259.095..12259.096 строки = 1 петли = 1) Выход: updatefunc1 (($ 0) :: BIGINT [], ($ 1) :: BIGINT []) InitPlan 1 (возвращает $ 0)
Теперь сравните его к моей функции, но для 100.000 записей:
select updatefunc2(
array(select * from generate_series(1,100000)),
array(select 22222 from generate_series(1,100000))
);
результат является 1 секунда 150 мс:
Результат (стоимость = 20.00..20.31 строк = 1 ширина = 0) (фактический время = 1150.018 ..1150.123 строки = 1 петли = 1) Выход: updatefunc2 (($ 0) :: BIGINT [], ($ 1) :: BIGINT []) InitPlan 1 (возвращает $ 0)
Приведенные выше результаты означают, что ваша функция:
(12/100)/(1,150/100000) = 10434,78
раз slooooooooooooooooooooooooooweeeeeeeeeeeeeeeeeeeeeeer,
и в% это только 1043400% медленнее
EDIT 2
Моя версия 9.2.15. Он подбрасывает синтаксические ошибки
Ниже приводится версия, которая должна работать на ранних версиях с PostgreSQL:
CREATE OR REPLACE FUNCTION updatefunc3(BigInt[], BigInt[])
RETURNS void as $$
BEGIN
WITH arrays AS(
SELECT arr1[ rn ] as x, arr2[ rn ] as y
FROM (
SELECT $1 as arr1, $2 as arr2, generate_subscripts($1, 1) As rn
) x
)
UPDATE t1
SET c3 = a.y
FROM arrays a
WHERE c2 = a.x;
END;
$$
LANGUAGE plpgsql;
select updatefunc3(ARRAY[40,82,77], ARRAY[333,654]);
select * from t1 where c2 in (40,82,77);
и тест скорости uptadint 100000 строк:
select updatefunc3(
array(select * from generate_series(1,100000)),
array(select 22222 from generate_series(1,100000))
);
Результат (стоимость = 20,00..20.31 строк = 1 ширина = 0) (фактическое время = 1361.358 ..1361.460 rows = 1 loops = 1) Выход: updatefunc3 (($ 0) :: BIGINT [], ($ 1) :: BIGINT []) InitPlan 1 (возвращает $ 0)
время обновления 100k строк ниже 1,5 секунды
EDIT 3
@kordiko: Не могли бы вы сказать мне, почему ваш запрос намного лучше. Моя функция проходит через каждую строку и обновляет элементы по одному. Ваша функция также выглядит аналогичной. Разве что все эквивалентные строки обновляются одновременно в вашем запросе.
Это потому, что моя функция работает только одну команду обновления независимо от количества элементов в массивах, в то время как ваши обновления функциональных элементов один на один - для 100 элементов он работает 100 команд обновления. Для 1000 элементов он запускает 1000 команд обновления.
Я провел тесты на столе со 1000000 строками, но без индекса. В моей функции обновление читает содержимое таблицы только один раз (выполняется полное сканирование таблицы) и обновляет соответствующую строку. Ваша функция выполняет 100 обновлений, и каждый из них выполняет полное сканирование таблицы.
Если вы создаете и индекс col2
, то скорость вашей функции резко inceases см ниже тест (обратите внимание, что ряд элементов в этом тесте увеличивается от 100 до 100000:
create INDEX t1_c2_ix on t1(c2);
select updatefunc1(
array(select * from generate_series(1,100000)),
array(select 22222 from generate_series(1,100000))
);
Result (cost=20.00..20.31 rows=1 width=0) (actual time=**3430.536**..3430.636 rows=1 loops=1)
Output: updatefunc1(($0)::bigint[], ($1)::bigint[])
InitPlan 1 (returns $0)
Теперь время составляет лишь около 3,5 второго
И испытание моей функции после создания индекса:.
select updatefunc3(
array(select * from generate_series(1,100000)),
array(select 22222 from generate_series(1,100000))
);
Результат (стоимость = 20.00..20.31 строк = 1 ширина = 0) (фактическое время = 1270,619. .1270.724 строки = 1 петли = 1) Выход: updatefunc3 (($ 0) :: BIGINT [], ($ 1) :: BIGINT []) InitPlan 1 (возвращает $ 0)
время остается тем же самым, но на 100% быстрее, чем ваша функция.
@kordiroko Извините. Я пробовал целый день, изменяя ваше решение. Не удалось заставить его работать. – gudge
Я обновил свой андер, пожалуйста, взгляните на него. – krokodilko
Моя версия - 9.2.15. Он вызывает синтаксические ошибки. – gudge