试试:
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
编辑
@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)(实际
time=12259.095..12259.096 rows=1 loops=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)(实际
time=1150.018..1150.123 rows=1 loops=1) 输出:
updatefunc2(($0)::bigint[], ($1)::bigint[]) InitPlan 1(返回 $0)
以上结果意味着,您的功能是:
( 12 / 100 ) / ( 1.150 / 100000 ) = 10434,78
时间 slooooooooooooooooooooooooooweeeeeeeeeeeeeeeeeeeeeeer,
以 % 为单位,这只是 1043400 % 慢
编辑 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 100,000 行的速度测试是:
select updatefunc3(
array( select * from generate_series(1,100000)),
array( select 22222 from generate_series(1,100000))
);
结果(成本=20.00..20.31 行=1 宽度=0)(实际
time=1361.358..1361.460 rows=1 loops=1) 输出:
updatefunc3(($0)::bigint[], ($1)::bigint[]) InitPlan 1(返回 $0)
更新100k行的时间在1.5秒以下
编辑 3
@kordiko:你能告诉我为什么你的查询要好得多。
我的函数遍历每一行并一一更新元素。
您的功能似乎也做同样的事情。难道所有的
等效行在您的查询中同时更新。
这是因为我的函数只运行一个更新命令,而不管数组中的元素数量如何,而您的函数一个一个地更新元素 - 对于 100 个元素,它运行 100 个更新命令。对于 1000 个元素,它会运行 1000 个更新命令。
我已经在一个有 1000000 行但没有任何索引的表上完成了测试。在我的函数中,更新只读取一次表内容(进行全表扫描),并更新匹配的行。您的函数执行 100 次更新,每次更新都会执行一次全表扫描。
如果您在col2 上创建和索引,那么您的函数的速度会显着提高,请参见下面的测试(请注意,此测试中的元素数量从 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%。