Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 6 ■ LOCKING AND LATCHING 205 ops$tkyte@ORA10G> insert into p values ( 2 ); 1 row created. ops$tkyte@ORA10G> commit; Commit complete. and then we execute the following: ops$tkyte@ORA10G> insert into c values ( 2 ); 1 row created. nothing untoward happens yet. But if we go into another session and attempt to delete the first parent record ops$tkyte@ORA10G> delete from p where x = 1; we’ll find that session gets immediately blocked. It is attempting to gain a full table lock on table C before it does the delete. Now no other session can initiate a DELETE, INSERT, or UPDATE of any rows in C (the sessions that had already started may continue, but no new sessions may start to modify C). This blocking would happen with an update of the primary key value as well. Because updating a primary key is a huge no-no in a relational database, this is generally not an issue with updates. Where I have seen this updating of the primary key become a serious issue is when developers use tools that generate SQL for them, and those tools update every single column, regardless of whether the end user actually modified that column or not. For example, say that we use Oracle Forms and create a default layout on any table. Oracle Forms by default will generate an update that modifies every single column in the table we choose to display. If we build a default layout on the DEPT table and include all three fields, Oracle Forms will execute the following command whenever we modify any of the columns of the DEPT table: update dept set deptno=:1,dname=:2,loc=:3 where rowid=:4 In this case, if the EMP table has a foreign key to DEPT and there is no index on the DEPTNO column in the EMP table, then the entire EMP table will be locked during an update to DEPT. This is something to watch out for carefully if you are using any tools that generate SQL for you. Even though the value of the primary key does not change, the child table EMP will be locked after the execution of the preceding SQL statement. In the case of Oracle Forms, the solution is to set that table’s UPDATE CHANGED COLUMNS ONLY property to YES. Oracle Forms will generate an UPDATE statement that includes only the changed columns (not the primary key). Problems arising from deletion of a row in a parent table are far more common. As I demonstrated, if I delete a row in table P, then the child table, C, will become locked during the DML operation, thus preventing other updates against C from taking place for the duration of the transaction (assuming no one else was modifying C, of course; in which case the delete will wait). This is where the blocking and deadlock issues come in. By locking the entire table C, I have seriously decreased the concurrency in my database to the point where no one will be able to modify anything in C. In addition, I have increased the probability of a deadlock, since I now “own” lots of data until I commit. The probability that some other session will become blocked on C is now much higher; any session that tries to modify C will get blocked. Therefore, I’ll start seeing lots of sessions that hold some preexisting locks on other resources getting
206 CHAPTER 6 ■ LOCKING AND LATCHING blocked in the database. If any of these blocked sessions are, in fact, locking a resource that my session also needs, we will have a deadlock. The deadlock in this case is caused by my session preventing access to many more resources (in this case, all of the rows in a single table) than it ever needed. When someone complains of deadlocks in the database, I have them run a script that finds unindexed foreign keys, and 99 percent of the time we locate an offending table. By simply indexing that foreign key, the deadlocks—and lots of other contention issues—go away. The following example demonstrates the use of this script to locate the unindexed foreign key in table C: ops$tkyte@ORA10G> column columns format a30 word_wrapped ops$tkyte@ORA10G> column tablename format a15 word_wrapped ops$tkyte@ORA10G> column constraint_name format a15 word_wrapped ops$tkyte@ORA10G> select table_name, constraint_name, 2 cname1 || nvl2(cname2,','||cname2,null) || 3 nvl2(cname3,','||cname3,null) || nvl2(cname4,','||cname4,null) || 4 nvl2(cname5,','||cname5,null) || nvl2(cname6,','||cname6,null) || 5 nvl2(cname7,','||cname7,null) || nvl2(cname8,','||cname8,null) 6 columns 7 from ( select b.table_name, 8 b.constraint_name, 9 max(decode( position, 1, column_name, null )) cname1, 10 max(decode( position, 2, column_name, null )) cname2, 11 max(decode( position, 3, column_name, null )) cname3, 12 max(decode( position, 4, column_name, null )) cname4, 13 max(decode( position, 5, column_name, null )) cname5, 14 max(decode( position, 6, column_name, null )) cname6, 15 max(decode( position, 7, column_name, null )) cname7, 16 max(decode( position, 8, column_name, null )) cname8, 17 count(*) col_cnt 18 from (select substr(table_name,1,30) table_name, 19 substr(constraint_name,1,30) constraint_name, 20 substr(column_name,1,30) column_name, 21 position 22 from user_cons_columns ) a, 23 user_constraints b 24 where a.constraint_name = b.constraint_name 25 and b.constraint_type = 'R' 26 group by b.table_name, b.constraint_name 27 ) cons 28 where col_cnt > ALL 29 ( select count(*) 30 from user_ind_columns i 31 where i.table_name = cons.table_name 32 and i.column_name in (cname1, cname2, cname3, cname4, 33 cname5, cname6, cname7, cname8 )
- Page 200 and 201: CHAPTER 5 ■ ■ ■ Oracle Proces
- Page 202 and 203: CHAPTER 5 ■ ORACLE PROCESSES 157
- Page 204 and 205: CHAPTER 5 ■ ORACLE PROCESSES 159
- Page 206 and 207: CHAPTER 5 ■ ORACLE PROCESSES 161
- Page 208 and 209: CHAPTER 5 ■ ORACLE PROCESSES 163
- Page 210 and 211: CHAPTER 5 ■ ORACLE PROCESSES 165
- Page 212 and 213: CHAPTER 5 ■ ORACLE PROCESSES 167
- Page 214 and 215: CHAPTER 5 ■ ORACLE PROCESSES 169
- Page 216 and 217: CHAPTER 5 ■ ORACLE PROCESSES 171
- Page 218 and 219: CHAPTER 5 ■ ORACLE PROCESSES 173
- Page 220 and 221: CHAPTER 5 ■ ORACLE PROCESSES 175
- Page 222 and 223: CHAPTER 5 ■ ORACLE PROCESSES 177
- Page 224 and 225: CHAPTER 5 ■ ORACLE PROCESSES 179
- Page 226 and 227: CHAPTER 5 ■ ORACLE PROCESSES 181
- Page 228 and 229: CHAPTER 6 ■ ■ ■ Locking and L
- Page 230 and 231: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 232 and 233: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 234 and 235: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 236 and 237: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 238 and 239: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 240 and 241: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 242 and 243: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 244 and 245: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 246 and 247: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 248 and 249: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 252 and 253: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 254 and 255: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 256 and 257: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 258 and 259: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 260 and 261: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 262 and 263: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 264 and 265: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 266 and 267: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 268 and 269: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 270 and 271: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 272 and 273: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 274 and 275: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 276 and 277: CHAPTER 7 ■ ■ ■ Concurrency a
- Page 278 and 279: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 280 and 281: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 282 and 283: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 284 and 285: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 286 and 287: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 288 and 289: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 290 and 291: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 292 and 293: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 294 and 295: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 296 and 297: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 298 and 299: CHAPTER 7 ■ CONCURRENCY AND MULTI
CHAPTER 6 ■ LOCKING AND LATCHING 205<br />
ops$tkyte@ORA10G> insert into p values ( 2 );<br />
1 row created.<br />
ops$tkyte@ORA10G> commit;<br />
Commit complete.<br />
<strong>and</strong> then we execute the following:<br />
ops$tkyte@ORA10G> insert into c values ( 2 );<br />
1 row created.<br />
nothing untoward happens yet. But if we go into another session <strong>and</strong> attempt to delete the<br />
first parent record<br />
ops$tkyte@ORA10G> delete from p where x = 1;<br />
we’ll find that session gets immediately blocked. It is attempting to gain a full table lock on<br />
table C before it does the delete. Now no other session can initiate a DELETE, INSERT, or UPDATE<br />
of any rows in C (the sessions that had already started may continue, but no new sessions may<br />
start to modify C).<br />
This blocking would happen with an update of the primary key value as well. Because<br />
updating a primary key is a huge no-no in a relational database, this is generally not an issue<br />
with updates. Where I have seen this updating of the primary key become a serious issue is<br />
when developers use tools that generate SQL for them, <strong>and</strong> those tools update every single<br />
column, regardless of whether the end user actually modified that column or not. For example,<br />
say that we use <strong>Oracle</strong> Forms <strong>and</strong> create a default layout on any table. <strong>Oracle</strong> Forms by<br />
default will generate an update that modifies every single column in the table we choose to<br />
display. If we build a default layout on the DEPT table <strong>and</strong> include all three fields, <strong>Oracle</strong> Forms<br />
will execute the following comm<strong>and</strong> whenever we modify any of the columns of the DEPT<br />
table:<br />
update dept set deptno=:1,dname=:2,loc=:3 where rowid=:4<br />
In this case, if the EMP table has a foreign key to DEPT <strong>and</strong> there is no index on the DEPTNO<br />
column in the EMP table, then the entire EMP table will be locked during an update to DEPT. This<br />
is something to watch out for carefully if you are using any tools that generate SQL for you.<br />
Even though the value of the primary key does not change, the child table EMP will be locked<br />
after the execution of the preceding SQL statement. In the case of <strong>Oracle</strong> Forms, the solution<br />
is to set that table’s UPDATE CHANGED COLUMNS ONLY property to YES. <strong>Oracle</strong> Forms will generate<br />
an UPDATE statement that includes only the changed columns (not the primary key).<br />
Problems arising from deletion of a row in a parent table are far more common. As I<br />
demonstrated, if I delete a row in table P, then the child table, C, will become locked during the<br />
DML operation, thus preventing other updates against C from taking place for the duration of<br />
the transaction (assuming no one else was modifying C, of course; in which case the delete will<br />
wait). This is where the blocking <strong>and</strong> deadlock issues come in. By locking the entire table C,<br />
I have seriously decreased the concurrency in my database to the point where no one will be<br />
able to modify anything in C. In addition, I have increased the probability of a deadlock, since<br />
I now “own” lots of data until I commit. The probability that some other session will become<br />
blocked on C is now much higher; any session that tries to modify C will get blocked. Therefore,<br />
I’ll start seeing lots of sessions that hold some preexisting locks on other resources getting