Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Rizwan.

Asked: June 11, 2007 - 1:04 pm UTC

Last updated: June 22, 2007 - 10:04 am UTC

Version: 9.2.0.5

Viewed 10K+ times! This question is

You Asked

We have a table with 253 columns. To insert or update a row, the middle tier was 'creating' the SQL dynamically in java - without using bind variables. Now I need to re-write the logic in PL/SQL.
I have the following question for you. I would be grateful if you could answer it:

Will it be better in the update statement to update only those columns which have changed or should I use the new:
 update tableA set row = recordA  where pkColumn = value;   

(where recordA is of type tableA.%rowtype).

Regards,
Rizwan


and Tom said...

the answer, as always, is - it depends.

do you tend to update very few of the columns? It might be worth while to generate an update for just the columns that have changed. That will cut down on the redo and undo generated.

do you tend to update lots of unique sets of columns (eg: you could end up generating MILLIONS of unique sql statements here). then I'd go for the single statement.

do you have an unindex foreign key pointing to these tables? I'd surely want to skip updating the primary key then (to avoid a full table lock on the child table).

(Oracle does have an optimization to skip index maintenance if you have not modified the key value - but -

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create table p ( x int primary key, y int );

Table created.

ops$tkyte%ORA10GR2> create table c ( x references p, y int );

Table created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> insert into p values ( 1, null );

1 row created.

ops$tkyte%ORA10GR2> insert into p values ( 2, null );

1 row created.

ops$tkyte%ORA10GR2> insert into c values ( 2, null );

1 row created.

ops$tkyte%ORA10GR2> commit;

Commit complete.

ops$tkyte%ORA10GR2> update c set y = 0;

1 row updated.

ops$tkyte%ORA10GR2> declare
  2          pragma autonomous_transaction;
  3          l_rec p%rowtype;
  4  begin
  5          l_rec.x := 1;
  6          l_rec.y := 2;
  7          update p set row = l_rec where x = l_rec.x;
  8          commit;
  9  end;
 10  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 7



that won't do a thing for the full table lock of an unindexed foreign key - here we deadlocked ourselves over trying to lock table C, the update could not get the full table lock....



In general, I'd support updating all of the columns MINUS the primary key.


But, don't forget, the java programmers STILL HAVE TO BIND TO THE PLSQL CALL. They will have to write as much code to fix the problem - they MUST BIND to the plsql call or you will have achieved.....

nothing.

Rating

  (16 ratings)

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

Comments

[RE] Update - set row

Rizwan Qazi, June 11, 2007 - 2:28 pm UTC

Thanks very much, Tom!

1) We have indexes on the foreign keys pointing to the above table.

2) We do update a lot of unique sets of columns.
(The application is a web-based multi-form application - as the user moves from one form to the other the column is continuously updated. Many applications use this table for this purpose. Each application updates different sets of columns from different form pages.)

Thanks again. I think we would go for the single update statment and benchmark with runstats, etc.

Regards,
Rizwan

Beware of triggers...

Kashif, June 12, 2007 - 10:17 am UTC

My 2 cents:

When you update using the set row feature, triggers you may have defined for a column will fire and may cause unexpected outcomes. I'm a big believer of updating only what is needed and nothing else.

Kashif

Tom Kyte
June 12, 2007 - 10:35 am UTC

I'm a bigger believer in


NO TRIGGERS - they are horrible... wish they were never invented...


I respectfully disagree with you here - if the trigger should do things only when a value changes, the trigger should contain requisite code to ensure that.

Well...

Kashif, June 12, 2007 - 12:26 pm UTC

Tom,

I know how you feel about triggers, however things like an auto-generated id in Oracle can be implemented using a trigger only (short of calling the sequence everytime in an insert).

Plus, the trigger may or may not validate for changed values in the columns, I was simply trying to provide a heads-up on potential issues Rizwan may encounter.

Updating 253 columns every single time a row needs to be updated seems a bit extreme, not to mention the additional redo/undo they will be generating. I would question why there are 253 columns in the table to begin with.

SET ROW needs to be used with caution. at the very least the SET ROW syntax had the ability to exclude the primary key from the update.

Kashif

Tom Kyte
June 12, 2007 - 2:03 pm UTC

auto generated ID's via triggers are (pardon my bluntness) "not smart"

a great way to confuse? - sure
an utter waste of resources? - absolutely
a bad idea? - I sure think so

there are other ways to generate surrogates "auto-generated", not a fan of them however

ops$tkyte%ORA9IR2> create table t
  2  ( x raw(16) default sys_guid() primary key,
  3    y number
  4  )
  5  /

Table created.

