Serializable or For Update
Robert C, December 27, 2007 - 7:37 am UTC
Hi Tom,
Thanks for the great response. I'm a firm advocate of the third option and use it extensively in my designs, where necessary of course.
Would I be correct to say that in the case of options one and two mentioned above, the serializable isolation level would be insufficient to enforce these rules, and only the use of For Update can correctly ensure integrity.
Also, is it true that in Oracle, unlike SQL Server, if you update a subset of, or insert a new set of rows using a single column condition, and where no index exists on the column, Oracle will still only acquire a row level lock?
For example:
Session A
SQL> create table test (id number);
Table created.
SQL> insert into test values (1);
1 row created.
SQL> insert into test values (4);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test for update;
ID
----------
1
4
Using a new connection, Session 2, (SQL Plus Session 1 is still connected):
SQL> select * from test;
ID
----------
1
4
If I were to try to update one of these two rows, I would be blocked by Session 1 as expected. However, my initial thoughts were that I would still be blocked if I were to attempt to insert rows into this table, as there are no indexes present with which Oracle can use to acquire a key range lock. It appears though, that I can indeed continue to insert new rows from session 2:
SQL> insert into test values (2);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test;
ID
----------
1
4
2
We now continue in Session 1:
SQL> commit;
Commit complete.
SQL> select * from test;
ID
----------
1
4
2
Does Oracle lock at the row level in all such situations. I ask because I've come from using SQL Server for a few years, where the following situation does occur:
SQL Server
Session 1:
// New table, no rows, and no other connections at this time
Insert into test values (1);
Session 2:
Insert into test values (2);
The result would be Session 2 is blocked by Session 1.
Thanks Tom
December 27, 2007 - 9:48 am UTC
... Would I be correct to say that in the case of options one and two mentioned
above, the serializable isolation level would be insufficient to enforce these
rules, and only the use of For Update can correctly ensure integrity. ...
correct that serializable is insufficient.
more correct to say that LOCK TABLE is typically called for.
we are not sql server, we do not suffer from their locking issues.
You would only be blocked from inserting in the even of a duplicate UNIQUE value.
eg:
create table t (x int primary key, y int );
session 1: insert into t values ( 1, 1 );
session 2: insert into t values ( 2, 2 ); <<=== no problem
session 2: insert into t values ( 1, 1 ); <<=== this'll block on session 1 tho
Without an index...
Robert C, December 27, 2007 - 6:25 pm UTC
I had always understood Oracle (SQL Server also behaves in this way) to allow concurrent inserts into a table if an index is available. I'm curious to whether this is possible without an index, as in my example above.
Without an Index
create table test (x int, y int).
SQL Server
Session1: Insert test values (1,1)
Session2: Insert test values (2, 2) // That'll be blocked by
Oracle (From my example above)
Session1: Insert into test values (1, 1)
Session2: Insert into test values (2, 2) // No Issue
Witho an Index
create table test (x int primary key , y int).
SQL Server
Session1: Insert test values (1,1)
Session2: Insert test values (2, 2) // This will succeed
Oracle (From my example above)
Session1: Insert into test values (1, 1)
Session2: Insert into test values (2, 2) // This will succeed
I'd just like to ensure that I understand how Oracle will behave in this situation when there is no index available. To relate my question to a real world example, in my previous role there was the requirement to lock a range of values (from a foreign key column) while some calculations were being performed. The range (not rows) had to be locked as there was the possibility that the transaction would insert new rows into the range based on the results of the calculations.
Eg. SQL Server
create table myTable (x int primary key, y int foreign key myLookup (id))
insert into myLookUp values (1)
insert into myLookUp values (2)
insert into myTable values (1, 1)
insert into myTable values (2, 1)
insert into myTable values (3, 2)
insert into myTable values (4, 2)
Now, in Session One we wish to lock the range of rows (and prevent any inserts of new rows) for the foreign key values of 1 for column Y in myTable. In SQL Server can accomplish this using the serializable transaction level:
Session1: set transaction isolation level serializable
Session1: select * from myTable where y = 1
Session2: insert into myTable values (5, 2) // Insert succeeds
Session2: Insert into myTable values (5, 1) // Blocked by the range lock held by Session1.
Session1: Performs various calculations on myTable and then decides to insert the following row.
Session1: Insert into myTable values (5, 1) // Succeeds.
In Oracle, how can I achieve this same type of lock? Ie, only lock on the range of 1 for the y column. In SQL Server, if I were to remove the unique index from myLookUp, then in the above scenario, SQL Server would lock the entire myTable table.
Thanks,
December 28, 2007 - 3:34 pm UTC
regardless of an index - oracle has pretty much always allowed for concurrent insert
the only time this would not be true is when you have a UNIQUE constraint (primary key, unique index) in place - then two sessions might serialize upon attempting to insert the same value.
and in sqlserver, I believe back in the days of page level locking, you needed a clustered index to sometimes permit concurrent inserts. To spread the data around so the inserts did not go after the same block
Code for locks? Against an Oracle databasse?
Chuck Jolley, December 27, 2007 - 9:20 pm UTC
To quote Yoda: You must unlearn what you have learned.
I have been programming against Oracle for 9 years and in that time I have not coded one single lock, not even a select for update.
Not one single time in hundreds of thousands of lines of code.
There is about a 99.99% chance you can simply forget about locks.
Unless you have some awfully bizarre business rules this will simply not be an issue.
I'm sure Tom will give you examples and such, but really, the table will look to each session just the way you would intuitively expect it to.
December 28, 2007 - 3:35 pm UTC
you have to think about 'locks' when you have lost update possibilities.
search this site for 'lost update' for more discussion
To the above poster...
Robert C, December 27, 2007 - 10:01 pm UTC
To the above poster: Of course I'm not against using a database for locking. The essence of my message was to correctly understand the locking behaviour of the Oracle database in certain situations to determine whether or not explicit locking is necessary.
Coming from an SQL Server background and with a solid understanding of database theory, I merely wish to ensure that my understanding of Oracle's implementation of database transactions is correct. With such an understand, I will be able to ensure that my decisions are correct and are based on fact rather than the risk of misunderstanding.
As you will know, Oracle writers are not blocked by readers, as is the case with SQL Server. Hence, transactions need to be developed differently to address this difference. It is this very difference that I'm trying to clarify here with my questions.
With respect to your claim that the select for update clause is seldom used in reality, I will have to strongly disagree with you here, based on common sense and experience. In the case of the former, I find it impossible to comprehend that the select for update clause is used as the exception. If you expect two rows to modify the same subset of rows, the select for update clause should be used.
Consider the overlapping date problem rule, or any such transactions that requires an insert to be based wholly on the contents of the set to which the insert will be made. If the select for update clause were not to be implemented in this case, the following could occur:
Session1: Select data to read (no overlap exists)
Session2: Select data to read (because session2 will not be blocked by other transactions, it also does not detect an overlap)
Session1: Proceeds to insert a row
Session2: Proceeds to insert a row
After both transactions have committed, we will find that the rule has, in fact, been violated. Now in order to avoid this situation, the select for update clause must be used.
For another example, please see my above question.
Of course as with any discussion, my claimed understanding may be incorrect, and it is for the presence of this possibility that I am asking these very questions.
December 28, 2007 - 3:37 pm UTC
...
Consider the overlapping date problem rule, or any such transactions that
requires an insert to be based wholly on the contents of the set to which the
insert will be made. If the select for update clause were not to be implemented
in this case, the following could occur:
...
ah - but - you cannot lock that which you cannot see. You need to either lock the table OR lock a row in a parent table for this overlapping date issue (this is the example I used in my last book expert oracle database architecture in fact!)
To the above poster (2)
Robert C, December 27, 2007 - 10:07 pm UTC
I also forgot to ask: Did you read Tom's reply to my first follow up, in which he quite clearly points out that explicit locking is in fact required to enforce certain rules.
I'm really struggling to understand your view here.
December 28, 2007 - 3:37 pm UTC
explicit locking is needed in many real world cases - be is pessimistic (select for update) or optimistic (use a timestamp, ora_rowscn or something similar)
yes.
Taking the piss?
Robert C, December 27, 2007 - 10:11 pm UTC
To the above poster:
You say, quote:
I have been programming against Oracle for 9 years and in that time I have not coded one single
lock, not even a select for update.
Not one single time in hundreds of thousands of lines of code.
There is about a 99.99% chance you can simply forget about locks.
end quote
Ah.. It has only just occurred to me that your above quote was said in jest. For to suggest that one can simply just "forget about locks" would be grossly irresponsible.
Possible to edit your comments before a followup has been posted?
Robert C, December 28, 2007 - 1:54 am UTC
Just a very important point I need to clarify, for I didn't explain it very clearly earlier. When I mentioned that SQL Server can lock a range of values, I actually meant to say that SQL Server can prevent an insert into a range of values if the query includes a predicate that specifies a foreign key value.
Apologies for the confusion.
Tom,
What is your view on extending the functionality of AskTom to enable users to make amendments to their follow ups to a question?
December 28, 2007 - 3:38 pm UTC
since I don't have you "login", it would not really be feasible.
and I don't want to make you "login"
Not Kidding
Chuck Jolley, December 28, 2007 - 2:17 pm UTC
I wasn't kidding, I have never coded an explicit lock against an Oracle database.
I didn't mean you could generically "forget about locks"
But if you handle your transactions properly locking will not be something you spend much time worrying about in an Oracle database.
December 28, 2007 - 3:51 pm UTC
well, truth be told, I sort of disagree - especially in a stateless web environment... Lost updates abound.
Stateless programming - Yech
Chuck Jolley, December 28, 2007 - 4:07 pm UTC
There is that.
We only have a couple of small web interfaces to our database and collisions are not in the cards there simply because of the business rules, ie there is nothing to collide.
So I haven't had to deal with that problem.
January 01, 2008 - 5:24 pm UTC
and if you use something like APEX - you don't have to - it does the optimistic concurrency control for you.
But I would say "stateless - not yech - but the way it is"
asktom is totally stateless from a database connection perspective, but we use APEX to manage and maintain the state for us.
Editing the posts
Radhakrishna, February 14, 2008 - 3:58 am UTC
since I don't have you "login", it would not really be feasible.
and I don't want to make you "login"
Tom - First line is fine, but for the second line, any reason for not wanting to have a login?
Thanks
Radhakrishna
February 14, 2008 - 9:29 am UTC
because it would be ANNOYING for you
and it would bug the #@%#@%#@ out of me as people email me with "i cannot log in, i forgot my name, i forgot my password, ....."
A reader, February 14, 2008 - 10:21 am UTC
"because it would be ANNOYING for you
and it would bug the #@%#@%#@ out of me as people email me with "i cannot log in, i forgot my name, i forgot my password, ....."
.. I know it's extra work, but these tasks can be automated without your interference
I think what I would like to see is advance notice on the home page that 'Tom may accept new question on so & so date at this time for x minutes...' because many time we have new question for you but we end-up posting in one of your follow-up because of lack of access to new question sets.
Robert C, February 15, 2008 - 4:05 am UTC
Many years ago when I was young (I'm 25 now), I almost invariably found the ask a question process unavailable. Living in Brisbane at the time however, I did have the time differences against me.
Over Christmas and the New Year of 2007 / 2008 I found that the option to ask a question was frequently available. Perhaps you just need to visit the site during a festive period?
February 15, 2008 - 8:09 am UTC
or a period of time when I'm not traveling so much :)
Internet Cafe at the Airport
Robert, February 20, 2008 - 7:53 am UTC
Tom,
Could you not log onto AskTom from one of the Internet Cafes at the Airport?