Does Oracle update columns when the data values are the same? - oracle

If I have a column called NAME and it has a value of "CLARK" and I run an update statement
update table1 set name = 'CLARK';
Does Oracle actually update the column or does it ignore the update command since the values are the same?
I found this question (Oracle, how update statement works) and the first answer implies that an update occurs even if the values are equal. I also tried it in SQL Developer and it ran but I don't know if an update truly occurred.
Thanks in advance.

Yes, Oracle does update the column even if it the same.
In a really simple example, this makes no difference. But consider the following:-
When a record is updated, a lock is obtained on that record for the updating session,
When a record is updated, triggers on the table would fire
This aspects of the update show that the column is actually updated.
Of course, perhaps there are some optimisations when the value is the same, but these are not visible to you as a user of Oracle.

Yes, all row are updated and all triggers fired, even if the actual values doesn't change.

Related

Statement-level trigger in Oracle

I can't fully understand how a statement-level trigger works. It executes once for each transaction right? If I have this AFTER INSERT trigger and what it does inside is that it updates one specific column if it meets the condition (ex for column status, UPDATE table_name SET STATUS = "Single" WHERE COLUMN is null).
Are the newly inserted data only the ones get to be affected? Or every data in the table that has this null value in column status. I'll be glad hearing your knowledge about this.
A statement level trigger will fire once after the triggering statement has run, unlike a row level trigger which fires for each affected row.
After statement triggers are generally used to do processing of the set of data - e.g. logging into a table, or running some post-statement processing (usually a procedure).
If you're wanting to update a value in every affected row, then I would advise using a before row level trigger. The update statement in your question would affect all rows where the COLUMN column is null.
Whether a trigger is actually the right thing to use is debatable. However, I would recommend you look at the documentation and also this Oracle-base article to gain a better understanding of how triggers work and when you might use them.

Can this update cause a deadlock in oracle 10g

I came across this update statement and was wondering how the internal working is. It updates a column which also is used in the where clause of the update.
Should this be ideally done in two steps, or does oracle takes care of it automatically?
UPDATE TBL1 SET DATE1=DATE2 WHERE DATE2> DATE1
Oracle takes care of it automatically. Effectively when it runs the update, Oracle performs the following steps:
Queries the table - i.e. evaluate the WHERE clause predicate for each row in the table
For each row that is returned by step 1, update it as per the SET clause. The values of each column are those that were fetched.
For this reason, it is perfectly possible to run an update like this which swaps the values of columns:
UPDATE TBL1 SET DATE1=DATE2, DATE2=DATE1 WHERE DATE2 > DATE1;
The update might be blocked if another session tries to update or delete one of the same rows. Deadlocks are possible but Oracle automatically resolves these by rolling back one of the sessions and raising an exception.

Dynamically Evaluate Pseudo Records (:OLD, :NEW) in Oracle Trigger

Problem: I have a table to which a customer may add columns. This table might have hundreds of columns of varying data types depending on how insane the customer is. I need to deploy an AFTER UPDATE trigger against this table to insert a row in another table for each column value that has changed.
Example:
Table_A, Row 1: Key_Value=1, Col1=123, Col2="foo"...Coln="bar"
becomes
Table_B, Row 1: Key_Value=1, ColName="Col1", ColValue=123
Table_B, Row 2: Key_Value=1, ColName="Col2", ColValue="foo"
Table_B, Row 3: Key_Value=1, ColName="Coln", ColValue="bar"
Since I do not know what columns they may create and this trigger must be deployed with the application, I need to evaluate the OLD vs NEW pseudo records dynamically (if :new.columns[1] != :old.columns[1] then...) to see what has changed and log only the changed columns. The only examples I have been able to find require referencing the columns in the pseudo records explicitly (if :new.col1 != :old.col1 then...).
Question: Is there a way to do this in Oracle?
Caveats: No, this is not for auditing purposes, so I cannot use Oracle's built-in auditing. No, we are not going to rewrite our app because you know how to do it better, this is the way it needs to work for better or worse.
Any helpful comments are welcome. All snarkey DBA drivel is not. Thanks in advance.
No. You can't dynamically reference columns in the :new or :old pseudorecord.
The closest you're likely to come is to write code that dynamically generates the entire trigger body by querying the data dictionary and making static references to columns in the pseudorecord. That code, however, would need to be run every time a column was added or removed from the table. Normally, that would be done as part of normal release management. If you are saying that people are adding and removing columns from this table without going through a release process, you could write a DDL trigger that submitted a job via dbms_job that called the procedure that rebuilt the trigger. That would be a lot of moving pieces and it would be a pain to troubleshoot when something inevitably goes wrong but if you're not open to alternate ways of implementing the functionality, that's complexity you'll have to live with.

