I had to update every row of table with an result of external function. It was possibility for testing of some patterns:
postgres=# create table testcursor(i integer primary key, v integer);1. test - standard update statement
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "testcursor_pkey" for table "testcursor"
CREATE TABLE
postgres=# insert into testcursor select i, 0 from generate_series(1,100000) g(i);
INSERT 0 100000
postgres=# analyze testcursor;
ANALYZE
/* external function sample */
create or replace function ext_fce(a integer, b integer)
returns int as $
declare r int;
begin
/* protect section */
begin
r := b;
exception when others then
r := null;
end;
return r;
end;
$$ language plpgsql;
postgres=# update testcursor set v = ext_fce(i, 30);2. test - update with updateable cursors
UPDATE 100000
Time: 4369,246 ms
create or replace function testc2(_v integer)3. test - update with PK
returns void as $$
declare
c cursor for select i from testcursor;
_i integer;
begin
open c;
fetch c into _i;
while found loop
update testcursor set v = ext_fce(_i, _v)
where current of c;
fetch c into _i;
end loop;
close c;
end;
$$ language plpgsql;
postgres=# select testc2(20);
testc2
--------
(1 row)
Time: 8434,985 ms
create or replace function testc3(_v integer)Result: Using updateable cursor is about 90% slower than one statement. Usig pk is about 17% slower than updateable cursor. - So updateable cursors has sense and it is well to use it. But every iteration is much slower than one statement's update.
returns void as $$
declare _i integer;
begin
for _i in select i from testcursor loop
update testcursor set v = ext_fce(_i,_v) where i = _i;
end loop;
end;
$$ language plpgsql;
postgres=# select testc3(30);
testc3
--------
(1 row)
Time: 9959,209 ms
The function testc3 is missing.
ReplyDeletefixed, thanks
ReplyDeleteThe result is consistent with the idea that relational databases are better used in a set oriented fashion when possible. Functions extend the domain of applicability of this set-oriented approach (but beware of SQL code inside them).
ReplyDeleteYour tests are interesting for two reasons:
first: we know how much cursors can suck;
second: cursors are anyway a very good solution if compared with client side code performing the same task, which should be on average at least an order of magnitude slower (I normally use java with an ORM layer and know what it means).
Thank you for sharing your results.