ops$tkyte%ORA9IR2> insert into t (y) values ( 1 );

1 row created.

ops$tkyte%ORA9IR2> select * from t;

X                                         Y
-------------------------------- ----------
32BA55D58BDC4F2DE040007F0100413C          1



If there are 253 columns and many unique sets of them, I'd probably want to pay the price of undo/redo over the millions of unique updates that would be generated.

And the price was pointed out - the trade off you have to make...

Triggers with Instead-OF Views are great!

Rumburak, June 12, 2007 - 12:31 pm UTC

Oh Tom, first time that I have to disagree! ;-)

Instead-OF-Triggers with Views are great! They helped me so much in my Apex-Apps when I use the automatic row processing feature. Hiding complicated pl/sql-logic within ONE simple insert/update/delete is great!



Tom Kyte
June 12, 2007 - 2:06 pm UTC

I hate them.

a stored procedure would have achieved the same goal.

I hate having complicated logic HIDDEN FROM VIEW.

I like simple things done simply

Because every time a developer comes up with something really fancy smancy smart and dandy - we get burned (I am a developer, I've burned myself so many times).

Re: Update - set row

Rizwan Qazi, June 12, 2007 - 3:02 pm UTC

Tom,
I loved the statement:

"If there are 253 columns and many unique sets of them, I'd probably want to pay the price of undo/redo over the millions of unique updates that would be generated."

That is the exact reason that I decided to go with a single update after your answer.

Thanks very much!
Rizwan

Sequence+trigger.

Kashif, June 13, 2007 - 9:49 am UTC

Tom,

You were advocating the sequence+trigger technique yourself till about March 2004 (follow this link and look for my name):

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:256815210563

I suppose you have changed your views on this technique now.

I wasn't aware of the SYS_GUID technique, thanks for the tip.

I respectfully disagree with you on your views on the auto incrementing technique (sequence+trigger) though. Most non-Oracle database developers have worked with auto-incrementing IDENTITY-type columns, and it is more intuititve for them to use a technique that simulates the IDENTITY column. That's been my experience anyway.

Getting back to SET ROW, I would be interested to know the actual (not hypothetical) number of unique update statements generated by Rizwan's application. Don't think it would be in the millions...

Kashif

Tom Kyte
June 13, 2007 - 2:02 pm UTC

I showed how to do it, i was not advocating it. I've written many many times that "this is not the right way", in books even....

Rizwan already said it would be lots of unique combinations - hundreds at least I would guess. I'd rather pay the price of undo/redo in this case (it'll only be for the row data, not the indexes as they are not touched if the values did not change)

Why not sys_guid()?

Reader03, June 14, 2007 - 5:36 am UTC

You said:
there are other ways to generate surrogates "auto-generated", not a fan of them however
ops$tkyte%ORA9IR2> create table t
  2  ( x raw(16) default sys_guid() primary key,
  3    y number
  4  )
  5  /


Why aren't you a fan of this technique? Any obvious drawbacks or just a feeling?
Tom Kyte
June 14, 2007 - 7:50 am UTC

because I like things to be plug obvious.

I don't like magic.

I don't like surprises.

I like things "obvious", this hides the "obvious"


and if I had my way, coders writing stuff in 3gls outside the database would never see INSERT, UPDATE, DELETE, MERGE or even SELECT in their code. They would only call PLSQL - in which case the argument for magic disappears entirely.

One mans Magic....

Mike, June 14, 2007 - 9:09 am UTC

<Quote>
I don't like magic.
</Quote>

I recently watched this man http://www.derrenbrown.co.uk/ on T.V. Get a person to pick a single word, from a single article, from a single page, of one of several daily news papers. That word was the same word as written on a piece of paper that had been in an envelope on stage since the start of the show.

To me that seemed like Magic, to the man on stage it was but application of the tools of the trade. I do not think _anything_ should be universally ruled out. I do not think triggers are univerally bad, nor are sequences, nor are global variables not even the "when others" clause.

We are all adults, we should use our tools responsibly, if an instead of trigger on a view is considered the better of the availalbe approaches I see no reason to just say no.
Tom Kyte
June 14, 2007 - 9:58 am UTC

triggers are almost always bad.
global variables are almost always bad.
when others is ALWAYS bad unless followed by RAISE;

Unfortunately, while I agree in fact with your "we are all adults", I know in practice that most programmers are not - well - responsible.


The number of times triggers have burned - countless. They are evil, to be avoided. They are overused, abused, misused.

Your example is a perfect reason why actually. Most of us cannot do magic, but we are asked to maintain it.

Alexander the ok, June 14, 2007 - 10:08 am UTC

Tom,

