Skip to Main Content
  • Questions
  • significant limitations when using the update ... set row clause

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Dieter.

Asked: July 22, 2007 - 3:02 pm UTC

Last updated: July 24, 2007 - 11:07 am UTC

Version: 10.2

Viewed 1000+ times

You Asked

Hi Tom,

The SET ROW clause has been available since Oracle 9i and after years of wring endless and database design dependent assignment list, I just love it.
The clause enables us to update a record using a PL/SQL record and very efficient syntax like:

UPDATE table_name
SET ROW = plsql_record
WHERE  ...


Unfortunately the target table's primary key is always updated whenever a record is updated, but most of the time the primary key has not changed.
This sometimes dramatically decreases the performance of an update statement and can also cause some significant locking issues when updating a table that is referenced by many other tables.

1) Did you find a way to get around this important disadvantage?
2) Would you rather suggest not to use this PL/SQL "feature?
3) Do you know of something in the Oracle pipeline addressing this problem?

Thank you for all your help and keep up the good work,

Dieter

and Tom said...

... Unfortunately the target table's primary key is always updated ...

that is false, ALL of the columns in the record are updated (have to be, think about it - there is nothing 'special' about a primary key that says 'do not update me' besides common sense).

It is only a looking issue if you have UNINDEXED foreign keys and update the parent records primary key (that I believe would be the cause for most any and all noticeable performance issues - since we skip the index maintenance if you do not modify the indexed column).

I'm not a fan of this set row - it is an idea that sounds good but when you peel back the layers - it is not.

It updates by position - not by name - so I've seen some tricky to debug situations whereby a record is selected from table T1 and applied to table T2 - and the columns were just a bit out of order, eg:

ops$tkyte%ORA9IR2> create table t1 ( x int primary key, a int, b int );

Table created.

ops$tkyte%ORA9IR2> create table t2 ( x int primary key, b int, a int );

Table created.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> insert into t1 values ( 1, 2, 3 );

1 row created.

ops$tkyte%ORA9IR2> insert into t2 values ( 1, null, null );

1 row created.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> declare
  2          l_rec t1%rowtype;
  3  begin
  4          select * into l_rec from t1;
  5          update t2 set row = l_rec where x = l_rec.x;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> select 't1', x, a, b from t1
  2  union all
  3  select 't2', x, a, b from t2;

'T          X          A          B
-- ---------- ---------- ----------
t1          1          2          3
t2          1          3          2




I would much rather "pay the price" of listing, in order, the columns I intend and need to update - rather than this syntactic sugar that has been the cause of no little confusion.

I don't mind typing a bit today - in order to forgo really bad accidental side effects (eg: bugs) tomorrow.



I'm not a huge fan of this feature anymore - I wrote about it when it first came out, but experience has caused me to conclude we'd be better off without it.

Just like autonomous transactions - they seemed like such a good idea at the time...

Rating

  (5 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

You don't have to update every column...

Adrian Billington, July 23, 2007 - 4:04 pm UTC


You can workaround this problem fairly easily and only update the columns you are interested in. I've written about it here: http://www.oracle-developer.net/display.php?id=418

Regards
Adrian
Tom Kyte
July 24, 2007 - 9:11 am UTC

he wanted to avoid referencing each and every column, your approach has them explicitly reference each and every column (as would mine) they are interested in touching.

see, they want cake and to eat it too.


Jens, July 24, 2007 - 2:50 am UTC

You say
"Just like autonomous transactions - they seemed like such a good idea at the time... "

I still love those. Especially for logging and stuff. What is wrong with them?

Jens
Tom Kyte
July 24, 2007 - 9:45 am UTC

the are universally misused and abused.

they are useful for logging errors - period. We should have just provided a customizable "log my error" routine, not the autonomous transaction.

Beyond that, they are harmful - especially when used by people that don't "get it".

So, it is a feature that when used appropriate is great, but is universally mis-applied over and over again leading to corrupt data.

eg: if you use an autonomous transaction in a trigger to avoid a mutating table constraint, the odds are near 100% you have a bug in your trigger logic.

Agree but...

Dieter Oberkofler, July 24, 2007 - 10:31 am UTC

Hi Tom,

Thank you for your feedback. I see your point but have two comments on it:

1) Not using records has the major disadvantage that when an attribute (columns) is added to a table, all of the PL/SQL code needs to be reviewed. (I know DB access encapsulation solves this one but this is not always an option)

2) I would not see why the database could not offer an option to simply internally compare the original to the new row contents and only update the needed columns. This would solve the problem... or not?

Tom Kyte
July 24, 2007 - 11:07 am UTC

1) and if you add a column to a table... and the record automatically changes... and your code automatically starts updating it... and there was a trigger that does something upon this column changing...

and - well, I like explicit code. I believe that my transaction should be coded to modify attributes (a,b,c) and if it needs to modify d later - i HAVE TO revisit that code by definition.

and if my code is not to update D, well, since my code did not explicitly reference it - my code is NOT broken!!

I don't think this line of argument has validity. if your code cares about this new column, your code needs to do something to it, meaning your code must be revisited.

and if your code doesn't care about this new column and your code explicitly does not reference this column - your code is not broken.

2) we've had this discussion on other forums (Jonathan Lewis's blog in particular). It is an optimization that would negatively impact 99% of the updates out there performance wise - since most updates only do what they need to.

option

Dieter Oberkofler, July 24, 2007 - 11:26 am UTC

1) I understand you and follow those rules of explicit code whenever possible. On the other had I've seen thousands of PL/SQL lines simply assigning variables to columns and got sick of them as well when fixing the one missing assignment.

2) I do agree on the negative impact on 98% of the code and this is the reason why I mentioned that a special option in the set row clause might help.

Helena Marková, July 25, 2007 - 4:59 am UTC


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library