<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
		>
<channel>
	<title>Comments on: Select For Update &#8211; In What Order are the Rows Locked?</title>
	<atom:link href="http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/feed/" rel="self" type="application/rss+xml" />
	<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/</link>
	<description>Miscellaneous Random Oracle Topics: Stop, Think, ... Understand</description>
	<lastBuildDate>Thu, 23 May 2013 04:02:42 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
	<item>
		<title>By: How to avoid database deadlocks? &#124; BlogoSfera</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-5481</link>
		<dc:creator><![CDATA[How to avoid database deadlocks? &#124; BlogoSfera]]></dc:creator>
		<pubDate>Thu, 23 May 2013 04:02:42 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-5481</guid>
		<description><![CDATA[[&#8230;] to deadlocks because the database does not specify what locking order will be used. I found two discussions that hint that this behavior isn&#8217;t specified by the SQL standard, not to mention [&#8230;]]]></description>
		<content:encoded><![CDATA[<p>[&#8230;] to deadlocks because the database does not specify what locking order will be used. I found two discussions that hint that this behavior isn&#8217;t specified by the SQL standard, not to mention [&#8230;]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Dom Brooks</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4093</link>
		<dc:creator><![CDATA[Dom Brooks]]></dc:creator>
		<pubDate>Thu, 24 Nov 2011 17:00:14 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4093</guid>
		<description><![CDATA[Interesting observation. I set out to do the same but got distracted by what I should have been doing in the first place ;-)]]></description>
		<content:encoded><![CDATA[<p>Interesting observation. I set out to do the same but got distracted by what I should have been doing in the first place <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4091</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Thu, 24 Nov 2011 13:38:02 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4091</guid>
		<description><![CDATA[Dom,

Nice solution!  I don&#039;t think that I would have come up with that solution if I continued to work on this problem.

Let&#039;s test with 2 sessions to see what happens.
Session 1:
&lt;pre&gt;
select t1.c1
from   (select rowid rd
        from   t1
        order  by c1 asc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.c1;
 
  C1
----
   1
   2
   3
   4
   5
&lt;/pre&gt;
That worked.

Session 2:
&lt;pre&gt;
SET AUTOTRACE ON
 
select t1.c1
from   (select rowid rd
        from   t1
        order  by c1 desc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.c1;
 
   C1
-----
10000
 9999
 9998
 9997
 9996
 
Execution Plan
----------------------------------------------------------
Plan hash value: 3858600555
 
---------------------------------------------------------------------------------------
&#124; Id  &#124; Operation                      &#124; Name &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
---------------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT               &#124;      &#124;     5 &#124;   185 &#124;     6   (0)&#124; 00:00:01 &#124;
&#124;   1 &#124;  FOR UPDATE                    &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;   2 &#124;   BUFFER SORT                  &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;*  3 &#124;    COUNT STOPKEY               &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;   4 &#124;     NESTED LOOPS               &#124;      &#124;     5 &#124;   185 &#124;     6   (0)&#124; 00:00:01 &#124;
&#124;   5 &#124;      VIEW                      &#124;      &#124; 11610 &#124;   136K&#124;     1   (0)&#124; 00:00:01 &#124;
&#124;   6 &#124;       SORT ORDER BY            &#124;      &#124; 11610 &#124;   283K&#124;   147  (11)&#124; 00:00:01 &#124;
&#124;   7 &#124;        TABLE ACCESS FULL       &#124; T1   &#124; 11610 &#124;   283K&#124;   137   (5)&#124; 00:00:01 &#124;
&#124;   8 &#124;      TABLE ACCESS BY USER ROWID&#124; T1   &#124;     1 &#124;    25 &#124;     1   (0)&#124; 00:00:01 &#124;
---------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(ROWNUM&lt;=5)
 
Note
-----
   - dynamic sampling used for this statement (level=2)
&lt;/pre&gt;
That also worked, and without Session 1 blocking Session 2.

I started wondering if there could not be a hidden problem... if the order of the rows within the &quot;Top 5&quot; really is important, are we actually relying on an implicit sort order?  Let&#039;s test.
Session 2:
&lt;pre&gt;
select /*+ LEADING(T1) */ t1.c1
from   (select rowid rd
        from   t1
        order  by c1 desc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.c1;
 
   C1
-----
10000
 9999
 9998
 9997
 9996
 
Execution Plan
----------------------------------------------------------
Plan hash value: 397963150
 
--------------------------------------------------------------------------------
&#124; Id  &#124; Operation               &#124; Name &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
--------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT        &#124;      &#124;     5 &#124;   185 &#124;   288  (10)&#124; 00:00:01 &#124;
&#124;   1 &#124;  FOR UPDATE             &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;   2 &#124;   BUFFER SORT           &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;*  3 &#124;    COUNT STOPKEY        &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;*  4 &#124;     HASH JOIN           &#124;      &#124; 11610 &#124;   419K&#124;   288  (10)&#124; 00:00:01 &#124;
&#124;   5 &#124;      TABLE ACCESS FULL  &#124; T1   &#124; 11610 &#124;   283K&#124;   137   (5)&#124; 00:00:01 &#124;
&#124;   6 &#124;      VIEW               &#124;      &#124; 11610 &#124;   136K&#124;   147  (11)&#124; 00:00:01 &#124;
&#124;   7 &#124;       SORT ORDER BY     &#124;      &#124; 11610 &#124;   283K&#124;   147  (11)&#124; 00:00:01 &#124;
&#124;   8 &#124;        TABLE ACCESS FULL&#124; T1   &#124; 11610 &#124;   283K&#124;   137   (5)&#124; 00:00:01 &#124;
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(ROWNUM&lt;=5)
   4 - access(&quot;T1&quot;.ROWID=&quot;X&quot;.&quot;RD&quot;)
 
Note
-----
   - dynamic sampling used for this statement (level=2)
&lt;/pre&gt;
The expected rows were still returned in the expected sort order - interesting.  However, notice that the Nested Loops operation changed to a Hash Join - might this still be a problem?

One more try without a LEADING hint, but changing the inline view to retrieve the top 9,999 rows sorted in descending order.
Session 2:
&lt;pre&gt;
select t1.c1
from   (select rowid rd
        from   t1
        order  by c1 desc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 9999
for update of t1.c1;
 
    C1
------
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
...
  9994
  9995
  9996
  9997
  9998
  9999
 
9999 rows selected.
 
Execution Plan
----------------------------------------------------------
Plan hash value: 4115059001

--------------------------------------------------------------------------------
&#124; Id  &#124; Operation               &#124; Name &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
--------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT        &#124;      &#124;  9999 &#124;   605K&#124;   269  (10)&#124; 00:00:01 &#124;
&#124;   1 &#124;  FOR UPDATE             &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;   2 &#124;   BUFFER SORT           &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;*  3 &#124;    COUNT STOPKEY        &#124;      &#124;       &#124;       &#124;            &#124;          &#124;
&#124;*  4 &#124;     HASH JOIN           &#124;      &#124; 11610 &#124;   702K&#124;   269  (10)&#124; 00:00:01 &#124;
&#124;   5 &#124;      VIEW               &#124;      &#124; 11610 &#124;   136K&#124;   147  (11)&#124; 00:00:01 &#124;
&#124;   6 &#124;       SORT ORDER BY     &#124;      &#124; 11610 &#124;   283K&#124;   147  (11)&#124; 00:00:01 &#124;
&#124;   7 &#124;        TABLE ACCESS FULL&#124; T1   &#124; 11610 &#124;   283K&#124;   137   (5)&#124; 00:00:01 &#124;
&#124;   8 &#124;      TABLE ACCESS FULL  &#124; T1   &#124; 11610 &#124;   283K&#124;   118   (5)&#124; 00:00:01 &#124;
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(ROWNUM&lt;=9999)
   4 - access(&quot;T1&quot;.ROWID=&quot;X&quot;.&quot;RD&quot;)
 
Note
-----
   - dynamic sampling used for this statement (level=2)
&lt;/pre&gt;
I don&#039;t know if that qualifies as a bug in Oracle Database, but not only is the order not in descending order, but we lost the row with C1 value 10000 - we ended up with the *bottom* 9,999 rather than the *top* 9,999.

I think that your suggestion is still a very good one.]]></description>
		<content:encoded><![CDATA[<p>Dom,</p>
<p>Nice solution!  I don&#8217;t think that I would have come up with that solution if I continued to work on this problem.</p>
<p>Let&#8217;s test with 2 sessions to see what happens.<br />
Session 1:</p>
<pre>
select t1.c1
from   (select rowid rd
        from   t1
        order  by c1 asc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.c1;
 
  C1
----
   1
   2
   3
   4
   5
</pre>
<p>That worked.</p>
<p>Session 2:</p>
<pre>
SET AUTOTRACE ON
 
select t1.c1
from   (select rowid rd
        from   t1
        order  by c1 desc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.c1;
 
   C1
-----
10000
 9999
 9998
 9997
 9996
 
Execution Plan
----------------------------------------------------------
Plan hash value: 3858600555
 
---------------------------------------------------------------------------------------
| Id  | Operation                      | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |      |     5 |   185 |     6   (0)| 00:00:01 |
|   1 |  FOR UPDATE                    |      |       |       |            |          |
|   2 |   BUFFER SORT                  |      |       |       |            |          |
|*  3 |    COUNT STOPKEY               |      |       |       |            |          |
|   4 |     NESTED LOOPS               |      |     5 |   185 |     6   (0)| 00:00:01 |
|   5 |      VIEW                      |      | 11610 |   136K|     1   (0)| 00:00:01 |
|   6 |       SORT ORDER BY            |      | 11610 |   283K|   147  (11)| 00:00:01 |
|   7 |        TABLE ACCESS FULL       | T1   | 11610 |   283K|   137   (5)| 00:00:01 |
|   8 |      TABLE ACCESS BY USER ROWID| T1   |     1 |    25 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(ROWNUM&lt;=5)
 
Note
-----
   - dynamic sampling used for this statement (level=2)
</pre>
<p>That also worked, and without Session 1 blocking Session 2.</p>
<p>I started wondering if there could not be a hidden problem&#8230; if the order of the rows within the &#8220;Top 5&#8243; really is important, are we actually relying on an implicit sort order?  Let&#8217;s test.<br />
Session 2:</p>
<pre>
select /*+ LEADING(T1) */ t1.c1
from   (select rowid rd
        from   t1
        order  by c1 desc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.c1;
 
   C1
-----
10000
 9999
 9998
 9997
 9996
 
Execution Plan
----------------------------------------------------------
Plan hash value: 397963150
 
--------------------------------------------------------------------------------
| Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |     5 |   185 |   288  (10)| 00:00:01 |
|   1 |  FOR UPDATE             |      |       |       |            |          |
|   2 |   BUFFER SORT           |      |       |       |            |          |
|*  3 |    COUNT STOPKEY        |      |       |       |            |          |
|*  4 |     HASH JOIN           |      | 11610 |   419K|   288  (10)| 00:00:01 |
|   5 |      TABLE ACCESS FULL  | T1   | 11610 |   283K|   137   (5)| 00:00:01 |
|   6 |      VIEW               |      | 11610 |   136K|   147  (11)| 00:00:01 |
|   7 |       SORT ORDER BY     |      | 11610 |   283K|   147  (11)| 00:00:01 |
|   8 |        TABLE ACCESS FULL| T1   | 11610 |   283K|   137   (5)| 00:00:01 |
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(ROWNUM&lt;=5)
   4 - access("T1".ROWID="X"."RD")
 
Note
-----
   - dynamic sampling used for this statement (level=2)
</pre>
<p>The expected rows were still returned in the expected sort order &#8211; interesting.  However, notice that the Nested Loops operation changed to a Hash Join &#8211; might this still be a problem?</p>
<p>One more try without a LEADING hint, but changing the inline view to retrieve the top 9,999 rows sorted in descending order.<br />
Session 2:</p>
<pre>
select t1.c1
from   (select rowid rd
        from   t1
        order  by c1 desc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 9999
for update of t1.c1;
 
    C1
------
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
...
  9994
  9995
  9996
  9997
  9998
  9999
 
9999 rows selected.
 
Execution Plan
----------------------------------------------------------
Plan hash value: 4115059001

--------------------------------------------------------------------------------
| Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |  9999 |   605K|   269  (10)| 00:00:01 |
|   1 |  FOR UPDATE             |      |       |       |            |          |
|   2 |   BUFFER SORT           |      |       |       |            |          |
|*  3 |    COUNT STOPKEY        |      |       |       |            |          |
|*  4 |     HASH JOIN           |      | 11610 |   702K|   269  (10)| 00:00:01 |
|   5 |      VIEW               |      | 11610 |   136K|   147  (11)| 00:00:01 |
|   6 |       SORT ORDER BY     |      | 11610 |   283K|   147  (11)| 00:00:01 |
|   7 |        TABLE ACCESS FULL| T1   | 11610 |   283K|   137   (5)| 00:00:01 |
|   8 |      TABLE ACCESS FULL  | T1   | 11610 |   283K|   118   (5)| 00:00:01 |
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(ROWNUM&lt;=9999)
   4 - access("T1".ROWID="X"."RD")
 
Note
-----
   - dynamic sampling used for this statement (level=2)
</pre>
<p>I don&#8217;t know if that qualifies as a bug in Oracle Database, but not only is the order not in descending order, but we lost the row with C1 value 10000 &#8211; we ended up with the *bottom* 9,999 rather than the *top* 9,999.</p>
<p>I think that your suggestion is still a very good one.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Dom Brooks</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4090</link>
		<dc:creator><![CDATA[Dom Brooks]]></dc:creator>
		<pubDate>Thu, 24 Nov 2011 09:05:49 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4090</guid>
		<description><![CDATA[Like this?

[code]
select t1.col1
from   (select rowid rd
        from   t1
        order  by col1 asc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.col1;
[/code]]]></description>
		<content:encoded><![CDATA[<p>Like this?</p>
<pre class="brush: plain; title: ; notranslate">
select t1.col1
from   (select rowid rd
        from   t1
        order  by col1 asc) x
,      t1
where  t1.rowid = x.rd
and    rownum &lt;= 5
for update of t1.col1;
</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Mark W. Farnham</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4087</link>
		<dc:creator><![CDATA[Mark W. Farnham]]></dc:creator>
		<pubDate>Wed, 23 Nov 2011 13:40:28 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4087</guid>
		<description><![CDATA[An interesting thing about testing for deadlocks is that you can sometimes drive deadlocks with procedures consistently, but some other techniques are only prone to deadlocking, while yet others are not prone to deadlocking but may still be susceptible to deadlocks in certain race conditions under heavy load.

I think you were trying to demonstrate an easy way to show that if you don&#039;t pay attention to order it is trivial to get deadlocks. Don&#039;t be confident your pair of random updates won&#039;t ever deadlock because they didn&#039;t once. That just demotes your test to one that won&#039;t always deadlock. I suspect your earlier test had some additional wrinkle (or was on a different data set) if it consistently deadlocked.

Of course there are plenty of ways to intentionally generate deadlocks consistently. The goal of avoiding deadlocks is a bit trickier and Charles&#039; demonstration of a way to influence the order of locking as of current releases is useful toward that goal.

For now it seems a very useful technique. Like any other detail of current physical access method and order, it may change in the future. Unlike eschewing an order by in V5 when you had the matching group by because you knew order only had a sort based aggregation and it actually completely re-sorted the result set, Charles&#039; process won&#039;t break your query if the order of acquiring locks changes in the future due to some change in the access order. It will just lose its current positive effect on avoiding deadlocks. And while hash aggregation methods for group by were well understood computer science just waiting to reach a positive tradeoff for advantages versus cost of implementation and testing, acquiring locks in order when there is an order in place and supported by an index seems solid as long as parallel access methods are not considered. (And multiple threads of parallel DML against the same objects is just asking for trouble as far as deadlocks go. I suggest you either run one thread as parallel as you need or as many threads as you need each not parallel rather than multiple threads somewhat less in parallel.)]]></description>
		<content:encoded><![CDATA[<p>An interesting thing about testing for deadlocks is that you can sometimes drive deadlocks with procedures consistently, but some other techniques are only prone to deadlocking, while yet others are not prone to deadlocking but may still be susceptible to deadlocks in certain race conditions under heavy load.</p>
<p>I think you were trying to demonstrate an easy way to show that if you don&#8217;t pay attention to order it is trivial to get deadlocks. Don&#8217;t be confident your pair of random updates won&#8217;t ever deadlock because they didn&#8217;t once. That just demotes your test to one that won&#8217;t always deadlock. I suspect your earlier test had some additional wrinkle (or was on a different data set) if it consistently deadlocked.</p>
<p>Of course there are plenty of ways to intentionally generate deadlocks consistently. The goal of avoiding deadlocks is a bit trickier and Charles&#8217; demonstration of a way to influence the order of locking as of current releases is useful toward that goal.</p>
<p>For now it seems a very useful technique. Like any other detail of current physical access method and order, it may change in the future. Unlike eschewing an order by in V5 when you had the matching group by because you knew order only had a sort based aggregation and it actually completely re-sorted the result set, Charles&#8217; process won&#8217;t break your query if the order of acquiring locks changes in the future due to some change in the access order. It will just lose its current positive effect on avoiding deadlocks. And while hash aggregation methods for group by were well understood computer science just waiting to reach a positive tradeoff for advantages versus cost of implementation and testing, acquiring locks in order when there is an order in place and supported by an index seems solid as long as parallel access methods are not considered. (And multiple threads of parallel DML against the same objects is just asking for trouble as far as deadlocks go. I suggest you either run one thread as parallel as you need or as many threads as you need each not parallel rather than multiple threads somewhat less in parallel.)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Timur Akhmadeev</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4086</link>
		<dc:creator><![CDATA[Timur Akhmadeev]]></dc:creator>
		<pubDate>Wed, 23 Nov 2011 11:35:04 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4086</guid>
		<description><![CDATA[Charles,

I&#039;m referring to just a plain SELECT ... FOR UPDATE ORDER BY DBMS_RANDOM.VALUE. Some time ago I easily got deadlock in such a case with 2 sessions running the same statement. But I can&#039;t reproduce it now, so maybe I&#039;m wrong.]]></description>
		<content:encoded><![CDATA[<p>Charles,</p>
<p>I&#8217;m referring to just a plain SELECT &#8230; FOR UPDATE ORDER BY DBMS_RANDOM.VALUE. Some time ago I easily got deadlock in such a case with 2 sessions running the same statement. But I can&#8217;t reproduce it now, so maybe I&#8217;m wrong.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4085</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Tue, 22 Nov 2011 21:10:26 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4085</guid>
		<description><![CDATA[Mark,

Thank you for the compliment and the very useful comments related to avoiding deadlocks.

On an unrelated side note, I wondered how Oracle Database would handle a Top-N type query with a FOR UPDATE clause - would it have to revisit the table&#039;s blocks to lock just the rows that were to be returned, or would it lock all of the rows in the table as the rows were read from the blocks?  I adjusted the first SELECT FOR UPDATE query so that without the FOR UPDATE clause it would only return the first 5 rows when sorted by column C1.  I then added a FOR UPDATE clause:
&lt;pre&gt; 
SELECT
  *
FROM
  (SELECT
    C1,
    C2
  FROM
    T1
  WHERE
    MOD(C1,100)=0
  ORDER BY
    C1)
WHERE
  ROWNUM&lt;=5
FOR UPDATE;
 
  (SELECT
  *
ERROR at line 4:
ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
&lt;/pre&gt;

It looks like the programmers anticipated this particular problem, but that is a bit of an incorrect/vague error message description.]]></description>
		<content:encoded><![CDATA[<p>Mark,</p>
<p>Thank you for the compliment and the very useful comments related to avoiding deadlocks.</p>
<p>On an unrelated side note, I wondered how Oracle Database would handle a Top-N type query with a FOR UPDATE clause &#8211; would it have to revisit the table&#8217;s blocks to lock just the rows that were to be returned, or would it lock all of the rows in the table as the rows were read from the blocks?  I adjusted the first SELECT FOR UPDATE query so that without the FOR UPDATE clause it would only return the first 5 rows when sorted by column C1.  I then added a FOR UPDATE clause:</p>
<pre> 
SELECT
  *
FROM
  (SELECT
    C1,
    C2
  FROM
    T1
  WHERE
    MOD(C1,100)=0
  ORDER BY
    C1)
WHERE
  ROWNUM&lt;=5
FOR UPDATE;
 
  (SELECT
  *
ERROR at line 4:
ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
</pre>
<p>It looks like the programmers anticipated this particular problem, but that is a bit of an incorrect/vague error message description.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4084</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Tue, 22 Nov 2011 20:57:10 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4084</guid>
		<description><![CDATA[Timur,

I think that you have a good suggestion, but I am having trouble putting together a full picture of what you are suggesting (I have a feeling that your comment ties in with Mark&#039;s comment below).  Are you describing a situation where the resultset of a SQL statement like this:
&lt;pre&gt;
SELECT
  C1,
  C2
FROM
  T1
ORDER BY
  DBMS_RANDOM.VALUE;
&lt;/pre&gt;

(Note in the above that the FOR UPDATE clause is not specified.)  Would be used in a loop to update the rows one at a time in table T1?  I could see this arrangement resulting in a deadlock if two sessions perform the action at roughly the same time.  A related side note: if an ORDER BY clause is not specified, it could very well be the case that the rows for two sessions will be returned in different sort orders if the execution plans were not identical for the same SQL statement executed by the two sessions, and I suspect that could lead to the same problem described above with the ORDER BY DBMS_RANDOM.VALUE.

Please let me know if I completely missed the point.]]></description>
		<content:encoded><![CDATA[<p>Timur,</p>
<p>I think that you have a good suggestion, but I am having trouble putting together a full picture of what you are suggesting (I have a feeling that your comment ties in with Mark&#8217;s comment below).  Are you describing a situation where the resultset of a SQL statement like this:</p>
<pre>
SELECT
  C1,
  C2
FROM
  T1
ORDER BY
  DBMS_RANDOM.VALUE;
</pre>
<p>(Note in the above that the FOR UPDATE clause is not specified.)  Would be used in a loop to update the rows one at a time in table T1?  I could see this arrangement resulting in a deadlock if two sessions perform the action at roughly the same time.  A related side note: if an ORDER BY clause is not specified, it could very well be the case that the rows for two sessions will be returned in different sort orders if the execution plans were not identical for the same SQL statement executed by the two sessions, and I suspect that could lead to the same problem described above with the ORDER BY DBMS_RANDOM.VALUE.</p>
<p>Please let me know if I completely missed the point.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Mark W. Farnham</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4083</link>
		<dc:creator><![CDATA[Mark W. Farnham]]></dc:creator>
		<pubDate>Tue, 22 Nov 2011 14:45:41 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4083</guid>
		<description><![CDATA[a) brilliant and useful post
b) Additional reason why it is useful: A key strategy contributing to minimizing application driven deadlocks is defining an order of update across the organization. The first step in getting this right is to always have the tables in the same order in multistatement logical units of work. Getting the same order of update by rows is the next piece. While I *think* you can still get interdigitated sets of rows ultimately ending up in a deadlock because of range overlaps with different filters so you get different winners in the race for different rows, getting the locks in the same order within each table plus getting the tables in the same order will stamp out the vast majority of deadlocks pre-emptively.]]></description>
		<content:encoded><![CDATA[<p>a) brilliant and useful post<br />
b) Additional reason why it is useful: A key strategy contributing to minimizing application driven deadlocks is defining an order of update across the organization. The first step in getting this right is to always have the tables in the same order in multistatement logical units of work. Getting the same order of update by rows is the next piece. While I *think* you can still get interdigitated sets of rows ultimately ending up in a deadlock because of range overlaps with different filters so you get different winners in the race for different rows, getting the locks in the same order within each table plus getting the tables in the same order will stamp out the vast majority of deadlocks pre-emptively.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Timur Akhmadeev</title>
		<link>http://hoopercharles.wordpress.com/2011/11/21/select-for-update-in-what-order-are-the-rows-locked/#comment-4082</link>
		<dc:creator><![CDATA[Timur Akhmadeev]]></dc:creator>
		<pubDate>Tue, 22 Nov 2011 07:25:53 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5636#comment-4082</guid>
		<description><![CDATA[&lt;blockquote&gt;Any other ideas for a demonstration of the order in which rows are locked when a SELECT FOR UPDATE is used?&lt;/blockquote&gt;
Easiest way I know is to run two order by dbms_random.value for update statements; high chances are there&#039;ll be a deadlock.]]></description>
		<content:encoded><![CDATA[<blockquote><p>Any other ideas for a demonstration of the order in which rows are locked when a SELECT FOR UPDATE is used?</p></blockquote>
<p>Easiest way I know is to run two order by dbms_random.value for update statements; high chances are there&#8217;ll be a deadlock.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