A BEFORE UPDATE TRIGGER can cause MUTATING TABLE Oracle error?

Please suppose you have, in Oracle Database, a BEFORE UPDATE TRIGGER.
If fires only when in a particular column is assigned a certain value (in example, the string 'SUBSTITUTE'` is inserted as update in the ALPHA column), otherwise it does not fire.
This trigger does many queries and, under certain conditions, updates some records of the triggered table.
Being a BEFORE UPDATE TRIGGER, could it cause MUTATING TABLE error?
You can assume that the body of the trigger does not update the ALPHA column, but could update other columns and/or insert new records in the same table, using :OLD values.
The update of the ALPHA column to the string value 'SUBSTITUTE' provokes the trigger fire.
A mutating table is a table that is currently being modified by an update, delete, or insert statement. If your before-update for-each-row trigger tries to modify the table that is defined against then it will get an ORA-04091: table X is mutating, trigger/function may not see it error. Here's a SQL Fiddle with a trivial example.
You'd get the same with an after-update trigger depending on what you're doing; and you can't make it statement-level if you need to act depending on the :new.alpha value.
Both the 'does many queries' part and the update suggest that perhaps a trigger is not the right tool here; this is quite vague though, and what the right tool is depends on what you're doing. A procedure that makes all the necessary changes and is called instead of the simple update might be one solution, for example.

Oracle, 2 procedures avoid deadlock

I have two procedures that I want to run on the same table, one uses the birth date and the other updates the name and last name taken from a third table.
The one that uses the birthday to update the age field runs all over the table, and the one that updates the names and last name only updates the rows that appear on the third table based on a key.
So I launched both and got deadlocked! Is there a way to prioritize any of them? I read about the nowait and skip locked for the update but then, how would I return to the ones skipped?
Hope you can help me on this!!
One possibility is to lock all rows you will update at once. Doing all updates in a single update statment will accomplish this. Or
select whatever from T
where ...
for update;
Another solution is to create what I call a "Gatekeeper" table. Both procedures need to lock the Gatekeeper table in exclusive mode before updating the table in question. The second procedure will block until the first commits but won't deadlock. In 11g you can create a table with no space allocated.
A variation is to insert a row in the Gatekeeper. Then lock only that row with select for update. Then you can use the Gatekeeper in other situations.
I would guess that you got locked because the update for all the rows and the update for a small set of rows accessed rows in different orders.
The former used a full scan and reached Raw A first, then went on to other rows, eventually trying to lock Row B. However, the other query was driven from an index or a join and already had Row B locked, and was off to lock Row A when it found it was already locked.
So, the fix: firstly, having an age column that needs to be constantly modified is a really bad idea. Perhaps it was done to allow indexing of age, but with a correctly written query an index on date of birth will let you find the same records just as quickly. You've broken normalisation rules and ended up coding yourself a deadlocking application. Hopefully you are only updating the rows that need to be updated, not all of them regardless -- I mean, that would just be insane.
The best solution is to get rid of that design flaw.
The not so good solution is to deconflict your queries by running them at different times or by using DBMS_Lock so that only one of them can run at any time.

Resources