カーソル使用中の更新

確認方法:
1000万件のテーブルtab1とtab2を作成し
tab1を更新しながら、tab1を参照するカーソルをオープン


--テスト用テーブル作成
drop table tab1 purge;
create table tab1(col1 int,col2 int);
create index ind1 on tab1(col1);

drop table tab2 purge;
create table tab2(col1 int,col2 int);
create index ind2 on tab2(col1);

declare
begin
for i in 1..10000000 loop
insert into tab1 values(i,i);
insert into tab2 values(i,i);

if mod(i,1000) = 0 then
commit;
end if;
end loop;
end;
/

select count(*) from tab1;
select count(*) from tab2;


--tab1をランダム更新

declare
v_random integer;

begin
while true loop

--1500万以下のランダムな数字を生成
select floor(dbms_random.value(1, 15000001)) into v_random from dual;

--数字が1-500万ならupdate
if v_random >= 1 and v_random < 5000000 then
update tab1 set col2 = -1 * col2 where col1 = v_random;
--数字が500万-1000万ならdelete
elsif v_random >= 5000001 and v_random < 10000000 then
delete from tab1 where col1 = v_random;
--数字が1000万-1500万ならinsert
else
insert into tab1 values(v_random,v_random);
end if;

commit;

end loop;
end;
/


--tab1をランダム更新中にtab1を参照するカーソルオープン

declare
cursor cur1 is select * from tab1 where mod(col2,3) = 0;

begin
for c1 in cur1 loop
update tab2 set col2 = 0 where col1 = c1.col1;
commit;
end loop;
end;
/

--tab1,tab2の状態確認

select count(*),min(col2),max(col2) from tab1;
select count(*),min(col2),max(col2) from tab2;

select * from (select * from tab2 where col1 >= 1 order by col1) where rownum < 50;
select * from (select * from tab2 where col1 >= 5000001 order by col1) where rownum < 50;
select * from (select * from tab2 where col1 >= 10000001 order by col1) where rownum < 50;

select count(*) from tab2 where col2 = 0;
select count(*) from tab2 where col2 != 0;

select count(*) from tab1 where col1 >= 5000001 and col1 < 10000001;
select count(*) from tab1 where col1 < 5000001 and col2 < 0;

 


カーソルで参照しているテーブルをランダム更新中にカーソルオープンしても特に問題なしの模様

 

確認方法:
1000万件のテーブルtab1とtab2を作成し
tab1を更新しながら、tab1を参照するカーソルをオープン


--テスト用テーブル作成
drop table tab1 ;
create table tab1(col1 int,col2 int);
create index ind1 on tab1(col1);

drop table tab2 ;
create table tab2(col1 int,col2 int);
create index ind2 on tab2(col1);

drop procedure proc1;

delimiter //
create procedure proc1()
begin
declare i int;

set i = 0;

while i < 10000000 do
set i = i + 1;
insert into tab1 values(i,i);
insert into tab2 values(i,i);
end while;
end
//
delimiter ;


call proc1();


select count(*) from tab1;
select count(*) from tab2;


--tab1をランダム更新

drop procedure proc2;

delimiter //
create procedure proc2()
begin
declare i int;
declare v_random int;

set i = 0;

while true do
set i = i + 1;

-- 1500万以下のランダムな数字を生成
select floor(rand() * 15000000)+1 into v_random;

-- 数字が1-500万ならupdate
if ( v_random >= 1 and v_random < 5000001 ) then
update tab1 set col2 = -1 * col2 where col1 = v_random;
-- 数字が500万-1000万ならdelete
elseif ( v_random >= 5000001 and v_random < 10000000 ) then
delete from tab1 where col1 = v_random;
-- 数字が1000万-1500万ならinsert
else
insert into tab1 values(v_random,v_random);
end if;


end while;
end
//
delimiter ;


call proc2();


--tab1をランダム更新中にtab1を参照するカーソルオープン

drop procedure proc3;

delimiter //
create procedure proc3()
begin

-- データ追加
declare vdone int DEFAULT 0;
declare vcol1 int ;
declare vcol2 int ;

DECLARE cur1 CURSOR FOR
select * from tab1 where mod(col2,3) = 0;

DECLARE continue handler FOR sqlstate '02000' SET vdone = 1;

open cur1;
fetch cur1 into vcol1,vcol2;
while vdone != 1 do

update tab2 set col2 = 0 where col1 = vcol1;
fetch cur1 into vcol1,vcol2;

end while;
close cur1;

end
//
delimiter ;


call proc3();

--tab1,tab2の状態確認

select count(*),min(col2),max(col2) from tab1;
select count(*),min(col2),max(col2) from tab2;

select * from tab2 where col1 >= 1 order by col1 limit 50;
select * from tab2 where col1 >= 5000001 order by col1 limit 50;
select * from tab2 where col1 >= 10000001 order by col1 limit 50;

select count(*) from tab2 where col2 = 0;
select count(*) from tab2 where col2 != 0;