WHEN OTHERS is just bad. Even if a "raise" is present, it just hides where the problem is.

Just the other day I was helping someone debug vendor code that had when others littered everywhere in huge packages. Once we commented those out, would found the problem in minutes. (I'm pretty sure it was you who clued me in to this originally too.)
Tom Kyte
June 14, 2007 - 4:01 pm UTC

as an aside, dbms_trace can be used instead of commenting out all of them.

dbms_trace will log all exceptions to a table for review after the fact. handled and unhandled exceptions.

magic

A reader, June 14, 2007 - 11:15 am UTC

"I don't like magic"

so you don't like the dual table ?


Tom Kyte
June 14, 2007 - 4:01 pm UTC

love dual. what is magic about a one row, one column table?

And yet...

Mike, June 14, 2007 - 11:20 am UTC

<Quote>
when others is ALWAYS bad unless followed by RAISE;
</quote>

Always? Some years ago when discussing DBMS_JOB you suggested using when others then and not re-raising and I agreed then and now that that is the best approach.

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1965472676428#12751057495968

Search for - Followup September 30, 2003 - 12pm US/Eastern:

That said I'd have to agree with the praticalities of your arguements - isn't it a shame? I sometimes feel that programmers are like small children. That you have no choice but to take their toys away as they cannot learn to place nicely with the other children.

<Sigh>

Mike.
Tom Kyte
June 14, 2007 - 4:03 pm UTC

but that was to make a job succeed - ok, I'll say 99.9999999999999% of the time.

That was a strange case - if a job fails, we (i) don't typically want it removed from the queue - this makes a failed job silently succeed.

I don't like "magic"

Sokrates, June 14, 2007 - 4:42 pm UTC

What about VPD's

Robert, June 20, 2007 - 2:23 pm UTC

Tom,

You don't like triggers because they hide and/or obfuscate the obvious.... but what about the Virtual Private Database concept? Doesn't this do the same thing? (e.g. "Why am I not getting anything back from this query!?)"

Thanks,

Robert.
Tom Kyte
June 20, 2007 - 2:38 pm UTC

not so much - you should see what you are permitted to see.

Sort of an analogy:

george logs in and issues "select * from scott.emp"
it works
mary logs in and issues "select * from scott.emp"
it fails, no such table.

why isn't mary getting anything back - EMP obviously exists because george can see it



Views are like VPD, I like VIEWs a lot.


Triggers are hiding some serious side effects - data processing is taking place there.

Re: What about VPDs?

David Weigel, June 21, 2007 - 10:24 am UTC

But the effects of VPDs when changing data uncomfortably resemble trigger side-effects. I work on an application that we sold to ~100 customers and have to support. It drives me nuts when I need to fix data we broke and it resembles this:
CUSTDB> select count(*) from importanttable where key = 1000;

  COUNT(*)
----------
         0

CUSTDB> insert into importanttable (key) values (1000);
*
ERROR at line 1:
ORA-00001: unique constraint (MFOUR.IMPORTANTTABLE_IX0) violated
Sometimes a customer will have a VPD (that admittedly we supplied at some point) to solve some strange security need, and it's not intuitively obvious when I start on a problem to dump out all_policies for all the potentially affected tables.

And I had to ditch all of the merges from my code because of ORA-28132: Merge into syntax does not support security policies. I hate that.
Tom Kyte
June 21, 2007 - 11:19 am UTC

"sorry"?

But I don't agree. The 'side effects' are immediate and obvious.

They are to me nothing different from a view, and a view is very much ok. Triggers - code, lots of code, lots of tricky code, lots of tricky code running in the background written by people not thinking about multi-user conditions and the like.

I just disagree, you are free to not like them however?

assume real database developpers

Sokrates, June 21, 2007 - 12:27 pm UTC

assume triggers written by people who know everything
about multi-user conditions and the like

do you still hate them ?
Tom Kyte
June 22, 2007 - 10:04 am UTC

yes....


It goes beyond the recurring incorrect, flawed implementations I see time after time.

It makes the entire implementation unmanageable - it is like "magic stuff happens here".

Re: What about VPDs?

David Weigel, June 21, 2007 - 1:22 pm UTC

I agree that VPD makes tables act like views. (Except that you can use merge on an updatable view, natch.) Thing is, if you ask the database, they're tables: they're in all_tables and SQL Developer doesn't show a little asterisk next to the ones with VPD policies on them to say, "Psst! Don't expect these tables to act like all the other ones!" It's that element of surprise that makes me dislike VPDs. (And triggers, Sokrates, even when they're written by smart people, because I'm a big fan of "what you type is what you get".)

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