Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
Home -> Community -> Usenet -> c.d.o.server -> Re: Straight SQL always put perform PL/SQL?
Thanks very much for your respond. I read the "write consistency' as
well. I think it is the opertimizer somehow messed up, the cursor
knows to use the index, while update statement choose a full table
scan on a big table.
To demonstrate it, I re-create the simplified situation of our case.
create table test1 as select * from test where id1 < 400000;
update test1 set col1='b';
update test set id3='Y' where id1 < 500;
commit;
create unique index test_ind on test(id1,id2); create bitmap index test_idx3 on test(id3); create unique index test1_ind on test1(id1,id2);
exec dbms_stats.gather_table_stats('scott', 'TEST', method_opt=>'for
all indexed
columns', cascade=>TRUE);
exec dbms_stats.gather_table_stats('scott', 'TEST1', method_opt=>'for
all indexed
columns', cascade=>TRUE);
SQL> declare
2 v_count number;
3 CURSOR test_cur IS
4 select test.id1,test.id2,test.col1 from test, test1 5 where test.id1=test1.id1 6 and test.id2 = test1.id2 and test.id3='Y';7 BEGIN
10 update test 11 set col1 = test_curs.col1 12 where test.id1 = test_curs.id1 13 and test.id2 = test_curs.id2 14 and test.id3='Y'; 15 END LOOP;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.20
SQL> update test a
2 set a.col1 = (select col1
3 from test1 b
4 where a.id1=b.id1
5 and a.id2 = b.id2 and a.id3='Y')
6 where exists
7 (select 1 from test1 b where a.id1=b.id1
8 and a.id2 = b.id2 and a.id3='Y');
499 rows updated.
Elapsed: 00:01:27.75
PL/SQL is much faster.
Thanks very much for your help.
>
> A couple of problems with your comparison:
>
> Your index on test1.id is not unique, so the scalar
> subquery used in the update could (in theory)
> return multiple rows. In the SQL case this
> would crash the query. The pl/sql code would
> "multiply" rows from test, and update them
> multiple times, which means you don't get
> a deterministic result.
>
> Assume you have the appropriate unique index
> in place on test1.id, then your pl/sql is the coded
> equivalent of an update to a join view:
>
> update (
> select test.id,test.col1 from test,test1
> where test.id=test1.id
> )
> set
> id = col1
> ;
>
> However, whilst this update is running, conflicting
> updates could get in ahead of the N million row
> update, do a quick change and commit.
>
> In the case of the SQL, the statement would have to
> rollback if it hit a conflict, and start again with a
> 'write consistent' update - effectively doing a
> 'select for update / update' the second time around.
> (See Ask Tom, search for 'write consistency').
>
> In the case of the PL/SQL, the code will simply
> be doing a read-consistent query, and updating
> rows identified by id. This allows you to get a
> 'lost update' from the conflict (a change made
> by the interfering update gets over-written by
> the pl/sql loop).
>
> In your case of the 1 hour vs. 5 minutes, one of
> the causes of extra time may have been an
> implicit rollback and restart.
>
> --
> Regards
>
> Jonathan Lewishttp://jonathanlewis.wordpress.com
>
> Author: Cost Based Oracle: Fundamentalshttp://www.jlcomp.demon.co.uk/cbo_book/ind_book.html
>
> The Co-operative Oracle Users' FAQhttp://www.jlcomp.demon.co.uk/faq/ind_faq.html
Received on Mon Dec 17 2007 - 15:48:56 CST