select count(*) from tab1 where col1 >= 5000001 and col1 < 10000001;
select count(*) from tab1 where col1 < 5000001 and col2 < 0;

 

 

確認方法:
1000万件のテーブルtab1とtab2を作成し
tab1を更新しながら、tab1を参照するカーソルをオープン


--テスト用テーブル作成
drop table tab1;
create table tab1(col1 int,col2 int);
create index ind1 on tab1(col1);

drop table tab2;
create table tab2(col1 int,col2 int);
create index ind2 on tab2(col1);

insert into tab1 select generate_series(1,10000000),generate_series(1,10000000);
insert into tab2 select generate_series(1,10000000),generate_series(1,10000000);

select count(*) from tab1;
select count(*) from tab2;


--tab1をランダム更新

drop function fun1();

create or replace function fun1()
returns void as
$$
DECLARE

v_random integer;

BEGIN

-- 1500万以下のランダムな数字を生成
select floor(random() * 15000000)+1 into v_random;

-- 数字が1-500万ならupdate
if v_random >= 1 and v_random < 5000000 then
update tab1 set col2 = -1 * col2 where col1 = v_random;
-- 数字が500万-1000万ならdelete
elsif v_random >= 5000001 and v_random < 10000000 then
delete from tab1 where col1 = v_random;
-- 数字が1000万-1500万ならinsert
else
insert into tab1 values(v_random,v_random);
end if;

END
$$ language 'plpgsql';


----------

while true;do

SQL="psql -c 'select fun1()' test"
eval ${SQL}

done

----------


--tab1をランダム更新中にtab1を参照するカーソルオープン

 

drop function fun2();

create or replace function fun2()
returns void as
$$
DECLARE
r record;

BEGIN

-- データ追加
for r in select * from tab1 where mod(col2,3) = 0
loop
update tab2 set col2 = 0 where col1 = r.col1;
end loop;

END
$$ language 'plpgsql';


select fun2();


--tab1,tab2の状態確認

select count(*),min(col2),max(col2) from tab1;
select count(*),min(col2),max(col2) from tab2;

select * from tab2 where col1 >= 1 order by col1 limit 50;
select * from tab2 where col1 >= 5000001 order by col1 limit 50;
select * from tab2 where col1 >= 10000001 order by col1 limit 50;

select count(*) from tab2 where col2 = 0;
select count(*) from tab2 where col2 != 0;

select count(*) from tab1 where col1 >= 5000001 and col1 < 10000001;
select count(*) from tab1 where col1 < 5000001 and col2 < 0;

 

確認方法:
100万件のテーブルtab1とtab2を作成し
tab1を更新しながら、tab1を参照するカーソルをオープン


--テスト用テーブル作成
drop table tab1;
create table tab1(col1 int,col2 int);
create index ind1 on tab1(col1);

drop table tab2;
create table tab2(col1 int,col2 int);
create index ind2 on tab1(col2);

DECLARE @i integer;
SET @i = 1;
WHILE @i <= 1000000
BEGIN
insert into tab1 values(@i,@i);
insert into tab2 values(@i,@i);
SET @i = @i + 1;
END


select count(*) from tab1;
select count(*) from tab2;


--tab1をランダム更新
DECLARE @v_random integer;
WHILE 1=1
BEGIN
-- 150万以下のランダムな数字を生成
set @v_random = (select floor(rand() * 1500000)+1);

-- 数字が1-50万ならupdate
if ( @v_random >= 1 and @v_random < 500000 )
update tab1 set col2 = -1 * col2 where col1 = @v_random;

-- 数字が50万-100万ならdelete
if ( @v_random >= 500001 and @v_random < 1000000 )
delete from tab1 where col1 = @v_random;

-- 数字が100万-150万ならinsert
if ( @v_random >= 1000001 and @v_random < 1500000 )
insert into tab1 values(@v_random,@v_random);

END


--tab1をランダム更新中にtab1を参照するカーソルオープン

DECLARE @col1 integer;
DECLARE @col2 integer;
BEGIN

declare cur1 cursor for
select * from tab1 where col2%3 = 0

open cur1;
fetch next from cur1 into @col1,@col2;

while @@fetch_status = 0
begin
update tab2 set col2 = 0 where col1 = @col1;
fetch next from cur1 into @col1,@col2;
end
close cur1;
deallocate cur1;


END

 

--tab1,tab2の状態確認

select count(*),min(col2),max(col2) from tab1;
select count(*),min(col2),max(col2) from tab2;

select top 50 * from tab2 where col1 >= 1 order by col1;
select top 50 * from tab2 where col1 >= 500001 order by col1;
select top 50 * from tab2 where col1 >= 1000001 order by col1;

select count(*) from tab2 where col2 = 0;
select count(*) from tab2 where col2 != 0;

select count(*) from tab1 where col1 >= 500001 and col1 < 1000001;
select count(*) from tab1 where col1 < 500001 and col2 < 0;