Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Gururaj.

Asked: June 21, 2001 - 9:52 am UTC

Last updated: March 07, 2024 - 4:14 pm UTC

Version: 8.X

Viewed 100K+ times! This question is

You Asked

Hi Tom,


Here are the few questions on Locking.

1)How do I use v$lock to figure out lock details ? Details like
whos has locked,on which table,who else is waiting, and what type
of locking (shared or exlusive ?), since when it is locked.

2)Why and when exclusive/shared locks are used ? Could you give me
example please ?

Thanks for the answer, I understand better.

3)Could you tell me significance of v$mystat and v$locked_object ?

Thank you .

4) Do we have page level locking in Oracle ?

Thank you


Thanks in advance,

Gururaj

and Tom said...

1) Here is a small example showing how this happens. We will use three V$ tables in order to see how this works; V$TRANSACTION, V$SESSION, and V$LOCK. V$TRANSACTION contains an entry for every active transaction. V$LOCK contains an entry for all locks held as well as locks being waited on. V$SESSION shows us the sessions logged in. We'll start by starting a transaction in one session and looking at the state of the system at that point:

tkyte@TKYTE816> update dept set deptno = deptno+10;
4 rows updated.

tkyte@TKYTE816> select username,
2 v$lock.sid,
3 trunc(id1/power(2,16)) rbs,
4 bitand(id1,to_number('ffff','xxxx'))+0 slot,
5 id2 seq,
6 lmode,
7 request
8 from v$lock, v$session
9 where v$lock.type = 'TX'
10 and v$lock.sid = v$session.sid
11 and v$session.username = USER
12 /

USERNAME SID RBS SLOT SEQ LMODE REQUEST
-------- ---------- ---------- ---------- ---------- ---------- ----------
TKYTE 8 2 46 160 6 0

tkyte@TKYTE816> select XIDUSN, XIDSLOT, XIDSQN
2 from v$transaction
3 /

XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
2 46 160

The interesting things to note here are:

ƒá The LMODE is 6 in the V$LOCK table and the request is 0. If you refer to the definition of the V$LOCK table in the Oracle Server Reference, you will find that LMODE=6 is an exclusive lock. A value of 0 in the request means we are not making a request ¡V we have the lock.
ć There is only one row in this table. This V$LOCK table is more of a queuing table than a lock table. Many people expect there would be four rows in V$LOCK since we have four rows locked. What you must remember however is that Oracle does not store a master list of every row locked anywhere. To find out if a row is locked, we must go to that row.
ć I took the ID1 and ID2 columns, and performed a bit of bit manipulation on them. Oracle needed to save three 16bit numbers, but only had two columns in order to do it. So, the first column ID1 holds two of these numbers. By dividing by 2^16 with trunc(id1/power(2,16)) rbs and by masking out the high bits with bitand(id1,to_number('ffff','xxxx'))+0 slot, I am able to get the two numbers that are hiding in that one number back out.
ć The RBS, SLOT, and SEQ values match the V$TRANSACTION information. This is my transaction ID.

Now I'll start another session using the same user name, update some rows in EMP, and then try to update DEPT:

tkyte@TKYTE816> update emp set ename = upper(ename);
14 rows updated.

tkyte@TKYTE816> update dept set deptno = deptno-10;


I am now blocked in this session. If we run the V$ queries again, we see:

tkyte@TKYTE816> select username,
2 v$lock.sid,
3 trunc(id1/power(2,16)) rbs,
4 bitand(id1,to_number('ffff','xxxx'))+0 slot,
5 id2 seq,
6 lmode,
7 request
8 from v$lock, v$session
9 where v$lock.type = 'TX'
10 and v$lock.sid = v$session.sid
11 and v$session.username = USER
12 /

USERNAME SID RBS SLOT SEQ LMODE REQUEST
-------- ---------- ---------- ---------- ---------- ---------- ----------
TKYTE 8 2 46 160 6 0
TKYTE 9 2 46 160 0 6
TKYTE 9 3 82 163 6 0

tkyte@TKYTE816> select XIDUSN, XIDSLOT, XIDSQN
2 from v$transaction
3 /

XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
3 82 163
2 46 160

What we see here is that a new transaction has begun ¡V (3,82,163) is the transaction ID. It has two rows in V$LOCK this time. One row represents the locks that it owns (where LMODE=6). It also has a row in there that shows a REQUEST with a value of 6. This is a request for an exclusive lock. The interesting thing to note here is that the RBS/SLOT/SEQ values of this request row are the transaction ID of the holder of the lock. We can easily see that the transaction with SID=8 is blocking the transaction with SID=9. Now, if we commit in SID = 8 the above changes:

tkyte@TKYTE816> select username,
2 v$lock.sid,
3 trunc(id1/power(2,16)) rbs,
4 bitand(id1,to_number('ffff','xxxx'))+0 slot,
5 id2 seq,
6 lmode,
7 request, block
8 from v$lock, v$session
9 where v$lock.type = 'TX'
10 and v$lock.sid = v$session.sid
11 and v$session.username = USER
12 /

USERNAME SID RBS SLOT SEQ LMODE REQUEST
-------- ---------- ---------- ---------- ---------- ---------- ----------
TKYTE 9 3 82 163 6 0

tkyte@TKYTE816> select XIDUSN, XIDSLOT, XIDSQN
2 from v$transaction
3 /

XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
3 82 163

that request row has gone ¡V it disappeared the instant the other session gave up its lock. That request row was the queuing mechanism. The database is able to wake up the blocked sessions the instant the transaction is completed. Note that the above gives us a very easy way to see blockers and waiters:

tkyte@TKYTE816> select
(select username from v$session where sid=a.sid) blocker,
2 a.sid,
3 ' is blocking ',
4 (select username from v$session where sid=b.sid) blockee,
5 b.sid
6 from v$lock a, v$lock b
7 where a.block = 1
8 and b.request > 0
9 and a.id1 = b.id1
10 and a.id2 = b.id2
11 /

BLOCKER SID 'ISBLOCKING' BLOCKEE SID
-------- ---------- ------------- -------- ----------
TKYTE 8 is blocking TKYTE 9

simply by doing a self-join of V$LOCK with itself (I ran this query before committing the session with SID=8).

2) exclusive lock -- I updated a row. no one else can update it until I commit. I have an X lock on that row and only one person at a time can have an X lock. an X lock provides serialization to a resource.

A shared lock -- when I update a table, I take a shared lock on the DEFINITION of the table. Everyone else can do that as well (more then one session can get a shared lock on the table definition). So, more than one person at a time can update the table. If you wanted to ALTER the table, you would need an X lock on the defintion. You cannot get an X lock when there are shared locks so you wait until there are no shared locks.

3) mystat has the statistics (cpu use, blocks read, cursors opened, etc) for your session only. v$locked_object shows you all of the locks in the system.

4) no, never.

Rating

  (450 ratings)

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

Comments

Locks and Blockers

Aslam Momin, July 12, 2001 - 11:53 am UTC

Hi Tom (and Team !!!),

Excellent answer.
Thanks for imparting the technical knowledge.

How can i find the name of the table

sivababu, January 23, 2002 - 11:19 am UTC

Hello TOM,
This is superb to find the locking. But how can i find the table name?.

Thanks and waiting for ur reply.

regards
sivababu


Find the table name -- Urgent

sivababu, January 24, 2002 - 3:32 am UTC

Hello TOM,
I'm strugling with last two days to find out which table is locked. But i couldn't find out. When i was using the JAVA MAILING SYSTEM. some tables are locked. I don't know why it is locked. So I'm want to know which tables are locked. So that i can find the problem.

Thank you and expecting your reply.

regards,
sivababu

Tom Kyte
January 25, 2002 - 6:57 am UTC

search this site for showsql.sql

it'll show you what sql people are executing. when you get a blocked session, run showsql and you'll see what SQL they are trying to execute but cannot.

That should help you ID the table in question.

Thanks

sivababu, January 25, 2002 - 8:03 am UTC

Hello TOM,
Thanks very much. I got this query from your book.

regards,
sivababu

Reader

Reader, February 04, 2002 - 1:37 pm UTC

Tom,

You have used
"trunc(id1/power(2,16)) rbs"

Many books have used 65535 instaed of power(2,16)= 65536

Do these both approches result in the same value
consistently, if so why
65536 = 1000000000000000
65535 = 111111111111111

Reader

Reader, February 05, 2002 - 7:00 am UTC

Never mind about the previous posting.
It was 65536 in other books

Questions on Locking

A reader, March 21, 2002 - 10:42 pm UTC

Dear Tom,

Your queries to identify waiting sessions was really very useful.

Can we find out for how long a transaction is locked or alternatively for how long a a session is waiting to acquire a lock.

Thanks

Tom Kyte
March 22, 2002 - 9:15 am UTC

You can see how long its been waiting by looking at the last_call_et column in v$session (if timed statistics is on this is updated frequently, else not so frequently)

A reader, April 02, 2002 - 5:45 am UTC

What is the overhead of having Timed_Statistics on.
Does this make the system very slow.

last_column_et has some number. Does this mean time elapsed in seconds since this query is running.

If timed_statistics is not on then will this give wrong information.Does this gets reset everytime a new query is tun.

Thanks

Tom Kyte
April 02, 2002 - 8:30 am UTC

It is very very very low. The general feeling is less then 5%.

I run all of my systems with it on as I find the value it provides far outweighs any overhead it might be percieved to have.

I believe you mean last_CALL_et -- its the time in seconds of the last call to the database. If the session is active -- its the amount of time spent processing the last statement. If inactive -- its a measure of the idle time. Only valid when timed_stats is on

It gets reset with every new "call" to the database.

A reader, July 26, 2002 - 3:28 pm UTC

Tom,

I want to know sql statements associated with one transaction. How can i know that?

Can I join v$transaction,v$session and v$sqlarea ?

Like
select c.name, b.username,b.osuser,a.ses_addr,b.saddr, xidusn,xidslot, xidsqn,used_ublk,a.start_time,d.sql_text
from v$transaction a,v$session b,v$rollname C,v$sqlarea d
where a.addr = b.taddr
and b.saddr = a.ses_Addr
and a.xidusn = c.usn
and v.sql_address = d.address

Thanks,

Tom Kyte
July 28, 2002 - 3:14 pm UTC

You can only know the current statement, the other statements might not even be there anymore (in the shared pool)

search this site for showsql.sql -- it does that.

Locks

suresh, July 29, 2002 - 2:46 am UTC

Exclusive Locks - row level as well as table level

Shared Locks - Table level only.

Is it Correct?

Thanks for your help

Tom Kyte
July 29, 2002 - 7:23 am UTC

the locks are all table level entries actually. You will not see individual row level locks in v$lock.

Yes, Oracle has no shared row lock. Not necessary.

Questions on Locking

Bharath, July 30, 2002 - 4:56 am UTC

Hi Tom,

Thanks for all the answers that you provide.

1. One of our report populates a temporary table before it starts running and the same is deleted after the report is run. The order of manipulations/selection on the table is as follows

1. Insert
2. Select
3. Select
3. Update/Insert
4. Delete
5. Commit

When the report is run more than once at the same time then it takes lot of time to get completed. When querying DBA_DML_LOCKS, we see lots of exclusive locks on this table(which is fine, because there are lot of DML operations happening on the table) which is 'Not Blocking'. But the problem is the locks are held for quite some time which does not happen when only once the report is run. But when I add COMMIT after each DML operation, the report runs normally. What is the reason behind this and how often should we COMMIT and when should we SELECT?


2. There is also another report, which also has temporary tables. Once I got a call saying that the report is running slowly. I ran the report after enabling the TRACE. The trace file was generated in a couple of minutes but the report took more that 2-3 hours to complete. Later I found that the report was taking time because of high watermark on the temporary table. My question is, how was the TRACE file generation was completed in a couple of minutes.

Thanks,
Bharath

Tom Kyte
July 30, 2002 - 12:34 pm UTC

1) not clear from what you describe as to what is happening here. The DML are all concurrent so committing won't affect anything at all. In fact, all the commit will do is let others see the data of others -- probably a bad idea.

I can say, you should be using a GLOBAL TEMPORARY TABLE and skipping the delete all together.

2) use global temporary tables and your problem will go away.

Which Rows are locked by a session

Vikas Khanna, August 29, 2002 - 9:25 am UTC

Hi,

I am doing an exercise to prove that Oracle never escalates locks and for this, I created a one million row table. Opened one session and started updating the rows in batches of 10. What I observed is that in the V$lock table the sid for that session has created an Exclusive Row Lock and a table share lock. But if in the same session I am updating them in batches, should it show me Row locks as new rows, as I keep on getting these two rows as the only rows for that session.

How could I have this information that what rows are locked by a session. Which is the V$ table from which this can be obtained.

Is there a limit for the Lock Manager for the no. of locks to handle? I think a big no. but my superiors have differences with me on this and they compare this with SQl Server escalation from Row to Page and then to Table.

A detailed explanation would be appreciated.

Thanks



Tom Kyte
August 29, 2002 - 7:48 pm UTC

If you have my book -- "expert one on one" i go into this.

We do NOT have a table of locks. That would be a serious scalability limiter and ram eater (we are not DB2, we are not SQLserver).

The lock is stored as an attribute of the data...

Tell you what -- to do your test, do this:

create table t ( x int primary key );
insert into t 1,000,000 (or whatever) rows with x = 1, 2, 3, .....


update t set x = x=1 where x <= 999,999;

and in another session do:

update t set x = x+1 where x = 1000000;

WE DO NOT HAVE A LOCK MANAGER -- they are the folly of other RDBMS. We have no such concept.



That is the downfall of SQLServer -- they have to have a serialized, limiting, scalability inhibiting lock manager. We have none.


You are trying to compare apples to flying toaster ovens (remember that screen saver?)

Apples are good, flying toasters -- interesting but not much use ;)

Which Rows are locked by a session

Vikas Khanna, August 29, 2002 - 9:26 am UTC

Hi,

I am doing an exercise to prove that Oracle never escalates locks and for this, I created a one million row table. Opened one session and started updating the rows in batches of 10. What I observed is that in the V$lock table the sid for that session has created an Exclusive Row Lock and a table share lock. But if in the same session I am updating them in batches, should it show me Row locks as new rows, as I keep on getting these two rows as the only rows for that session.

How could I have this information that what rows are locked by a session. Which is the V$ table from which this can be obtained.

Is there a limit for the Lock Manager for the no. of locks to handle? I think a big no. but my superiors have differences with me on this and they compare this with SQl Server escalation from Row to Page and then to Table.

A detailed explanation would be appreciated.

Thanks



Locking Concepts

Vikas Khanna, August 30, 2002 - 4:52 am UTC

Tom.Excellent Reply. I do not think these toasters would ever become apples in real life.

But I am curious to know details of this process :
1) When I am locking a table's row two entries are shown to me in V$lock. Another row lock of the same table does not show be another entry related to row Exlusive lock.
What I need to know is where does Oracle store this information that this user has locked so many rows for this table.

2) If by any means I need to know, that a particular row is locked by whom where could I read this information from. Is there any Virtual table or it is in the X$ base tables of Oracle.

3) Meaning of this statement 'The lock is stored as an attribute of the data...' in detail

Curiosity to know the answers to these questions before this settles for the time being.

Tom Kyte
August 30, 2002 - 9:56 am UTC

I'll refer you to a book that goes through this in some detail -- "Expert one on one Oracle" (my book). I spend quite a few pages going over topics like this in detail.

In brief


1) we do NOT store the nitty gritty details in some lock table -- that is the beauty of this implementation. The "locks" are attributes of the data itself. The "locks" you are looking for are just information in the block header (the ITL portion to be specific - a transaction entry). We need not mark down somewhere that you have 999,999 row locks. That is specifically why we can support an infinite number of locks (whereas the others -- cannot). Locks are not a scarce resource in Oracle as they are in other databases.

2) That information is quite simply not recorded anywhere. If you have someone being blocked by someone else -- I can tell you who is blocking who but you can only look at a row and say "it is not locked" or "it is locked" (using select FOR UPDATE NOWAIT). You cannot say by "whom" (unless you get blocked -- then you can)

3) read my book -- don't know how to say it briefly here other then the lock is just part of the block data, it is always there, it is never there. It is just an attribute of the data.

Explicit locking

Praveen, November 05, 2002 - 12:38 am UTC

Hi Tom,

Please help me to clear a couple of doubts..

1) Is it possible to obtain a 'table-level' exclusive lock?
For ex: I perform an UPDATE like this:

UPDATE Table1 SET field1 = value1;

This statement is going to update all rows in the table.

The question is _

Whether Oracle will first attempt a SELECT operation to determine which rows are going to be updated and issue row-level X-lock ?
OR
Will it obtain a 'table-level' exclusive lock immediately?

2) Here I came across "Two Important Reasons" for using explicit locking:

>> Raising error with NOWAIT option to prevent waiting for unspecified time for other transactions to be commited;

>> Locking ALL the table in EXCLUSIVE mode to eliminate overhead of MULTIPLE consecutive row-level locks during bulk operations;

How can we relate this to
>> "Transaction level read consistency" and
>> "Exclusive access to resources without waiting"

These are the two 'useful situation to override default locking' sited by the oracle doc?

3) Could you please provide us a few more similar examples so that we can decide when to go for exclusive locking?

Thanks and regards

Praveen

Tom Kyte
November 05, 2002 - 9:32 am UTC

1) it would put a lock at the table level saying in effect "there are rows locked in this table". It would not lock the table in exclusive mode (as there could be rows in the table that will not be updated!!!! How so you say? Someone inserted 50 rows -- did not commit -- you issue your update in another session, it'll NEVER update those 50 outstanding rows).

2) where is "here". I don't understand either of those two statements really.

First -- you typically use the select for update statement in order to avoid the concurrency problem known as "LOST UPDATE". You can put a nowait on there in order to avoid waiting for long periods (eg: I want to report back to the user that "hey, the row is locked right now"). The fact that you are doing explicit locking ISN'T to avoid waiting (thats a side effect). You are doing explicit locking to avoid LOST UPDATES (if you don't know what they are -- my book "Expert one on one Oracle" goes into that in great detail)

The second one might apply to Informix or DB2 or SQLServer (any flavor -- the MS or Sybase one). To Oracle -- nope. We do not have an external lock manager like they do, we do not have their inherit overhead. There is no overhead here (and in fact, if you do a lock table + row level operations we do the same work as if you just do row level operations).


I would need to have locations in the documentation to find the statements to which you refer in order to read them in context. I don't comment on 5 word snippets out of context.


3) do you mean EXPLICIT? If so, I'll refer you to my book again. I covered this topic in great detail.



Re: Follow up: Explicit Locking

Praveen, November 06, 2002 - 4:04 am UTC

Hi Tom,

Thankyou very much for the quick answer. I think I need to brush up my knowledge more thoroughly, because your answer (regarding explicit locking) infact arises quite a few number of questions.

Thanks once again

Praveen

How do I find out ITL Waits

A reader, December 04, 2002 - 3:00 pm UTC

Excellent thread and dicussion, Tom.

You mentioned here the ITL section of the data block. How do I know whether sessions are waiting for the ITL since the ITL section can't grow due to no space, or MAXTRANS is defined very low? Is there a row in V$SYSSTAT, V$SESSION_WAIT or V$SESSTAT views, somewhere?

Thanks a lot in advance.

Tom Kyte
December 04, 2002 - 4:27 pm UTC

If there is no free 'ITL' then the requesting session will wait on one
of the active transaction locks in mode 4.

you can see this by:

create table t ( x int ) maxtrans 2;
insert into t values ( 1 );
insert into t values ( 2 );
insert into t values ( 3 );
commit;
update t set x = 1 where x = 1;

and in another session "update t set x = 2 where x = 2"
and then in a third, "update t set x = 3 where x = 3"

that third guy will get hit -- you can query:

select SID,TYPE,ID1,ID2,LMODE,REQUEST from v$lock where type='TX';

SID TY ID1 ID2 LMODE REQUEST
---------- -- ---------- ---------- ---------- ----------
8 TX 327688 48 6 0
10 TX 327688 48 0 4

This shows SID 10 is waiting for the TX lock held by SID 8 and it
wants the lock in share mode (as REQUEST=4).


One way to see this is by seeing large enqueue waits in v$system_event.



Lock Appearing While Referring a Database Link

Baiju, December 04, 2002 - 11:57 pm UTC

Hello Tom,

When ever I refer a Database link in a query , i see a TX lock appearing in the v$lock for that session. Even if it is a SELECT statement also i see this lock. But if a simply start my session as READ ONLY and issue the same query , I don't see this lock...
Whether the lock is on the Database link object itself ?

Baiju

Tom Kyte
December 05, 2002 - 7:44 am UTC

TX are just transaction entries -- they aren't locking anything.

It just means you've begun a transaction -- waiting for commit or rollback. Tis normal in a distributed situation - the query coordinator may well as you to prepare to commit -- even if you've done no work (cause the QC doesn't know you did no work). So, you need a transaction.


ITL Waits

Arup Nanda, December 05, 2002 - 1:25 am UTC

Superb response to the original question in this thread and look how much it has expanded!

In as much as I try not to step over Tom's feet, I want to share another tip with the reviewer asking about ITL Waits. If you are lucky enough to be using 9i Release 2 (only release 2, not 1), you can enable segment level stats collection by setting STATISTIC_LEVEL = TYPICAL and then issuing the following query

SELECT OWNER, OBJECT_NAME, VALUE
FROM V$SEGMENT_STATISTICS
WHERE STATISITC_NAME = 'ITL wait'
AND VALUE > 0

This will immediately tell you all the segments that experienced ITL waits since the instance startup. Unfortunately this is only for 9iR2. Helps immensly.

OWB sessions lock to each other

Sean, January 16, 2003 - 8:45 pm UTC

Tom,
I have been using OWB9iR2 to generate ETL. As ETL been executed, and never come back. I have used your script to find out what's going on:

Could you tell me why OWB sessions locked? Who is the blocker?

owb_repos@db99> select username,
2 v$lock.sid,
3 trunc(id1/power(2,16)) rbs,
4 bitand(id1,to_number('ffff','xxxx'))+0 slot,
5 id2 seq,
6 lmode,
7 request
8 from v$lock, v$session
9 where v$lock.type in ( 'TX','TM')
10 and v$lock.sid = v$session.sid
11 and v$session.username = 'OWB_REPOS'
12 /

Thu Jan 16
User Sessions

ORACLE
USERNAME SID RBS SLOT SEQ LMODE REQUEST
---------- ----- --------- --------- --------- --------- ---------
OWB_REPOS 17 4 2 8476 6 0
OWB_REPOS 17 0 53323 0 0 2
OWB_REPOS 21 2 9 9584 6 0
OWB_REPOS 21 0 53350 0 2 0
OWB_REPOS 21 0 53323 0 6 0
OWB_REPOS 22 3 77 13712 6 0
OWB_REPOS 22 0 53323 0 0 2
OWB_REPOS 25 2 71 9586 6 0
OWB_REPOS 25 0 53323 0 0 2
OWB_REPOS 29 4 71 8484 6 0
OWB_REPOS 29 0 53323 0 0 2
OWB_REPOS 32 3 65 13711 6 0
OWB_REPOS 32 0 53323 0 0 2

13 rows selected.

owb_repos@db99>
owb_repos@db99> select XIDUSN, XIDSLOT, XIDSQN
2 from v$transaction
3 /

Thu Jan 16
User Sessions

XIDUSN XIDSLOT XIDSQN
--------- --------- ---------
4 2 8476
2 9 9584
2 71 9586
4 71 8484
3 65 13711
3 77 13712

6 rows selected.

owb_repos@db99>
owb_repos@db99> @vlock

Thu Jan 16
User Sessions

ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
-------- -------- ----- -- --------- --------- --------- --------- --------- ---------
23B533F8 23B5340C 17 TM 53323 0 0 2 1690 0
23B53374 23B53388 22 TM 53323 0 0 2 1690 0
23B53584 23B53598 25 TM 53323 0 0 2 1690 0
23B53500 23B53514 29 TM 53323 0 0 2 1690 0
23B5347C 23B53490 32 TM 53323 0 0 2 1690 0

And the following shows each session doing what:

session 17,
22,
25,
29,
32,

they are doing:

INSERT /*+ APPEND */ INTO "DSS02"."WORK_ORDER_02"("AGREEMENT_SID","WORK_ORDER_NB","ALLOCATION_RULE_C
_OPERATION_NB","CURRENT_OPERATION_ACTIVE_DT","WORK_ORDER_PRIORITY_CD","TOTAL_ACTUAL_MOVE_HR","TOTAL_
ORK_HR","TOTAL_ACTUAL_SETUP_HR","WORK_ORDER_TRACKING_CD","PART_FIRST_RCVD_DT") SELECT C0,C1,C2,C3,C4
:Q62000
SQL*Plus 2003-01-16/19:54:17

But session 21:

INSERT /*+ APPEND PARALLEL("WORK_ORDER_02", DEFAULT, DEFAULT)*/ INTO "WORK_ORDER
_02" ("AGREEMENT_SID", "WORK_ORDER_NB", "ALLOCATION_RULE_CD", "WORK_
ORDER_TYPE_CD", "CURRENT_OPERATION_NB", "CURRENT_OPERATION_ACTIVE_DT", "WORK
_ORDER_PRIORITY_CD", "TOTAL_ACTUAL_MOVE_HR", "TOTAL_ACTUAL_RUN_HR", "TOTAL_A
CTUAL_REWORK_HR", "TOTAL_ACTUAL_SETUP_HR", "WORK_ORDER_TRACKING_CD", "PART_F
IRST_RCVD_DT") (SELECT /*+ NO_MERGE*/ "AGREEMENT_SEQ_02".NEXTVAL "NEXTVAL"
, "ORD_TABLE_WDS01_MRPD"."WO_NBR" "WO_NBR", TRIM("ORD_TABLE_WDS01_MRPD"."ALLOC_C
TRL") "Result", TRIM("ORD_TABLE_WDS01_MRPD"."TYPE") "Result$0", TRIM("ORD_TABLE_
WDS01_MRPD"."HIGH_OPN") "Result$1", "ORD_TABLE_WDS01_MRPD"."HI_OPN_DATE" "HI_OPN_DATE",
TO_CHAR("ORD_TABLE_WDS01_MRPD"."PRI") "Result$2", "ORD_TABLE_WDS01_MRPD"."ACT_HRS

Looks to me the session21 blocking all of the rest?

Sean, January 16, 2003 - 8:49 pm UTC

By the way, I am sure it is 100% dead lock, because the logical and physical reads for all the sessions have never been changing over the loong time.

Tom Kyte
January 16, 2003 - 9:12 pm UTC

and i'm 100% sure it is not a deadlock as we automagically detect those and rectify them.

I'm 100% sure it is a "lock" if it is anything.

Anyway - use utllockt (in $ORACLE_HOME/rdbms/admin) to print out a blocker/waiter graph to verify your random queries there -- to see who it is. then, you can use my showsql.sql script (just search for that) to see what each session is actually running

Sean, January 16, 2003 - 8:58 pm UTC

FYI,
I only started one OWB_REPOS session, it spurn all the rest of OWB_REPOS's

SEan, January 16, 2003 - 9:43 pm UTC

Here is the UTLLOCKT output

-------------------------

WAITING_SESSION
----------------------------------------------------------------------------------------------------
LOCK_TYPE MODE_REQUESTED MODE_HELD LOCK_ID1 LOCK_ID2
-------------------------- -------------- -------------- ---------------------- --------------------
35
None

17
DML Row-S (SS) Exclusive 53323 0

21
DML Row-S (SS) Exclusive 53323 0

22
DML Row-S (SS) Exclusive 53323 0

32
DML Row-S (SS) Exclusive 53323 0

36
DML Row-S (SS) Exclusive 53323 0


6 rows selected.


Which shows session 35 blocks all the rest.

SEssion 35 doing?
Question for Tom, what's the 35 waits for??????

BUSZ@> @showsql_uid
DOC> show sql syntax
DOC> Sanny Subowo, Oracle Corporation, 4/16/99
DOC>#
Enter value for usrsid: 35
old 4: c.sid = '&usrsid'
new 4: c.sid = '35'

Thu Jan 16
User Sessions

SQL_TEXT
----------------------------------------------------------------------------------------------------
MODULE FIRST_LOAD_TIME
---------------------------------------------------------------- -------------------
INSERT /*+ APPEND PARALLEL("WORK_ORDER_02", DEFAULT, DEFAULT)*/ INTO "WORK_ORDER_02" ("AGREEM
RK_ORDER_NB", "ALLOCATION_RULE_CD", "WORK_ORDER_TYPE_CD", "CURRENT_OPERATION_NB", "CURRENT
DT", "WORK_ORDER_PRIORITY_CD", "TOTAL_ACTUAL_MOVE_HR", "TOTAL_ACTUAL_RUN_HR", "TOTAL_AC
"TOTAL_ACTUAL_SETUP_HR", "COST_METHOD_TYPE_CD", "PART_FIRST_RCVD_DT") (SELECT /*+ NO_MERG
EMENT_SEQ_02".NEXTVAL "NEXTVAL", "ORD_TABLE_WDS01_MRPD"."WO_NBR" "WO_NBR", "ORD_TABLE_WDS01_MRPD
C_CTRL", "ORD_TABLE_WDS01_MRPD"."TYPE" "TYPE", "ORD_TABLE_WDS01_MRPD"."HIGH_OPN" "HIGH_OPN",
1_MRPD"."HI_OPN_DATE" "HI_OPN_DATE", "ORD_TABLE_WDS01_MRPD"."PRI" "PRI", "ORD_TABLE_WDS01_MRPD
HRS_MOVE", "ORD_TABLE_WDS01_MRPD"."ACT_HRS_RUN" "ACT_HRS_RUN",
SQL*Plus 2003-01-16/21:05:29


ANd the rest of the blocked sessiona are all doing:

Thu Jan 16
User Sessions

SQL_TEXT
----------------------------------------------------------------------------------------------------
MODULE FIRST_LOAD_TIME
---------------------------------------------------------------- -------------------
INSERT /*+ APPEND */ INTO "DSS02"."WORK_ORDER_02"("AGREEMENT_SID","WORK_ORDER_NB","ALLOCATION_RULE_C
_OPERATION_NB","CURRENT_OPERATION_ACTIVE_DT","WORK_ORDER_PRIORITY_CD","TOTAL_ACTUAL_MOVE_HR","TOTAL_
ORK_HR","TOTAL_ACTUAL_SETUP_HR","COST_METHOD_TYPE_CD","PART_FIRST_RCVD_DT") SELECT C0,C1,C2,C3,C4,C5
63000
SQL*Plus 2003-01-16/21:05:30


The ETL extract data from the remote database, and there is no shown any locks overthere (checked with utllockt.sql)

the remote session doing:

SQL_TEXT
----------------------------------------------------------------------------------------------------
MODULE FIRST_LOAD_TIME
---------------------------------------------------------------- -------------------
SELECT "WO_NBR","TYPE","HAS_TRK","ALLOC_CTRL","HIGH_OPN","HI_OPN_DATE","PRI","ACT_HRS_MOVE","ACT_HRS
_RUN","ACT_HRS_RW","ACT_HRS_SU","DATE_FST_RCV" FROM "ORD_TABLE" "ORD_TABLE_WDS01_MRPD"
2003-01-16/19:54:17


Tom Kyte
January 17, 2003 - 9:00 am UTC

only one session at a time can insert append into a table. the rest are waiting for the first guy to finish.

Sean, January 16, 2003 - 9:48 pm UTC

Tom,
The following is the ETL code generated by OWB9iR2:

CREATE OR REPLACE PACKAGE "WORK_ORDER_01" AS
-- Status variable for Batch cursors
"WORK_ORDER_02_St" BOOLEAN;

-- Procedure Main -- Entry point in package "WORK_ORDER_01"
PROCEDURE Main;

END "WORK_ORDER_01";

/

CREATE OR REPLACE PACKAGE BODY "WORK_ORDER_01" AS

---------------------------------------------------------------------------
-- Function "WORK_ORDER_02_Bat"
-- performs batch extraction
-- Returns TRUE on success
-- Returns FALSE on failure
---------------------------------------------------------------------------
FUNCTION "WORK_ORDER_02_Bat" RETURN BOOLEAN IS

BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION ENABLE PARALLEL DML';

BEGIN

INSERT
/*+ APPEND PARALLEL("WORK_ORDER_02", DEFAULT, DEFAULT)*/
INTO
"WORK_ORDER_02"
("AGREEMENT_SID",
"WORK_ORDER_NB",
"ALLOCATION_RULE_CD",
"WORK_ORDER_TYPE_CD",
"CURRENT_OPERATION_NB",
"CURRENT_OPERATION_ACTIVE_DT",
"WORK_ORDER_PRIORITY_CD",
"TOTAL_ACTUAL_MOVE_HR",
"TOTAL_ACTUAL_RUN_HR",
"TOTAL_ACTUAL_REWORK_HR",
"TOTAL_ACTUAL_SETUP_HR",
"COST_METHOD_TYPE_CD",
"PART_FIRST_RCVD_DT")
(SELECT
/*+ NO_MERGE*/
"AGREEMENT_SEQ_02".NEXTVAL "NEXTVAL",
"ORD_TABLE_WDS01_MRPD"."WO_NBR" "WO_NBR",
"ORD_TABLE_WDS01_MRPD"."ALLOC_CTRL" "ALLOC_CTRL",
"ORD_TABLE_WDS01_MRPD"."TYPE" "TYPE",
"ORD_TABLE_WDS01_MRPD"."HIGH_OPN" "HIGH_OPN",
"ORD_TABLE_WDS01_MRPD"."HI_OPN_DATE" "HI_OPN_DATE",
"ORD_TABLE_WDS01_MRPD"."PRI" "PRI",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_MOVE" "ACT_HRS_MOVE",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_RUN" "ACT_HRS_RUN",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_RW" "ACT_HRS_RW",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_SU" "ACT_HRS_SU",
"ORD_TABLE_WDS01_MRPD"."HAS_TRK" "HAS_TRK",
"ORD_TABLE_WDS01_MRPD"."DATE_FST_RCV" "DATE_FST_RCV"
FROM
"ORD_TABLE"@"WDS01_MRPD" "ORD_TABLE_WDS01_MRPD"
);
COMMIT;
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
COMMIT;
RETURN FALSE;
END;
COMMIT;
RETURN TRUE;
END "WORK_ORDER_02_Bat" ;


PROCEDURE Main IS
get_batch_status BOOLEAN := TRUE;
BEGIN

-- Initialize all batch status variables
"WORK_ORDER_02_St" := FALSE;


"WORK_ORDER_02_St" := "WORK_ORDER_02_Bat";

END Main;
END "WORK_ORDER_01";

/


Sean, January 16, 2003 - 9:51 pm UTC

The following query, which is in the ETL returns immediately by OWB_REPOS

SELECT
/*+ NO_MERGE*/
"AGREEMENT_SEQ_02".NEXTVAL "NEXTVAL",
"ORD_TABLE_WDS01_MRPD"."WO_NBR" "WO_NBR",
"ORD_TABLE_WDS01_MRPD"."ALLOC_CTRL" "ALLOC_CTRL",
"ORD_TABLE_WDS01_MRPD"."TYPE" "TYPE",
"ORD_TABLE_WDS01_MRPD"."HIGH_OPN" "HIGH_OPN",
"ORD_TABLE_WDS01_MRPD"."HI_OPN_DATE" "HI_OPN_DATE",
"ORD_TABLE_WDS01_MRPD"."PRI" "PRI",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_MOVE" "ACT_HRS_MOVE",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_RUN" "ACT_HRS_RUN",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_RW" "ACT_HRS_RW",
"ORD_TABLE_WDS01_MRPD"."ACT_HRS_SU" "ACT_HRS_SU",
"ORD_TABLE_WDS01_MRPD"."HAS_TRK" "HAS_TRK",
"ORD_TABLE_WDS01_MRPD"."DATE_FST_RCV" "DATE_FST_RCV"
FROM
"ORD_TABLE"@"WDS01_MRPD" "ORD_TABLE_WDS01_MRPD"
;

New founding.

SEAN, January 16, 2003 - 10:39 pm UTC

There seams the enqueue blocked by 35:

owb_repos@db99> l
1 select event, sid, seq#,
2 wait_time,
3 seconds_in_wait,
4 /* state,
5 p1text, p1, p1raw,
6 p2text, p2, p2raw,
7 p3text, p3, p3raw
8 p1text || ' = ' || p1 parm1,
9 p2text || ' = ' || p2 parm2,
10 p3text || ' = ' || p3 parm3
11 */
12 decode( p1text, null, null,
13 p1text || ' = ' || p1 ) ||
14 decode( p2text, null, null,
15 ', ' || p2text || ' = ' || p2 ) ||
16 decode( p3text, null, null,
17 ', ' || p3text || ' = ' || p3 )
18 parameters
19 from v$session_wait
20 where event not in ( 'pmon timer', 'rdbms ipc message', 'smon timer',
21 'WMON goes to sleep', 'Null event',
22 'SQL*Net message from client' )
23* order by event, p1, p2
owb_repos@db99>

Thu Jan 16
Session Waits

WAIT SECONDS
EVENT SID SEQ TIME IN WAIT PARAMETERS
----------------------------- ----- ------ ---- ------- --------------------------------------------
PX Deq Credit: send blkd 35 2877 3 sleeptime/senderid = 268500993, passes = 2563, qref = 0
enqueue 17 1712 3 name|mode = 1414332418, id1 = 53323, id2 = 0
21 1711 3 name|mode = 1414332418, id1 = 53323, id2 = 0
32 1711 3 name|mode = 1414332418, id1 = 53323, id2 = 0
22 1712 3 name|mode = 1414332418, id1 = 53323, id2 = 0
36 1709 3 name|mode = 1414332418, id1 = 53323, id2 = 0

HOW CAN WE RESOLVE IT?!

THANKS IN ADVANCE.

Becuase of the Parallel inserts! the #35 parallel processs blocks others?

Sean, January 16, 2003 - 11:34 pm UTC


Tom Kyte
January 17, 2003 - 9:01 am UTC

yes, ONE session at a time can direct path insert into a table.

Still I have a puzzle in mind...

Shailesh, January 17, 2003 - 6:40 am UTC

Thank you very much for such a nice discription. Just came across similar Locking situation..

Executed few statements WITHOUT ISSUING COMMIT following way...

Session 1 :
------------
Update Table1 set column1 ='123' where Column1 = 4;

Update Table2 set column1 ='ABC' where Column1 = 'XYZ';

Session 2 :
--------------
Update Table1 set column1 ='123' where Column1 = 4;

Session 3 :
---------------
Update Table2 set column1 ='ABC' where Column1 = 'XYZ';

When tried to search which row has locked which other session.

SELECT B.OSUSER USERNAME, C.SID SID, C.OBJECT OBJECT, B.LOCKWAIT, A.SQL_TEXT SQL
FROM V$SQLTEXT A, V$SESSION B, V$ACCESS C
WHERE A.ADDRESS=B.SQL_ADDRESS AND
A.HASH_VALUE=B.SQL_HASH_VALUE AND
B.SID = C.SID AND C.OWNER != 'SYS'
AND SID IN (1,2,3);

I see..

Sid SQL
------ -----------------------------------------------
1 Update Table2 set column1 ='ABC' where Column1 = 'XYZ';

2 Update Table1 set column1 ='123' where Column1 = 4;

3 Update Table2 set column1 ='ABC' where Column1 = 'XYZ';

session 2 is locked by first statement executed by session 1.

But I can't see which row is locked by which row, rather than session. Because in above case it shows me that Session 1 has EXCLUSIVE LOCK for Table2 update statement, Then why session 2 is waiting for?

Can I get All statements executed by a particular session. I tried this but doesn't give required output.

SELECT * FROM V$OPEN_CURSOR WHERE SID = 1;


Thanks & Regards,

Shailesh



Tom Kyte
January 17, 2003 - 9:27 am UTC

we do not keep a list of row locks anywhere - that would be inheritly non-scalable and put a limit on the number of locks.

Transactions get blocked by other transactions. What you see is that ssession 2 and 3 are blocked by session 1, that is all. You can see the sql statments that sessions 2 and 3 are waiting to execute and that is all.

You cannot find all the statements for a session they
o may close cursors
o have their sql aged out
o etc



Does commit release all locks before returning?

Sam, January 20, 2003 - 4:50 pm UTC

Tom,

We have two database sessions that are processing the same set of rows (our client PL/SQL program runs in one session, and communicates with some transaction manager written in Pro*C running in some other session thru dbms_pipe).

The client program sends a request to the transaction manager, and the transaction manager will start processing (insert/update a set of rows). At the end, the transaction manager will commit or rollback and return control to the calling program.

The calling program will then lock the same set of rows just processed by doing a SELECT...FOR UPDATE NOWAIT.

We noticed that this is returning a "resource busy and nowait specified" error. If we remove the NOWAIT from the SELECT...FOR UPDATE, the 10046 level 8 trace shows a wait of about 1 second on a TX lock.

Does commit releases all the locks before returning control to the calling procedure? Or does some background process have to clean up the locks? Any ideas on what might be happening? We are pretty sure the client program and the transaction manager are the only two sessions modifying the set of rows.


Tom Kyte
January 20, 2003 - 4:58 pm UTC

A TX lock is the transaction itself -- and a commit would wipe that out.

"pretty sure" or 100% sure?

Insert blocked ?!

Robert, January 22, 2003 - 6:24 pm UTC

Tom,

I have been digging into lock investigation using a combination of scripts and ideas from your book, your website, Metalink, Oracle Internal Services by Steve Adams, etc. I think I have learned some useful things.

But I have a baffling situation...
We have a situation with our 3rd party app, where INSERT statements are being blocked. These appear to be just plain old insert statements. The blocker is blocking them with a lock_mode/type of 6/TX. The waiters are waiting with a lock_mode/type of 4/TX.

What could the blocker possibly be doing to block an insert statement?

Thanks,

Robert.

Tom Kyte
January 22, 2003 - 7:12 pm UTC

o look for unindexed foreign keys
o unique/primary key constraints (both inserting same value)



eg:

ops$tkyte@ORA817DEV> create table p ( x int primary key );
Table created.

ops$tkyte@ORA817DEV> create table c ( x references p );
Table created.

ops$tkyte@ORA817DEV> insert into p values ( 1 );
1 row created.

ops$tkyte@ORA817DEV> insert into p values ( 2 );
1 row created.

ops$tkyte@ORA817DEV> insert into c values ( 2 );
1 row created.

ops$tkyte@ORA817DEV> commit;
Commit complete.

ops$tkyte@ORA817DEV> update p set x = 1 where x = 1;
1 row updated.

<b>that'll lock the child table in 8i and below...</b>


ops$tkyte@ORA817DEV> insert into p values ( 3 );
1 row created.

<b>that'll block anyone from inserting into p the value 3</b>


ops$tkyte@ORA817DEV> select SID, TYPE, ID1, ID2, LMODE,
  2        (select object_name from user_objects where object_id=id1) oname,
  3             block
  4    from v$lock
  5   where sid = (select sid from v$mystat where rownum=1 )
  6   or block = 1;

       SID TY        ID1        ID2      LMODE ONAME           BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        10 TM      51210          0          3 P                   0
        10 TM      51212          0          4 C                   0
        10 TX     262198       5165          6                     0

ops$tkyte@ORA817DEV>
ops$tkyte@ORA817DEV> set echo off
either run:
insert into c values(2)
insert into p values(3)
in another session and then hit / again here...

<b>this is after trying to insert into C:</b>

ops$tkyte@ORA817DEV> /

       SID TY        ID1        ID2      LMODE ONAME           BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        10 TM      51210          0          3 P                   0
        10 TM      51212          0          4 C                   1
        10 TX     262198       5165          6                     0

<b>and then I ctl-c'ed and tried to insert into P</b>


ops$tkyte@ORA817DEV> /

       SID TY        ID1        ID2      LMODE ONAME           BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
        10 TM      51210          0          3 P                   0
        10 TM      51212          0          4 C                   0
        10 TX     262198       5165          6                     1

 

More Locking ... Row or Block ?

Christophe Parmentier, January 23, 2003 - 10:48 am UTC

Hi, got some more strange behaviours with locks.

We have 2 or more parallele processes working 2 tables but NOT on the same rows, they both make insert/delete and sometimes it looks like the row locking do block locking (we got a lot of rows...):

Process 1:
Insert Into T1 select from T3 where p = 1;
Insert Into T2 select from T3 where p = 1 and q = 0;
Commit;
Delete from T2 where p = 1;
Delete from T1 where p = 1;
Commit;

The Process 2 runs meanwhile doing the same with p = 2 and so on for others process...

We got ORA-02049: timeout: distributed transaction waiting for lock error.

It looks like process 1 and 2 cause a deadlock cause we don't insert/delete in the same order and that some rows that should not be locked ( different p ) are in fact block-locked... (Only explanation i get)

I've already been reordering the delete statements and removed the bitmap indexes (we heard that could be the problem in 8.1.7) but that look wired to me :)

If you have some explanations, i'm curious.

Thanks a lot and Regards.


Tom Kyte
January 23, 2003 - 11:13 am UTC

t1, t2, t3 -- same machine, different machines what?


bitmaps!!! you cannot have bitmaps on tables that you do operations like that on. No way. get rid of them. it is not 817, 80, 9i or version 55c -- bitmaps and modifications like that are like oil and water.

Additional informations...

Christophe Parmentier, January 23, 2003 - 11:31 am UTC

T1 and T2 are on a database and T3 on another instance... same machine, acces through DB Link.

We've removed the Bitmap Indexes and i wanted to know if this was enough.

Tom Kyte
January 23, 2003 - 11:55 am UTC

It was probably the bitmaps -- but it could be ANY OTHER concurrently executing process if there were any.

Again...

Christophe Parmentier, January 23, 2003 - 12:24 pm UTC

Just parallel processeses working on the T1 and T2 But on different rows (A lot!)

We have a dbms_lock that prevent parallel processes from running the same "p" parameters...

That was strange.

Thanks anyway.

Locking behavior

Kamal, April 22, 2003 - 7:11 am UTC

Hi,

It was a real good experience to gain good knowledge like this.
I have a strange doubt/problem. We have a table structure whereby TABLE2 is referecing PK of TABEL1. i.e. TABLE1 is PARENT table and TABLE2 is CHILD table. We have noticed that when we delete some record from CHILD table, TABLE2, I could see TABLE1 is getting locked in RS (row share) mode. and above all, we could not perform any DML on TABLE1, parent table. We were not having index on FK in child table. but that limitation of locking CHILD table is there when we perform any DML on parent table. This is almost reverse behavior. When we add index on FK of child table, we could perform DML on parent table.

Could you plz explain me this locking behavior ?

Thanx,
Kamal

Tom Kyte
April 22, 2003 - 7:52 am UTC

Is select a DML

kumar, April 24, 2003 - 7:20 am UTC

Tom,

A couple of niggling doubts..

1.Why is SELECT statement listed as a DML in Oracle SQL Reference ?

2. Will a select statement obtain a lock anytime ( excluding select for update ) ?

3. Why oracle is allowing me to drop a table when some other session is querying that table? Doesn't that violates the read consistency?



Tom Kyte
April 24, 2003 - 9:22 am UTC

1) because it is DML -- dml = data manipulation lanaguage (as opposed to DDL -- data definition lanaguage).

SELECT is DML, many people consider DML only to be "modifications" but that is technically inaccurate.

2) select for update -- will. during parse time, it will.

3) no read consistency says "we'll ensure a read consistent view and give you an error otherwise -- we'll never give you the wrong answer"

dropping the table doesn't violate that -- any many queries that were in process may return successfully -- whereas others may return with an

[tkyte@tkyte-pc-isdn mesg]$ oerr ora 8103
08103, 00000, "object no longer exists"
// *Cause: the object has been deleted by another user since the operation
// began


Thanks

kumar, April 24, 2003 - 10:15 am UTC

Tom,

Thanks for your response. One more doubt. When I am running a query on a table and some other session comes and truncates the table, Oracle throws an "Object Not Found" error. Why is this happening ?

Thanks again for answering the questions.

Tom Kyte
April 24, 2003 - 12:18 pm UTC

cause the data object id it was querying no longer exists.

The object "no longer exists" - Oracle *might* raise the error -- might not, depends on the query itself.


A truncate is just shorthand for:

o drop
o create
o add indexes and grants


the data_object_id changes with each truncate, its a whole new object.

Why the OBJECT_ID does not change...

Kamal Kishore, April 24, 2003 - 4:07 pm UTC

Hi Tom,
If truncate command is shorthand for DROP, CREATE sequence, then whey the OBJECT_ID of the table does not change after TRUNCATE?


SQL> create table t (x integer) ;

Table created

SQL> insert into t values (1) ;

1 row inserted

SQL> commit ;

Commit complete

SQL> select object_id, object_name from user_objects where object_name = 'T' ;

 OBJECT_ID OBJECT_NAME
---------- --------------------------------------------------------------------------------
    169100 T

1 row selected

SQL> truncate table t ;

Table truncated

SQL> select object_id, object_name from user_objects where object_name = 'T' ;

 OBJECT_ID OBJECT_NAME
---------- --------------------------------------------------------------------------------
    169100 T

1 row selected

SQL> 
 

Tom Kyte
April 24, 2003 - 4:31 pm UTC

thats just a surrogate key.  look at the DATA_OBJECT_ID, that is what I said is really important here -- the object (the data object) no longer exists...

ops$tkyte@ORA920> select object_id, data_object_id from user_objects where object_name= 'T';

 OBJECT_ID DATA_OBJECT_ID
---------- --------------
     34408          34408

ops$tkyte@ORA920> truncate table t;

Table truncated.

ops$tkyte@ORA920> select object_id, data_object_id from user_objects where object_name= 'T';


 OBJECT_ID DATA_OBJECT_ID
---------- --------------
     34408          34418

 

Excellent - as always

A reader, April 24, 2003 - 4:44 pm UTC


Great response

kumar, April 24, 2003 - 10:45 pm UTC

Tom,
Thats something I haven't read anywhere before this.
When I got the error first time, I thought it could be a bug.
Thanks for the response.

A reader, May 13, 2003 - 6:35 am UTC


TX without TM

David Pujol, June 09, 2003 - 5:31 pm UTC

Hi Tom, I've seen that in v$lock I look a transactions TX without TM lock. I've been studing this topic, and I'he seen some notes that talks about that this is a normal behaviour when dblinks are used. But, my question, can you explain me the reason of why Oracle take a TX lock and don`t take a TM lock too?, Is TM lock in remote database? Why?

Thanks in advance
David Pujol



Tom Kyte
June 09, 2003 - 7:06 pm UTC

using a dblink starts a transaction, yes.

you will see the TX lock as soon as you touch the dblink, even with a query. there need not be a tm lock at all. But, if the table is remote and you update it, the tm lock will be on the OTHER site's v$lock view, not yours.

bitand

Bala, June 10, 2003 - 11:07 pm UTC

Tom,
I tried learning from various source why this bitand thing is used. I am still not clear. Can you please explain me the basics of bitand function and how did you use it here.

bitand(id1,to_number('ffff','xxxx'))+0

Tom Kyte
June 11, 2003 - 6:49 am UTC

the number id1 is a 4 byte integer.

there are really two 2 byte numbers hiding in that single field.  So, if the two numbers were 2 and 3, then id1 would be 0x00020003 which is decimal

ops$tkyte@ORA920LAP> select to_number( '20003', 'xxxxx' ) from dual;

TO_NUMBER('20003','XXXXX')
--------------------------
                    131075

We needed the low 2 bytes only, we want '3' as the result.  So, we need to "mask off" the high 2 bytes and just keep the low two bytes.  In order to do that, we need the number such that all of the bits are "on" in the low 2 bytes and off in the high ones.  In binary, that would be:

00000000000000001111111111111111

and in hex

0x0000FFFF

Now, bitand is a function that takes two numbers and performs a classic "bit anding" on them.  that is, given two binary numbers:

01010101010101
01000100011100
---------------
01000100010100  <<<=== the bit and'ed result, only when BOTH bits are on...

so, if we use that number with all 1's on the end, we would only get the bits of the first number from the low two bytes.  so:


ops$tkyte@ORA920LAP> select bitand( 131075, to_number( 'ffff','xxxx') ) from dual;

BITAND(131075,TO_NUMBER('FFFF','XXXX'))
---------------------------------------
                                      3


Now, some releases of sqlplus would not recognize the output of bitand correctly, so I just added 0 to it, that made it a number always and made sqlplus happy.

 

bitand - Found the answer

Bala, June 10, 2003 - 11:19 pm UTC

Need more clarification

A reader, June 11, 2003 - 12:01 pm UTC

Version : Oracle 8.1

Tom, Sometimes, in SQL*Plus, if I give a select statement, the system seems to be hanging indefitely.
I open another session, check the lock mode, it says "3" , not "6" which means it is not exclusively locked. But then why does it hang when :
1. Multiple users are doing a "Select"
2. Multiple users are doing a "Update" of different rows in the same table.


Tom Kyte
June 11, 2003 - 7:03 pm UTC

need an example...

it doesn't work the way you describe.

you can leave the users doing select out of the equation, they do not count. unless of course, it is a select FOR UPDATE.



Procedure issue

sonali kelkar, June 11, 2003 - 3:49 pm UTC

I have a strange problem with 9.2.0 version of Oracle it it not in 8.1.7.. I have a stored procedure, it inserts a project row in work table then the trigger is fired which inserts into some other table...it comes back to the procedure.. now it inserts the task into the same work table but this when the same trigger is fired, I have a procedure with autonomous transaction to read the earlier row, it does not find it.. where is it lost, I can do dbmsoutput and see the row in original procedure, why can't the other procedure read it ? I have only one commit at the end of the original procedure.. does this have to with locking or a bug in 9.2 ??


Tom Kyte
June 12, 2003 - 8:16 am UTC

if you have this sequence of events:

a) call stored procedure
b) insert a row in T1
c) trigger on T1 inserts it into T2
d) insert a row in T1 again
e) trigger tries to read any of the rows from (b), (c), (d) using an autonomous
   transaction

(e) is fatally flawed and never worked that way in ANY release.

an autonomous transaction, by its very definition -- by its VERY definition -- is like a separate transaction.  Therefore, it can see

a) data that was committed when it begin
b) data it modifies

since the data in (b), (c), (d) is NOT YET committed, an atran in (e) will not see it.  It is easy to see this behaviour:

ops$tkyte@ORA920> create table t1 ( x int );

Table created.

ops$tkyte@ORA920> create table t2 ( x int );

Table created.

ops$tkyte@ORA920>
ops$tkyte@ORA920>
ops$tkyte@ORA920> create or replace procedure autonomous_proc
  2  as
  3          pragma autonomous_transaction;
  4  begin
  5          dbms_output.put_line( 'Enter.....' );
  6
  7          for x in ( select * from t2 )
  8          loop
  9                  dbms_output.put_line( 'data = ' || x.x );
 10          end loop;
 11          dbms_output.put_line( 'Exit.....' );
 12  end;
 13  /

Procedure created.

ops$tkyte@ORA920>
ops$tkyte@ORA920>
ops$tkyte@ORA920> create or replace trigger t1_trigger
  2  after insert on t1 for each row
  3  begin
  4          insert into t2 values ( :new.x );
  5  end;
  6  /

Trigger created.

ops$tkyte@ORA920> create or replace trigger t2_trigger
  2  after insert on t2 for each row
  3  begin
  4          autonomous_proc;
  5  end;
  6  /

Trigger created.

ops$tkyte@ORA920>
ops$tkyte@ORA920> insert into t1 values ( 1 );
Enter.....
Exit.....

1 row created.

ops$tkyte@ORA920> commit;

Commit complete.

ops$tkyte@ORA920> insert into t1 values ( 2 );
Enter.....
data = 1
Exit.....

1 row created.

ops$tkyte@ORA920> commit;

Commit complete.


<b>and you will observe exactly the same behaviour in 8i</b>

Now, if you believe they are behaving differently -- supply us a full test case as I have -- in <b>as few lines of code as humanly possible -- that is really important -- as small as you can</b>


odds are, you find your mistake in the test case generation -- i usually find mine that way.


 

YOu are the best as always....

Sonali Kelkar, June 12, 2003 - 9:01 am UTC

I tought that the code was wrong but as it works in 8i and has stopped working in 9i, I thought it was something else. I will try small test case in 8i now, like you said... because this code is huge, I may have missed something.
The sequence of events you have said is correct, thats how I want to do it... How do I do this ? I do not want to commit in the Procedure 1 untill all is done, I want to be able to rollback if anything goes wrong at any stage...

Thanks again for all your help, like always
Sonali

Tom Kyte
June 12, 2003 - 9:24 am UTC

I don't understand why you would use an atran


you do know how transactions and the ACID properties work in Oracle right? you are NOT applying SQLServers somewhat "poor" transactional practices on Oracle are you?

autonomous transactions have so few limited uses, that whenever I see them used, I immediately get suspicious -- 99999 times out of 99999+1 times, it is a bug in the developed code (to be using them)




Mutating trigger

sonali kelkar, June 12, 2003 - 10:00 am UTC

If I do not use atran I get mutating trigger error... I cannot read the table work, when a TR_ETActInsert - insert trigger on work is fired...thats the reason I have to use atran.. so I can read the row just inserted. How do I get around mutating table error then ?

I know how transaction works, atleast I feel so...no I am not using sql server logics here...
Here is the small portion of code

1. Procedure create_project

has 1st the insert into work table, for project.. this insert trigger gets fired but as enity_type=3 for project it does not do anything.. then 2nd insert is done thro' the procedure which for the task, this trigger on work insert is fired again, this time it inserts into table T2, for that its has to read the project row which was inserted before in the work table, but as I have a insert trigger on work, I cannot read the row from that table, so I used atran to achive this, but then in doing that I cannot read the earlier row because its not commited as yet, so its like cat and mouse !!
Can you help please ?

2. procedure with atran to read the project row of work table

Create or replace procedure get_project_data( inParchk in number, p_StrProjCode OUT varchar2,p_StrProjDesc OUT varchar2, p_inSelfAssign OUT number)
as
pragma autonomous_transaction;
begin

SELECT Work_Item_Code, Work_description, Work_SelfAssign
INTO p_StrProjCode, p_StrProjDesc, p_inSelfAssign
FROM work
WHERE Work_ID = inParChk;

DBMS_OUTPUT.PUT_LINE (p_StrProjDesc);
commit;
end;
/

3. Procedure with atran to get the project level, this procedure works, as it has nothing do with the project or task row inserted

Create or replace procedure get_project_level(P_inProjLevel OUT number)
as
pragma autonomous_transaction;
begin
SELECT max(Work_Level)+ 1 INTO P_inProjLevel FROM Work WHERE work_entity_type=2;
commit;
end;
/


4. Trigger without atran, which is calling the other atran procedures to read the project information.. I took out lots of code from this trigger which was not relevant to this problem..

CREATE or replace TRIGGER TR_ETActInsert
AFTER INSERT on mwebWork
For each row
Declare
-- variables here
Begin
get_project_level(inProjLevel);

SELECT Count(*)
INTO inCnt
FROM ETActivity
WHERE Act_Impt_ID = :New.Work_ID and Act_Source=20 and Act_Impt_ID is not NULL;

if inCnt = 0 then
If :New.Work_Entity_Type = 4 OR :New.Work_Entity_Type = 30 then

If :New.Work_Entity_Type = 4 then

Select :New.work_par5
into inParchk
from dual;

If inParchk <> 0 then
get_project_data(inParchk,StrProjCode, StrProjDesc, inSelfAssign);
Else
StrProjCode :='0';
StrProjDesc :='0';
inSelfAssign :=0;
End if;

-- xyz....here
ELSE
inSelfAssign := 10;
StrProjCode := 'Admin';
StrProjDesc := 'Admin';

END IF;

if inSelfAssign = 10 then
insert INTO ETActivity (a, b, c)
values ( a,b, inETManID, :New.Work_Plan_Finish,
:New.Work_Text_Ext4, StrProjDesc,
DECODE (:NEW.Work_Entity_Type, 4, :NEW.Work_MgrRevExp, 20));
End if;
End if;
end if;


end TR_ETActInsert;
/



Tom Kyte
June 12, 2003 - 10:34 am UTC

funny, I have a chapter in my new book I'm working on where I state "when I see the autonomous transaction, in a trigger, to avoid a mutating table error -- I'm almost assured that I'm looking at a bug (in the code)"


You never NEED TO READ the row you just inserted, we give it to you in the :new record in the trigger itself. You already HAVE the just inserted row value.

The only correct implementation would pass these column values as formal parameters to subroutines. do NOT read the row out of the table.

max(x)+1 -- ugg, yuck, blah -- terrible.

The mutating table constraint (believe it or not) is there to protect you from yourself. That you hit it means there is some error in your transactional way of thinking. Getting around it with an atran almost certainly means you are writing buggy code from a transactional perspective.

Not reading the latest row

sonali kelkar, June 12, 2003 - 10:46 am UTC

I guess, I wasn't clear in my last post...NO I am not reading the row just addeded..

1st the procedure inserts the project information in work table, that time when this trigger is fired it does not do anything(not supposed too)..say ROW 1 insert
Then the procedure inserts another row for the task in work table say ROW 2 insert, that time this trigger is fired again...this time I want to read the row which was inserted before ROW 1 (thro' the same procedure) but is not committed as yet... but this row, ROW 2 is not the one I want to read so I cannot user :NEW to get the value..as its ROW 1 need to be read inside trigger, if I don't use atran I get mutating trigger error...
Thanks again

Tom Kyte
June 12, 2003 - 11:18 am UTC

that logic hurts my head so badly, I cannot even fathom it.

trying to do this in TRIGGERS is just so wrong (and it never worked, not in 8i).

You have a process, seems like you do NOT want to simply insert into this table, you want to pass some data to a PROCESS and have it PROCESS the data, inserting as needed.


Tell me, if I

insert
commit
insert
commit


versus

insert
insert
commit

you cannot tell the difference, yet your trigger would think the first and second cases are the same.

I would look at removing this level of complexity, doing it simple, straightforward, with as little code as possible (less bugs that way)

Yes, you are right...always I guess

sonali kelkar, June 12, 2003 - 12:05 pm UTC

I tried small test case in both 9.2 and 8.1.7... the realized what was happening in the original code.. there was call to other procedure right after the 1st insert which was commiting not in the 2nd case... so I was getting no data found error...
Here is the test case I created

set serveroutput on;
drop table t1;
drop table t2;

create table t1 ( x int, y int );
create table t2 ( x int, y int );


create or replace procedure pr_checkcommit
as
begin
dbms_output.put_line('Ooooops other proc committing it ! ');
commit;
end;
/

create or replace procedure test_proc
as
begin
dbms_output.put_line( 'Enter.....' );
insert into t1 values(10, 15);
pr_checkcommit;
dbms_output.put_line( 'commit done.....' );
insert into t1 values(20, 30);
dbms_output.put_line( 'Exit.....' );
commit;
end;
/

create or replace procedure t2_proc (inrow1 in number, p_test OUT number)
as
pragma autonomous_transaction;
begin
dbms_output.put_line( 'IN the aTRAN.....' );
select y into p_test from t1 where x=inrow1;
end;
/

create or replace trigger t1_trigger
after insert on t1 for each row
declare
testrow1 int;
begin
dbms_output.put_line( 'IN the trigger.....' );
if :new.x = 20 then
t2_proc(10,testrow1);
insert into t2 values ( :new.x, testrow1 );
end if;
end;
/

execute test_proc;

If I comment out call to teh procedure pr_checkcommit I get error !! It took me 2 days to figure out what was different in both cases.. sometimes making small test case does HELP !!

I still have to NOW figure out what and how to change this code to make it work !

If you have any suggestions for that I will much appreciate it.

Thanks for help

Sonali


Tom Kyte
June 12, 2003 - 1:05 pm UTC

my suggestion is and will be:

forget the triggers. This is something that should be "front ended". someone calls a procedure that does the right thing, rather they trying to have 15 mysterious side effects from magic triggers to make things "look transparent"

One more try on row level locks :-)

Piotr Jarmuz, August 13, 2003 - 11:56 am UTC

Hello Tom,

Just one more try on how to get the info row level locks. I have read your book and know less or more the Oracle architecture. And I think there is teoretically a way to learn who is locking a particular row even without getting blocked.



So let's have a scenarion:

Session A locks one or more rows in table T with the following DML:

"update T set x=x+1 where y='foo'"

so, now

v$lock has the following entries:

1. TM shared lock on Table "T" by session A
2. TX(1234) transaction row (not associated with a particular object nor row)

After that table "layout" may look less or more like this:



TABLE "T"
--------------------------------------

--------------------
block #1
--------------------
Transaction Table
TX1(1234)
TX2
...

TXn
--------------------
Row directory
*(TX1) row100
row101
...

row110
--------------------

DATA
....
--------------------




--------------------
block #2
--------------------
Transaction Table
TX1(1234)
TX2
...

TXn
--------------------
Row directory
row110
*(TX1) row111
...

row120
--------------------

DATA
....
--------------------

* - rows are locked by session A (locks in Oracle are attributes of data)


Suppose that this query started the transaction ID=1234 and locked row100 in block #1 and row111 in block #2 in table "T". So entry in the row directory for row100 and row111 point to the transaction table entry TX1 in transaction table on corresponding blocks which in turn point to the TX lock seen in v$lock.

Now Session B executes "select * from T where y='foo' for update nowait" and then query goes to block1 finds row100 and sees it points to TX1 entry which holds TX ID=1234 and is still active. So now the row is locked and Oracle raises ORA-00054 Resource Busy Exception but it at least has theoretical knowledge of EXACTLY who locked that particular row. If the session B issued query without "nowait" option we would get TM lock entry with value of request=6 and we could know who is blocking who. But with nowait option that knowledge seem to be lost.

Sure there could be potentially many blockers to have locked session B. And we wouldn't be sure who exactly blocked us.
But at least in keyed queries by session B (0 or more rows returned) we would know exactly the blocker even with nowait option.

So if this is a theoretically possible then maybe it is also doable in practice?

If I am wrong please, correct me.

P.S.

I have exactly such a situation in my project (keyed selects for update) and I need to know who is locking my row (or object as I have OO approach on top of RDBMS). Currently I have a work-around for that with an extra table that stores Oracle session SID and IDs (primary key, all objects have surogate integers as PK which also allows for simple and efficient polymorphism, objects know the class they belong just by their ID) of locked objects that are inserted by a lock() method (the one doing select for update) and commited as autonomous transactions so that the blockee may get to learn the blocker.

All accesses to tables are exclusively via stored procedures, tables are invisible to users so this is OK but adds a performance overhead. I wondered if there would be faster way to do it using that internal Oracle info?

Best regards.


Tom Kyte
August 13, 2003 - 12:11 pm UTC

whether it is "theorectically" possible (it could be) isn't relevant. It doesn't happen.


good luck with your oo stuff.


still don't see why "bob" needs to know "mary" had the object. what is "bob" going to do about it?



BTW, I'm so glad this site is back

Shrek from DC, August 13, 2003 - 12:18 pm UTC

I don't know if the problem was on the asktom end or mine. I couldn't access asktom from home or work for about a day.

--Shrek.

Tom Kyte
August 13, 2003 - 12:26 pm UTC

it was a power failure caused by a backhoe ;)

Lock info

Piotr Jarmuz, August 13, 2003 - 12:31 pm UTC

In need that because so says specification :-). Although I was one of the designers I thought it would be a peanut in Oracle and agreed to this requirement...

This is going to be (among others) CMS system where many web editors will work with objects: like articles, items, users... etc. And they will possibly work remotely. And in case if someone locks an object and goes away from terminal (end users tend to do so) that I also need to edit it will help me a lot to know who did that so that I can call him and ask what's going on. There is also a hard limit implemented with user profiles on an idle session but I believe it is better to be co-operative as humans. It is more of a sociological requirement rather than technical.

One more correction to my previous post: keyed query is of course 0 or 1 (not 0 or many).

Thanks for your good-luck-wish. Working with Oracle is fun as much as reading your forum.

Regards.

Tom Kyte
August 13, 2003 - 12:43 pm UTC

terminal application should time out locks then.

and if they are remote, again - what is bob going to do when he finds out mary has his object and mary is gone to lunch? how does bob know shes at lunch? what can bob do about it?

urgent - select on system tables hangs!

A reader, August 20, 2003 - 10:15 pm UTC

Hi Tom
We have a situation where the following select
seems to hang (in a customer system). usually selects
should not hang - so I am wondering whether their
database system schema is messed up (e.g. lost indexes etc) - even then when and why can a select hang?!
In a similar sized database, this select works
just fine.
Any clues?

Thanx for an awesome site!


-
SELECT A.TABLESPACE_NAME oracle_database_tablespace,
B.FILE_NAME file_name,
B.BYTES sizeb,
SUM(A.BYTES) free
FROM DBA_FREE_SPACE A,DBA_DATA_FILES B
WHERE
A.FILE_ID = B.FILE_ID
GROUP BY
A.TABLESPACE_NAME, B.FILE_NAME, B.BYTES

Tom Kyte
August 21, 2003 - 6:01 pm UTC

might not be hung, might be a database with billions of dictionary managed extents or something

look in v$session_event or v$session_wait to see what it is doing/waiting for

Re: urgent - select on system tables hangs!

A reader, August 21, 2003 - 5:43 pm UTC

Hi Tom
The sql wasnt hanging - it took some 5 hours to
get around 300 odd records!!! I think their database's
system accounts are perhaps messed up...

Thanx!

Tom Kyte
August 21, 2003 - 7:28 pm UTC

look for lots of dictionary managed extents.

right you are as always!

A reader, August 21, 2003 - 6:14 pm UTC

"might not be hung, might be a database with billions of dictionary managed
extents or something

look in v$session_event or v$session_wait to see what it is doing/waiting for
"
Yup it was not hung - just took 5 hours or so to
complete!
How does the DMT affect a select statement. What can
a select be waiting on - I was thinking that a select
is never "blocked" by any locks?

If the above is the issue - then apart from the suggestion
of moving to LMT (a long term solution), is their
anything else we can do in the short term(e.g. reduce the
number of extents or any other DBA stuff?)

Thank you so much!!!!



Tom Kyte
August 21, 2003 - 7:31 pm UTC

it wasn't blocked -- it just had a gazillion rows to process.

reducing the extents would help -- but it takes a really really really long time to significantly reduce extents.

thanx Tom!

A reader, August 21, 2003 - 8:48 pm UTC

"it just had a gazillion rows to process. "

I am not able to understand why you have to allocate
extents during select. In this table one table has around 3000 rows - the other has around 300 rows. For
all other customers this query returns in minutes.
So, what exactly is causing this select to process
so many rows - is it some recursive sql that gets
executed?

Thanx!!!

Tom Kyte
August 22, 2003 - 8:23 am UTC

version?



hi Tom!

A reader, August 22, 2003 - 1:25 pm UTC

It is 8.1.7.3


The exact # of records in dba_free_space = 2266
and in dba_data_files = 374

Thank you so much!!

Tom Kyte
August 22, 2003 - 8:05 pm UTC

if you do a "set autotrace traceonly explain" -- what does their plan look like?

cbo
or
rbo?

do you see cost/card/bytes or not??

ok here is some more info

A reader, August 22, 2003 - 3:15 pm UTC

I found the id of the session1 by using
select sid from v$mystat where rownum = 1;
the answer was 75

Then I ran the following query in session2
select sid, event, time_waited , total_waits , average_wait
2 from v$session_event
3 where rownum <= 10
4 and sid = 75
5 order by time_waited desc, total_waits desc, average_wait desc;

This gave me a before snapshot of top 10 events as
follows:
----
SID EVENT TIME_WAITED TOTAL_WAITS AVERAGE_WAIT

---------- -------------------- ----------- ----------- ------------

75 SQL*Net message from 58530 90 650.333333

client

75 db file sequential r 17 28 .607142857

ead

75 latch free 3 3 1

75 control file sequent 1 31 .032258065

ial read

75 SQL*Net message to c 0 92 0

lient

75 file open 0 7 0

75 SQL*Net more data to 0 6 0

client

75 SQL*Net break/reset 0 3 0

to client

75 refresh controlfile 0 2 0

command
----


Then I ran the problem query in the session1 (id = 75).

After sometime I ran the same query as above in session2
to get an "after" snapshot as follows:
---- after snapshot

SID EVENT TIME_WAITED TOTAL_WAITS AVERAGE_WAIT

---------- -------------------- ----------- ----------- ------------

75 SQL*Net message from 67115 95 706.473684

client

75 db file sequential r 18 146 .123287671

ead

75 latch free 11 8 1.375

75 db file scattered re 10 90 .111111111

ad

75 control file sequent 1 69 .014492754

ial read

75 SQL*Net message to c 0 97 0

lient

75 file open 0 8 0

75 SQL*Net more data to 0 6 0

client

75 refresh controlfile 0 4 0

command

75 SQL*Net break/reset 0 3 0

to client

----

The problem query of course is still going strong.
the db file scattered read event perhaps indicates
a full table scans (or full index scans)

Please let me know if you need any more data and
how to get it?

Thanx a ton!!



thanx Tom!!!!

A reader, August 22, 2003 - 8:13 pm UTC

"if you do a "set autotrace traceonly explain" -- what does their plan look like?

cbo
or
rbo?
"

Unfortunately, I cannot do an autotrace - the plan table
does not exist!! Since it is a customer set up I don't have
the system login :( ...Is there any other way to find out
if a query is using RBO or cbo? Sorry to keep bothering you!! Anyways, how does it matter - I mean what
would your answer be if I said CBO (which is 99% likely
given our product is supposed to follow CBO)?

I guess you may be thinking along that if it is CBO and if
stats have not been generated (do the system tables
also need stats????) then that may explain - if we get say
a lousy plan for that select...

Thank you!!

Tom Kyte
August 23, 2003 - 10:16 am UTC



there was a release where a hint was accidently added to a data dictionary view that made queries of this fashion go really bad (cause the dictionary wasn't analyzed).

you can create a plan table on your own, $ORACLE_HOME/rdbms/admin/utlxplan.sql has the schema.

Gr8

Bipin Ganar, August 23, 2003 - 1:09 am UTC

Hi Tom,
here i have small question
I have one table 138 people are using that table.
One of the user got into deadlock. While trying to
insert the same table by the user gets hanged
Is there any way i can automatically remove /Kill session
if deadlock occurs after 1/2 Hour (Any parameter to set in file)


Tom Kyte
August 23, 2003 - 10:25 am UTC

deadlocks are automatically detected and one of the offending statements is aborted within 3 seconds.

please clarify what you mean by deadlock.

table lock in share or exclusive more

A Reader, August 23, 2003 - 12:42 pm UTC

Tom, I was reading the online doc re lock table <tablename> iN share (S) or share row exclusive (SRX) exclusive mode. It says, it is implicitly used for referential integrity. Could you please help me in understanding how and why oracle uses these table level locks to maintain referential integrity? also, is this why we need index on foreign key columns? thanks and I appreciate your time.

Tom Kyte
August 23, 2003 - 3:30 pm UTC

always helps to have a pointer to what you were reading so I can see it in context. but:

</code> http://docs.oracle.com/docs/cd/B10501_01/server.920/a96524/c22integ.htm#2161 <code>

describes the 9i behaviour with locking and fkeys. there are similar chapters in the 8i and before docs as well. (concepts guide)

thanx Tom!!

A reader, August 23, 2003 - 2:10 pm UTC

"there was a release where a hint was accidently added to a data dictionary view
that made queries of this fashion go really bad (cause the dictionary wasn't
analyzed).

you can create a plan table on your own, $ORACLE_HOME/rdbms/admin/utlxplan.sql
has the schema. "

Hi tom
Do you know what release it was (Was it 8.1.7.3)?
Most likely we are using CBO - I can confirm and
get back! Is there any metalink reference for this?
Unfortunately, I can't
create anything (including a plan table)
in this schema as it is a customer database. Thanx for your help so far!!

Tom Kyte
August 23, 2003 - 6:26 pm UTC

ask your customer to do it in order to help you RESOLVE THEIR ISSUE.

I forget the release 8.1.something -- could be .7.3 -- believe it was 816 but only 8174 has all patches.

Tom

A reader, August 23, 2003 - 2:20 pm UTC

"there was a release where a hint was accidently added to a data dictionary view
that made queries of this fashion go really bad (cause the dictionary wasn't
analyzed).
"

I guess, one solution is to try and analyze the affected
tables and then rerun the query then?


Tom Kyte
August 23, 2003 - 6:27 pm UTC

or fix the view def, yes, but the tables in question are DICTIONARY tables which you would have to analyze ALL of and then test.



another questions

A reader, August 23, 2003 - 2:41 pm UTC

Just realized that the dba_Data_files and dba_free_space
are views basedon some system tables. If we want to
analyze them we would have to analyze the underlying tables, right?

Thanx!!!!

Tom Kyte
August 23, 2003 - 6:27 pm UTC

yah

sorry Tom!

A reader, August 23, 2003 - 7:34 pm UTC

I just found out that the db was 8.1.7.4 - (someone
gave me wrong info)!
Sorry about that - my only guess is that the dba tables
have not been analyzed properly.

Also, I know that app tables should be analyzed periodically using monitoring + gather stale stats
- is it the same in case of system tables?

Thanx and I apologize once again for the wrong info
about the patchset version of the database.

Tom Kyte
August 23, 2003 - 8:01 pm UTC

i would need a tkprof to comment further.

hi Tom!

A reader, August 26, 2003 - 8:36 pm UTC

I don't have the tkprof, but I have confirmed that
none of the underlying tables have been analyzed!

My understanding is that the data dictionary tables
should be analyzed. Now these tables don't change a
lot( that too depends but in general,) but at least
they should have been analyzed once!

btw, do the data dictionary tables use the monitoring clause so that
we can periodically use the "gather stale statistics"
approach. What is the best practice when it comes
to analyzing data dictionary tables - are there
any differences when compared to application tables
that one should be aware of?

Thanx!
PS: btw, I found that a utiity that gives you all the
tables underneath a view (expanding any other views)
would be useful - Do you know of or have such a utility?



Tom Kyte
August 27, 2003 - 7:59 am UTC

in 8i, probably you don't want to analyze the dictionary
in 9i, yes, you very well might
in future releases -- definitely.


as for the view thing -- *_DEPENDENCIES will give you that info.

thank you Tom!

A reader, August 27, 2003 - 11:19 am UTC

The tip on *_dependencies is useful.

Is it possible for you to briefly elaborate on why
we don't need to analyze data dictionary tables in 8i and why in 9i and future versions we need to analyze these tables?

Thank you soooo much!!!

Tom Kyte
August 27, 2003 - 5:58 pm UTC

in 8i -- it is supported, but generally not needed.... if you haven't been doing it, no reason to start (no need to change that which is working)

in 9i, it is supported and many do it.

in 10 -- the rbo is not supported anymore.

thanx Tom!

A reader, August 27, 2003 - 6:34 pm UTC

so it is RBO usage etc that is dictating this
decision. I guess in 9i, you perhaps lose more of the
enhancements if you dont do CBO - hence a little more
compelling reason to do it.

Thanx!

question...

A reader, September 16, 2003 - 2:54 pm UTC

"SELECT A.TABLESPACE_NAME oracle_database_tablespace,
B.FILE_NAME file_name,
B.BYTES sizeb,
SUM(A.BYTES) free
FROM DBA_FREE_SPACE A,DBA_DATA_FILES B
WHERE
A.FILE_ID = B.FILE_ID
GROUP BY
A.TABLESPACE_NAME, B.FILE_NAME, B.BYTES
"

In your new book on page 495.
You specify a rownum based trick for "Join Queries"
In the above case also, we had views where individual
queries to views were very fast (minutes) but the join took
more than 5 hours - in 8174 database.
Do you think the same trick can be applied in this case?
(Wanted to verify with you before I try and run it in
the customer machine)

Tom Kyte
September 16, 2003 - 6:11 pm UTC

why don't you try it on your machines?

if the two individual queries run fast -- doing the rownum trick almost always works.

what I mean is an alternative query like

A reader, September 16, 2003 - 4:08 pm UTC

SELECT A.TABLESPACE_NAME oracle_database_tablespace,
B.FILE_NAME file_name,
B.BYTES sizeb,
SUM(A.BYTES) free
FROM (select *, rownum from DBA_FREE_SPACE) A,
(select *, rownum from DBA_DATA_FILES) B
WHERE A.FILE_ID = B.FILE_ID
GROUP BY A.TABLESPACE_NAME, B.FILE_NAME, B.BYTES


Tom Kyte
September 16, 2003 - 6:22 pm UTC

should be more like

select ...
from ( select <just columns you need>, sum(bytes) from dba_free_space where rownum >= 0 group by <just columns you need> ) a,
( select <just columns you need> from dba_data_files where rownum >= 0 ) b
where ....

thanx Tom!

A reader, September 16, 2003 - 6:20 pm UTC

"why don't you try it on your machines?

if the two individual queries run fast -- doing the rownum trick almost always
works.
"
In our machine the problem is not reproducible - All
queries run pretty fast.
Anyways, I have passed it to the elevant people who
should get back to me. I will let you know what happens
Thanx a lot!!!

oops!

A reader, September 16, 2003 - 6:25 pm UTC

"should be more like

select ...
from ( select <just columns you need>, sum(bytes) from dba_free_space where
rownum >= 0 group by <just columns you need> ) a,
( select <just columns you need> from dba_data_files where rownum >= 0 )
b
where ....
"

So the query that I gave - is it not equivalent to
the original query - or you are suggesting a more performant alternative?

Thanx!

Tom Kyte
September 16, 2003 - 8:20 pm UTC

you should aggregate dba_free_space and then join to dba_datafiles -- that is what that (my) query does.

instead of joining to every row in dba_free_space and then aggregating

the two queries do the same thing, just one of them should do less work

aggregate, then join

instead of

join, then aggregate.

sorry to repost

A reader, September 16, 2003 - 6:27 pm UTC

Sorry Tom - I actually already forwarded a query as:

"SELECT A.TABLESPACE_NAME oracle_database_tablespace,
B.FILE_NAME file_name,
B.BYTES sizeb,
SUM(A.BYTES) free
FROM (select file_id, tablespace_name, bytes, rownum from DBA_FREE_SPACE) A,
(select file_id, file_name, bytes, rownum from DBA_DATA_FILES) B
WHERE A.FILE_ID = B.FILE_ID
GROUP BY A.TABLESPACE_NAME, B.FILE_NAME, B.BYTES;
"

This one should be equivalent to the original query.
The one that you suggested - I am not sure whether that
is a performance improvement or a correction!

Sorry for the hassle!!

thanx Tom!!

A reader, September 17, 2003 - 11:13 am UTC

for your help!!!!!!

FZ, September 18, 2003 - 5:29 pm UTC

Tom, in case of serial blocking (e.g., A blocks B, B blocks C, and C blocks D), how to find the order of blocking (A->B->C->D)? It seems v$lock (or dba_lock) only shows A blocks others.

Tom Kyte
September 18, 2003 - 5:59 pm UTC

if a is blocking b. and b is blocking c. then v$lock will show you a blocks b. b blocks c. and so on.

utllockt (in $ORACLE_HOME/rdbms/admin) shows a little tree -- but it v$lock would show c getting blocked by b if b was blocking C

FZ, September 18, 2003 - 8:06 pm UTC

Tom,  here's an example:
sid=12: delete from tt;
sid=16: delete from tt where a=1;
sid=11: delete from tt where a>=1;

SQL> select * from v$lock where sid in (12,16,11);

ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
-------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
13B4E17C 13B4E190         11 TM      30687          0          3          0          0          0
142BDDF0 142BDE00         11 TX     327727      20151          0          6          0          0
13B890B0 13B891BC         12 TX     327727      20151          6          0         20          1
13B4E074 13B4E088         12 TM      30687          0          3          0         20          0
13B4E0F8 13B4E10C         16 TM      30687          0          3          0         10          0
142BDDA4 142BDDB4         16 TX     327727      20151          0          6         10          0

I understand #11 is not blocked directly by #16 now, but it'll happen when #12 release the lock. 
How to find #16 (not #11) will be the next one on the waiting list? 

thanx Tom!!!

A reader, October 05, 2003 - 11:21 am UTC

"you should aggregate dba_free_space and then join to dba_datafiles -- that is
what that (my) query does.
"

I am the reader who asked you for a solution - The
rownum trick from your book coupled with above tip
helped me solve the issue!!!

Please keep up the great work - You are the best!!

Insert ... Select .. For Update

A reader, November 04, 2003 - 9:30 pm UTC

Hi Tom,

I tried sth. like the following in SQL:

CREATE TABLE TAB2 AS SELECT * FROM TAB1 WHERE 1 = 0;

INSERT INTO TAB2 SELECT * FROM TAB1 FOR UPDATE;

It doesn't allow me to use the FOR UPDATE clause.

Do I have to issue a separate SELECT statement for locking the rows?

Tom Kyte
November 05, 2003 - 8:07 am UTC

yes.

A reader, November 12, 2003 - 12:58 pm UTC

Tom,
If there is a solution, you have it. Our database, once in few weeks, suddenly starts getting into "one session starts blocking all others" mode. This happens typically for a couple of minutes. Since the database is heavily used, the number of users sessions being blocked may increase up to more than 200. Sometimes this condition clears on its own, sometimes we have to kill the blocker. Do you have a script which I can run in this 2-3 minute interval (as a shell script or batch file) which spools the following information to a file:
a) Which session(s) is the blocker, including username(s).
b) which session(s) the blocker is blocking, including username(s).
c) Which SQL statement the blocker is running which resulted in the block.
d) Which statements the blocked sessions were trying to run when blocked.

There are many scripts on Metalink, but I am not sure if they will work or are they good enough for 9i. Some of them cannot be automated. The narrow time window will not permit me to substitute 200 session IDs in an IN list.

Thanks

Tom Kyte
November 12, 2003 - 4:45 pm UTC

you have a, b here.

to get c, d, you just need to also run my "showsql.sql" script.

you'll have everything. if you want to "merge them", go for it.

A reader, November 13, 2003 - 9:58 am UTC

Tom,
I tried to run the following script in the database:
tkyte@TKYTE816> select username,
2 v$lock.sid,
3 trunc(id1/power(2,16)) rbs,
4 bitand(id1,to_number('ffff','xxxx'))+0 slot,
5 id2 seq,
6 lmode,
7 request
8 from v$lock, v$session
9 where v$lock.type = 'TX'
10 and v$lock.sid = v$session.sid
11 and v$session.username = USER
12 /

It takes upwards of 2 minutes to return results. Sometimes it just seems to hang and no results even after 5 minutes. Looks like the more the number of sessions, the longer it takes. When the database experiences the problem, the number of user sessions can go into several hundered. Is there a way to make this script faster so it returns results quickly.
Thanks


ITL and Unindexed Foreign Keys Lock

Vivek Sharma, December 20, 2003 - 2:16 pm UTC

Dear Tom,

Based on the understanding from this site, please let mw know whether I have understood the Locking issues in terms of ITL and Unindexed Foreign Key cases.

In the case of ITL (Max Trans too low) :

The request column of the waiter will have a value 4 and type 'TX' with id1 and id2 pointing to anyone of the blockers (probably the first one). It won't have its own TX entry since the transaction did not began at that point of time.

Whereas in case of Unindexed Foriegn Key

The request column of the waiter will have a value 4 and type TX with id1 and id2 pointing to the blocker and will also have its own id1 and id2 with request as 0.

Am I correct ?

Question 2:

In your book Expert one on one, you have showed alongwith the example that 2 sessions are simulataneously inserting rows into a table with freelist 1. Data Block waits were increased due to this. When the freelist was increased to 2, the waits of Data Block remain constant (did not increase).

I am confused here. I use to think that if the waits on Data blocks is too high then I need to Increase Initrans or set the Pctfree / pctused paramaters to accomadate lesser rows in a block and if the waits on segment header is too high, I need to increase freelist. But your example shows that the waits on freelists increases the data block waits. Can you please clarify my above doubts.

Regards
Vivek


Tom Kyte
December 20, 2003 - 3:53 pm UTC

<quote>
The request column of the waiter will have a value 4 and type 'TX' with id1 and 
id2 pointing to anyone of the blockers (probably the first one). It won't have 
its own TX entry since the transaction did not began at that point of time.
</quote>

well, how could it have a TX record if it doesn't have a TX record? :)  you sort of contradict yourself.

A small test was easy to set up.

In one session:


drop table t;
                                                                                                                    create table t ( x int ) initrans 2 maxtrans 2;
                                                                                                                    insert into t select rownum from all_users;
commit;
select distinct dbms_rowid.rowid_block_number(rowid) from t;
                                                                                                                    update t set x = x where x = 1;


Now, open two more windows and in the second:
update t set x = x where x=2;

and in the third
update t set x=x where x=3;

What I observed was:

ops$tkyte@ORA920> select sid, type, id1, id2, lmode, block, request from v$lock where sid in ( 8, 9, 11 )
  2  /
 
       SID TY        ID1        ID2      LMODE      BLOCK    REQUEST
---------- -- ---------- ---------- ---------- ---------- ----------
         8 TX     131106      68619          6          0          0
         8 TM      59314          0          3          0          0
         9 TX     458777      67872          6          1          0
         9 TM      59314          0          3          0          0
        11 TM      59314          0          3          0          0
        11 TX     458777      67872          0          0          4
 
6 rows selected.


the blocked sid (11) is actually blocked waiting on the SECOND (not the first here -- but that doesn't "prove" it couldn't be the first, just proves that it doesn't have to be the first).

It does have a TX record. 



The blocked fkey is also easy to setup (you all can try these things yourselves!!! you too have the power.  simulations are the way to learn -- it is how i figure out most of the answers here!)


Run this in session 1:

create table p ( x int primary key );
create table c ( x references p );
                                                                                
insert into p values ( 1 );
insert into c values ( 1 );
insert into p values ( 2 );
commit;


In another window, do this:

insert into c values ( 2 );


and then in the first window do this:

update p set x=x where x=2;
 

Now, in a free session, look at v$lock (remember, change the sid's to be the sid's on your system!)
ops$tkyte@ORA920> select sid, type, id1, id2, lmode, block, request from v$lock where sid in ( 8, 9, 11 );
 
       SID TY        ID1        ID2      LMODE      BLOCK    REQUEST
---------- -- ---------- ---------- ---------- ---------- ----------
         8 TM      59330          0          0          0          4
         8 TM      59328          0          3          0          0
        11 TX     262179      69553          6          0          0
        11 TM      59330          0          3          1          0
        11 TM      59328          0          2          0          0

See -- now you can see for yourself exactly what will happen and when.



As for q2 -- data block waits are caused by many many things.  You could be waiting for some other session to read the block into the buffer cache, you could have itl issues, you could be contending for the data block that is the head of the freelist (as was the case in my example in the book).

I removed the contention by having sufficient freelists.  In 9i, you might look at ASSM (automatic segment space management) in order to not have to think about freelists as well.

 

ITL and Freelist Waits

Vivek Sharma, December 22, 2003 - 9:28 am UTC

Dear Tom,

Thanks a lot for your prompt reply. I think this forum is for Locking but unnecessarily I am asking this question on Data Blocks Contention.

Question 1
----------
Uptill Now, my thinking for the solution for wait events were( Please correct me if I am wrong) :

1. Waits on Data Blocks : Increase PCTFREE / Decrease PCTUSED to reduce number of rows in a block which will decrease the contention on a block. Else Increase the value of Initrans.

2. Waits on Segment Header : Increase value of Freelist of tables.

3. Waits on Undo Header : Increase the number of Rollback Segments as there is a contention on Transaction Table of Rolback Segment which reside on the Header of RBS.

4. Waits of Undo Block : Increase the Size of the rollback segments.

Please let me know if I am correct in my approach.

Question 2
----------
Also if the freelist contention can cause wait event on Data Block (as demonstrated in your book Expert One on One) then what does segment header wait events specify and what is the remedy to remove the waits on this.

Question 3
----------
Suppose my approach to increase pctfree and decrease pctused to lower the number of rows in a table so as to reduce the waits on Data Block then I need to recreate the object with this new setting. Because if the change the settings this will only be applicable for new blocks. If I recreate the object with this new settings, will it not affect the query response time of the queries.

Suppose I have a query which fetches row 1 and 10 from a table which are on same block. The user process will get the block from the disk to buffer and fetch both the rows from same block.
If the settings are changed and assuming these rows are splitted into 2 different rows, then user process will now have to read 2 blocks into buffer and then fetch the rows.

Will it affect the performance ?

Though these are all taken care off in Oracle 9i but since many sites are still on Oracle 8i, these answers will help me understand the importance and remedies of each and every wait events listed in v$waitstat.

Thanks and Regards,
Regards
Vivek



Tom Kyte
December 22, 2003 - 10:11 am UTC

q1) that is basically the rule of thumb advice found in support note Article-ID: <Note:62172.1>, yes. (but they have a tad more there)

q2) can be caused by rapid growth of an object (extends). not normally an "issue"

q3) and it is mostly NEW blocks that have the issue (it is adding data to the table)

it could increase OR decrease OR do nothing to the query response time. Fewer rows/block -- less in the buffer cache, longer full scans perhaps. (for example)

Waits on Data Blocks

Vivek Sharma, December 23, 2003 - 3:54 am UTC

Thanks a lot Tom for your quick response. I have gathered some more usefull information from this website and Metalink and have understood the waits on Segment Header. Thanks a lot.

The o/p of my v$waitstat shows

SQL> select * from v$waitstat;

CLASS                   COUNT       TIME
------------------ ---------- ----------
data block            9855031   14458609
sort block                  0          0
save undo block             0          0
segment header            760      86212
save undo header            0          0
free list                   0          0
extent map                 20         73
bitmap block                0          0
bitmap index block         27         78
unused                     28        844
system undo header          0          0
system undo block           0          0
undo header             50198    4523398
undo block             293738     332357

and my following query shows the output as 

select startup_time, current_time, class, waits / time_elapsed * 100 "Time Waited %age"
from (
select to_char(startup_time,'dd-mm-yyyy hh24:mi') startup_time,
       to_char(sysdate,'dd-mm-yyyy hh24:mi') current_time,
(sysdate-startup_time)*(24*60*60) time_elapsed, time waits, class
from v$instance, (select class, time/100 time from v$waitstat ))
/

STARTUP_TIME     CURRENT_TIME     CLASS              Time Waited %age
---------------- ---------------- ------------------ ----------------
21-12-2003 14:20 23-12-2003 14:05 data block                    84.95
                                  sort block                      .00
                                  save undo block                 .00
                                  segment header                  .50
                                  save undo header                .00
                                  free list                       .00
                                  extent map                      .00
                                  bitmap block                    .00
                                  bitmap index block              .00
                                  unused                          .00
                                  system undo header              .00
                                  system undo block               .00
                                  undo header                   26.31
                                  undo block                     1.94

14 rows selected.

It shows almost 85% of the time my users are experiencing waits on Data Blocks. I should seriously consider increasing the value of freelist for those tables which have concurrent inserts and updates. 

Please let me know whether my findings (as per my query above) is correct. Out of 48 hours of total uptime, 85% of the time users waiting is too much.

Thanks and Regards
Vivek
 

Tom Kyte
December 23, 2003 - 11:12 am UTC

waits on data blocks can be for many reasons, but yes, if you have a hot table or hot block -- by all means, use the tools at your disposal to fix it.

What is exchange deadlock

Arun Gupta, January 20, 2004 - 11:10 am UTC

Tom,
Recently, in a statspack report we saw exchange deadlock. From Metalink, we found that exchange deadlock is same as buffer deadlock. Is that correct? What exactly is an exchange deadlock?
Thanks

Tom Kyte
January 20, 2004 - 2:02 pm UTC

defined: "exchange deadlocks" is the number of times that a process detected potential deadlock when exchanging two buffers and therefore raised an internal, restartable error. Index scans are currently the only operation which perform exchanges.

Multiple SQLs slower the response

Wor, January 29, 2004 - 5:08 pm UTC

Hello Tom,
I am running on Win 2000 , Oracle 8.1.7.
I have one SQL query which has around 7 joins ( including some outer joins ) returns 65K rows, 12 columns , It takes 3 minutes to execute from one machine one at a time.
But If I execute the same SQL query simultaneously from 10 different client machines on the same Oracle server after 15 minutes the results are displayed on all 10 machines.
I am sure Oracle should be much more powerful than this.
On just 10 users that same SQl takes three times more time to execute. What will happen if 1000 users request the SQL execution, with this rate the same SQL will take Hours.
Can some thing be done to increase the performance ?

In ideal case I will have different SQL's running simultaneosly, more or less the Tables will be the same, thats why here for this example I used the same query 10 times.
Thanks in advance,
Wor

Tom Kyte
January 30, 2004 - 8:01 am UTC

Umm, you haven't told anyone about anything here that could let them say anything useful.


how big is this win 2k machine. If I hit my laptop with 10 concurrent users -- guess what happens.

You size your hardware based on your desired load. Oracle cannot makeup CPU and disk speed out of thin air. You have to have hardware able to accomodate your load.

Very good information

Emmett Cleveland, February 17, 2004 - 4:34 pm UTC

Tom, I have learned a lot from your site and your book.
I am not sure if this is the proper thread but I am looking at a lock type, under v$lock, of "TO".
I can not find this lock type on metalink or in any Oracle Doc.
Could you please explain what type of lock this is?


Tom Kyte
February 17, 2004 - 7:12 pm UTC

The TO enqueue protects concurrent DDL operations on temporary
tables. It is acquired in exclusive(X) mode during ALTER, DROP and CREATE
operations on a temporary table or its indexes.

Acquired in SX mode when performing DML against a temporary object
Acquired in S mode for DDL index operations.

The purpose of the lock is to prevent DDL from being issued against an
object while DML is occurring.

Answered my own question.

Emmett Cleveland, February 17, 2004 - 5:11 pm UTC

Sorry to waste your time, I found the answer to my post about TO lock type,
It is a lock that was introduced in 8i that controls DDL for temporary tables.


A reader, February 18, 2004 - 4:57 am UTC

very useful

about maxtrans

lizhuohua, February 23, 2004 - 10:26 am UTC

Dear tom,

This puzzles me:

create table p(x int) maxtrans 1;
insert into p values(1);
insert into p values(2);
commit;
update p set x=3 where x=1;
1 row updated.


in another sql/plus:

update p set x=4 where x=2;
1 row updated.


select sid, type, id1, id2, lmode, block, request
from v$lock where type='TX';


SID TY ID1 ID2 LMODE BLOCK REQUEST
---------- -- ---------- ---------- ---------- ---------- ----------
10 TX 327721 2709 6 0 0
15 TX 655390 2699 6 0 0

Why the "maxtrans" doesn't work?

(select * from v$version;
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for 32-bit Windows: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production)

Tom Kyte
February 23, 2004 - 10:35 am UTC

maxtrans is silently now 2 regardless of what you set it to in 9i and above.

maxtrans

Alberto Dell'Era, February 23, 2004 - 12:22 pm UTC

> maxtrans is silently now 2 regardless of what you set it to in 9i and above.

You mean "AT LEAST 2", i suppose ... ?

Tom Kyte
February 23, 2004 - 4:41 pm UTC

ahh, yes, of course :)

thanks for pointing that out.

Thanks

A reader, February 24, 2004 - 7:08 am UTC

Thanks a lot Tom for your help!

INSERT NOWAIT

Cefers.br, March 02, 2004 - 7:20 am UTC

Tom,

If a session inserts into a table that has a PRIMARY KEY and doesn´t COMMIT, any other sessions that try to insert records with the same PRIMARY KEY will be locked until the first session commits.

In this case, I want the second session to receive an error message instead of being locked until COMMIT. It would be something like NOWAIT clause on SELECT FOR UPDATE.

Is it possible?

(I´m using 9iR2)

Tom Kyte
March 02, 2004 - 8:10 am UTC

I'd really want to look at why I was generating the same primary key first and foremost but....

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:340617419132 <code>

shows how you can accomplish this.

dba_dml_locks & dba_ddl_locks

Sami, March 02, 2004 - 9:36 pm UTC

Dear Tom,

What is the use of "dba_dml_locks" and "dba_ddl_locks"

Select count(*) from dba_dml_locks;
0 record.

Select count(*) from dba_dml_locks;
35,000 records.


DBA_DDL_LOCKS records are not deleted like DBA_DML_LOCKS?

Sami, March 03, 2004 - 9:48 am UTC

Sorry Tom,

In my previous post,the second select should be read as "DBA_DDL_LOCKS".

Question,
Why do I have  27683 DDL_LOCKS? Looks like it got accomulaed over the period. The record stays in DBA_DDL_LOCKS, even after releasing the DDL lock?

Am I corerct?


Below query is from diffenent environment (than previous posting)

SQL> select count(*) from dba_dml_locks;
 
  COUNT(*)
----------
         2
 
SQL> select count(*) from dba_ddl_locks;
 
  COUNT(*)
----------
     27683
 
SQL> 
 

Tom Kyte
March 03, 2004 - 3:05 pm UTC

that view is "dynamic", you must have 27k dba_ddl_locks in action right now:

create or replace view dba_ddl_locks (
SESSION_ID
,OWNER
,NAME
,TYPE
,MODE_HELD
,MODE_REQUESTED
) as
select s.sid session_id,
substr(ob.kglnaown,1,30) owner,
substr(ob.kglnaobj,1,30) name,
decode(ob.kglhdnsp, 0, 'Cursor', 1, 'Table/Procedure/Type', 2, 'Body',
3, 'Trigger', 4, 'Index', 5, 'Cluster', 13, 'Java Source',
14, 'Java Resource', 32, 'Java Data', to_char(ob.kglhdnsp)) type,
decode(lk.kgllkmod, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive',
'Unknown') mode_held,
decode(lk.kgllkreq, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive',
'Unknown') mode_requested
from v$session s, x$kglob ob, x$kgllk lk
where lk.kgllkhdl = ob.kglhdadr
and lk.kgllkuse = s.saddr
and ob.kglhdnsp != 0

/


it is built off of v$ and x$ tables that do not persist

Is it really strange to have 20K+ DDL Locks

A reader, March 03, 2004 - 6:06 pm UTC

Dear Tom,

Why these many DDL locks? Is something wrong in this environment? Or it is normal to have 20k+ locks?

If it is not okay where should I start investigating this issue?

I checked the same environment again, now it got reduced from 27683 to 21318.

Oracle8i Enterprise Edition Release 8.1.7.3.0 - Production
With the Partitioning and Parallel Server options
JServer Release 8.1.7.3.0 - Production
 
SQL> select count(*) from dba_ddl_locks;
 
  COUNT(*)
----------
     21318
 
SQL> select count(*) from dba_dml_locks;
 
  COUNT(*)
----------
         3
 
SQL> 
 

Tom Kyte
March 04, 2004 - 8:04 am UTC

why don't you investigate what they are rather than counting them? (eg: look at the values therein).

could be perfectly normal -- if you have lots of users, doing lots of stuff. You'll see entries for sequences, tables, packages, procedures and the like -- stuff people are "using".

Could be just fine and dandy if you have lots of connected users doing stuff.

DBA_DDL_LOCKS break-up

Sami, March 03, 2004 - 6:19 pm UTC

18:18:07 SQL> 
SELECT TYPE,COUNT(*) FROM DBA_DDL_LOCKS GROUP BY TYPE;18:18:09 SQL> 
 
TYPE                                       COUNT(*)
---------------------------------------- ----------
10                                                1
11                                                1
16                                                2
18                                             1956
Body                                           1142
Java Data                                       169
Java Resource                                     3
Table/Procedure/Type                          24494
Trigger                                         765
 
9 rows selected.
 

SQL> set time on
18:09:03 SQL> /
 
  COUNT(*)
----------
     27054
 
18:09:08 SQL> /
 
  COUNT(*)
----------
     27051
 
18:09:14 SQL> /
 
  COUNT(*)
----------
     27053
 
18:09:20 SQL> /
 
  COUNT(*)
----------
     27607
 
18:10:02 SQL> /
 
  COUNT(*)
----------
     27621
 
 

Tom Kyte
March 04, 2004 - 8:06 am UTC

looks just fine, you just have lots of people doing lots of stuff. nothing to worry about here -- you have an active database.

(dba_ddl_locks)harmless but trying to understand the logic..

Sami, March 04, 2004 - 8:47 am UTC

Dear Tom,

Sorry for bothering you again.

I went thur manuals and books but still I could not understand the meaning/purpose of DDL locks. 

Please enlighten me with your valuable comments on this.

  1  SELECT name,COUNT(*) FROM DBA_DDL_LOCKS
  2  WHERE mode_held IS NOT NULL AND TYPE='Trigger'
  3  GROUP BY name
  4* order by 2 desc
SQL> /
 
NAME                                       COUNT(*)
---------------------------------------- ----------
PROFILEDUSER_TR01                               185
PROFILEDUSER_TR02                               184
LOGONDETAILS_TR01                                90
LOGONCAMATTRIBUTES_TR01                          72
:
:



SQL> SELECT session_id,mode_held,mode_requested 
FROM DBA_DDL_LOCKS 
WHERE mode_held IS NOT NULL AND TYPE='Trigger'
AND  name='PROFILEDUSER_TR01'  2    3    4  
  5  /
 
SESSION_ID MODE_HELD MODE_REQU
---------- --------- ---------
        25 Null      None
        36 Null      None
        36 Null      None
        36 Null      None
        36 Null      None
        36 Null      None
        39 Null      None
        41 Null      None
:
:
:



What does it mean by having 185 DDL locks on PROFILEDUSER_TR01?

Why DDL locks are higher than DML locks? 

My understanding is that DDL lock should occur while some one is performing DDL operations on an object.

 

Tom Kyte
March 04, 2004 - 1:16 pm UTC

do you have access to my book Expert one on one Oracle? I write about it in there

it just means "people are using that, if you do something to profileduser_tr01, there are 185 people using it that may be affected (or may prevent you from doing the change)"

Disable DDL

A reader, March 16, 2004 - 2:35 pm UTC

Tom,

I remember reading somewhere (your article or the Expert one-on-one book, I don't remember exactly) that doing an ALTER TABLE DISABLE TABLE LOCK will prevent any DDLs from being performed on the table. I searched your web-site but couldn't find it. I would appreciate if you could point me to the link or the chapter in your book where I could find this.

Thanks much

Tom Kyte
March 16, 2004 - 2:50 pm UTC

It is in the chapter on locking and concurrency

...
An interesting side note to the TM lock. The total number of TM locks allowed in the system is configurable by you (see the DML_LOCKS init.ora parameter definition in the Oracle8I Server Reference manual for details). It may in fact be set to 0. This does not mean that your database becomes a read-only database (no locks), but rather that DDL is not permitted. This is useful in very specialized application, such as OPS, to reduce the amount of intra-instance coordination that would otherwise take place. You can also remove the ability to gain TM locks on an object by object basis using the ALTER TABLE tablename DISABLE TABLE LOCK.

.........

Thanks

A reader, March 16, 2004 - 3:18 pm UTC

Tom,

Thanks much for pointing me to the article. In the same paragragh, you mention that disabling table lock removes the ability to perform a DDL on the table, but allows DMLs to be performed (ie. database does not become read-only). Why does disabling table lock using ALTER TABLE ... DISABLE TABLE LOCK prevents only DDL from happening on that table. The reason I have this question a DML on a table, takes 2 locks :
a) a TM lock on the table (shared lock) so that no other session/session can take an exclusive lock on the table
b) a TX lock on the table to make sure that the affected rows are not changed by another transaction/session

If the ALTER TABLE .. DISABLE TABLE LOCK removes the ability to gain a TM lock on the table(s), then how can we perform a DML on that (since to perform a DML, we need to have a TX lock on the rows which in turn requires a TM lock taken on the table).

Please explain

Thanks

Tom Kyte
March 16, 2004 - 4:18 pm UTC

the TM lock is not a "table lock" like "lock table in X mode", it is a lock registered against that segment saying "hey, I've got some locking going on this table".

It would prevent someone from dropping a column you are updating for example.  It is lightweight.

the TX lock isn't on the "table", you get one -- not one per table:

ops$tkyte@ORA9IR2> update emp set ename=ename;
 
14 rows updated.
 
ops$tkyte@ORA9IR2>  select * from v$lock where sid = (select sid from v$mystat where rownum=1);
  
 
ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST      
-------- -------- ---------- -- ---------- ---------- ---------- ---------- 
56B41D8C 56B41E98         10 TX     393258       9816          6          0          
56AE9D48 56AE9D5C         10 TM      35514          0          3          0          
 
ops$tkyte@ORA9IR2> ops$tkyte@ORA9IR2> update dept set dname=dname;
 
4 rows updated.
 
ops$tkyte@ORA9IR2>  select * from v$lock where sid = (select sid from v$mystat where rownum=1);
  
 
ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST      
-------- -------- ---------- -- ---------- ---------- ---------- ---------- 
56B41D8C 56B41E98         10 TX     393258       9816          6          0          
56AE9DCC 56AE9DE0         10 TM      35515          0          3          0          
56AE9D48 56AE9D5C         10 TM      35514          0          3          0          
 


A TM per segment, a TX per transaction.   

Basically the alter table disable table lock is preventing the "high mode" locks -- the ones that prevent other concurrent activity.

An update for example takes a "row exclusive" (mode=3) 'table lock'.  It means "hey, I've got some rows locked in exclusive mode in this table (not really a table lock truly).  as long as you don't try to lock the same rows -- you can have at this table"


A locak table in exclusive mode takes an "exclusive" lock -- it gets them all -- it does this at the table level.  It is a true "table lock"


Consider:

ops$tkyte@ORA9IR2> alter table emp disable table lock;
Table altered.
 

 
ops$tkyte@ORA9IR2> lock table emp in row share mode;
Table(s) Locked.

<b>that is like SELECT FOR UPDATE does.</b>
 
ops$tkyte@ORA9IR2> lock table emp in row exclusive mode;
Table(s) Locked.

<b>That is like UPDATE does</b>
 
ops$tkyte@ORA9IR2> lock table emp in share mode;
lock table emp in share mode
           *
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for EMP
 
 
ops$tkyte@ORA9IR2> lock table emp in share row exclusive mode;
lock table emp in share row exclusive mode
           *
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for EMP
 
 
ops$tkyte@ORA9IR2> lock table emp in exclusive mode;
lock table emp in exclusive mode
           *
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for EMP

<b>those last three are true TABLE LEVEL locks -- locked the entire table.  They are what are prohibited</b>

guess the command should be

alter table t disable "most" table lock; 

A reader, March 16, 2004 - 4:07 pm UTC

Great

Row Share mode

A reader, March 16, 2004 - 5:01 pm UTC

Tom,

My understanding with SELECT FOR UPDATE (without NOWAIT) is that the statement will take an
exclusive lock on the selected rows (provided no other session is holding an exclusive lock
on those rows). However, in your earlier discussion you mention :
"
ops$tkyte@ORA9IR2> lock table emp in row share mode;
Table(s) Locked.

that is like SELECT FOR UPDATE does.

ops$tkyte@ORA9IR2> lock table emp in row exclusive mode;
Table(s) Locked.

That is like UPDATE does
"

But I thought both of the above would hold an exclusive lock on the affected rows. Why does
SELECT FOR UPDATE take a lock in row share mode? Does that mean that other session can still
be able to change the same row. If so, what is the use of pessimistic locking?
I am getting confused

Please explain

Thanks

Tom Kyte
March 16, 2004 - 6:08 pm UTC

No, other sessions cannot lock that row. It is a row share table lock and defined as:

<quote>
Row Share Table Locks (RS) A row share table lock (also sometimes called a subshare table lock, SS) indicates that the transaction holding the lock on the table has locked rows in the table and intends to update them. A row share table lock is automatically acquired for a table when one of the following SQL statements is executed: SELECT ... FROM table ... FOR UPDATE OF ... ; LOCK TABLE table IN ROW SHARE MODE; A row share table lock is the least restrictive mode of table lock, offering the highest degree of concurrency for a table.

Permitted Operations: A row share table lock held by a transaction allows other transactions to query, insert, update, delete, or lock rows concurrently in the same table. Therefore, other transactions can obtain simultaneous row share, row exclusive, share, and share row exclusive table locks for the same table.

Prohibited Operations: A row share table lock held by a transaction prevents other transactions from exclusive write access to the same table using only the following statement: LOCK TABLE table IN EXCLUSIVE MODE;



You might want to glance at the concepts guide -- the section on "how oracle locks data" to get a description of all of the locks used and what other locks can coexist with it

What about regular UPDATE

A reader, March 16, 2004 - 6:20 pm UTC

Tom,

What ever applies to RS/SS lock obtained by SELECT .. FOR UPDATE applies to regular UPDATE statement also right? If not what is the difference between SELECT .. FOR .. UPDATE and the regular UPDATE statement except that the former indicates an intention for the transaction to update the specified rows. Is my understanding not correct. If so, please explain the difference between SELECT .. FOR ..UPDATE that takes a SS/RS lock and the regular UPDATE that takes a Exclusive row lock

Tom Kyte
March 16, 2004 - 6:37 pm UTC

update is a little "stronger", consider:


ops$tkyte@ORA9IR2> create table emp as select * from scott.emp;
 
Table created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> lock table emp in share mode;
 
Table(s) Locked.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          for x in ( select ename from emp where rownum = 1 for update )
  5          loop
  6                  dbms_output.put_line( 'locked ' || x.ename );
  7          end loop;
  8          commit;
  9  end;
 10  /
locked SMITH
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          for x in ( select ename from emp where rownum = 1 for update )
  5          loop
  6                  dbms_output.put_line( 'locked ' || x.ename );
  7                  update emp set ename = ename where ename = x.ename;
  8                  dbms_output.put_line( 'updated ' || x.ename );
  9          end loop;
 10          commit;
 11  end;
 12  /
locked SMITH
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 7
 


<b>we are able to "select for update" SMITH, but we are not able to actually update SMITH because of the outstanding table level share lock

(again -- concepts guide, lists all locks, describes all locks, tells us what locks coexist with other locks.  check it out!)</b>
 

Share, Share Row Exclusive and Exclusive Table Locks

Roger, April 16, 2004 - 2:53 pm UTC

Hi Tom,

Thank you for your time in answering questions on this site.

I have read the Oracle 10g concepts manual from pages 13-17 to 13-32 and also read Chapter 3 (concurrency and locking) of your Expert One on One book.

Questions
----------
1)When are Share, Share Row Exclusive and Exclusive Table Locks really used? I was able to verify that when I select for update, I see a RS table lock in V$lock. Also verified that when I perform a insert/update/delete I see a RX lock in V$lock. Can you please give an example (Other than the explcit LOCK TABLE command) that would show the other 3 table locks.

2) Kind of related to 1), your book and the documentation mention the use of "LOCK TABLE " command to place Share Row Exclusive and Exclusive Table Locks. But I don't understand how Oracle uses such locks. Please give an example of some DML/DDL SQL that would create a Share, Share Row Exclusive OR Exclusive Table Lock.

3) Oracle Concepts Manual 10g, page 13-22, Table Locks (TM) section, <quote> DML operation require table locks for 2 purposes: to reserve DML access to the table on behalf of a transaction and to prevent DDL operations that would conflict with the transaction </quote>

I don't see the point of the first purpose. Aren't ROW locks responsible for this and NOT table locks?

Thank you very much.



Tom Kyte
April 16, 2004 - 3:23 pm UTC

1)

When are they used? The three lock table commands that would do these are used "rarely".

Suppose you needed to do a mass update.
Suppose it was against a table with 5000 rows.
Suppose it was to be done while others are still working on the table.

If you just did "update t set x = x * f(z,a)" -- you could end up locking half of the rows, getting blocked -- start blocking others wanting to work on the 1/2 of the table -- wait for a while, have those that are blocking start to block others (eg: a real road jam) -- and then finishing.

Or, you could:

lock table in exclusive mode;
update t set x = x * f(z,a);
commit;


get the table -- update the entire thing -- commit -- as fast as you can.


These three locks are the result of lock table commands.


2) in older versions of Oracle (pre 7.3.3), the lock table in share mode was used to provide "serializable" transactions. any table you touched -- we'd prevent anyone from modifying it (except you) during that time (until you commit). That would be one "use of it".

the most common one (and even it is very very uncommon) is the exclusive mode, see #1


3) Ahh, but you can only tell if a transaction has a row locked in a table if you went to the row. The TM lock is there to tell people "george has a row(s) locked in this table". It is like a flag if you will. Once the flag is there, it can be used to prevent various things from happening (like a DDL command). It reserves the right for you to perform DML on the table.

Share, Share Row Exclusive and Exclusive Table Locks

Roger, April 16, 2004 - 10:11 pm UTC

May God bless you for being such a great person and helping so many people. I hope that I can be as successful as you one day.

How to avoid deadlocks in my application?

Tony, April 19, 2004 - 1:16 am UTC

Tom,
I've written many ETL programs in PL/SQL. Lots of locking issues are comming up while testing them with huge data.

1.How to avoid dealdlock suituations in my applications?
Is there any guidelines to avoid dealocks?
2. Which are the deadlock exceptions? How to handle deadlocks exceptions when it's encountered in applications?

Thanks in advance.




Tom Kyte
April 19, 2004 - 6:42 am UTC


1) deadlocks are rare in Oracle. predominant cause is "unindexed foreign key on a table where the parent table has rows DELETED or the primary key is UPDATED". See
</code> http://asktom.oracle.com/~tkyte/unindex/index.html <code>
for a discussion.

if that is not the cause, then it is generally an application issue. You are getting resources in different orders in different applications (eg: app1 locks row in T1 and then row in T2 -- app2 locks row in T2 and then T1. If app1 and app2 are going after the same row, well, that'll be a deadlock)

only design can get rid of #2

2) ora-60. typically, you have to rollback and restart as the other session is blocked waiting for you to commit or rollback (but you cannot commit as the transaction is not yet complete)

Oracle's row locking can generate false deadlocks

Scott Martin, April 20, 2004 - 7:59 pm UTC

After reading these posts it occurred to me that

1) Row locks are recorded on disk with txids.
2) Clients needing to update a row locked by another txid
wait on the txid to complete (not the row itself to become free).

Although I completely understand all the positive aspects of why
Oracle implements row locks this way, it occurred to me that this could
have unintended side effects.

A client is not truly waiting on the resource he needs
(the row) but only a related resource (the txid).

I bet it would be possible to put transaction "B" in a state
where it was needlessly waiting for transaction "A" to commit or
rollback.

If transaction "A" then needed to update a row
held by transaction "B" we could get a "false" deadlock.

By "false" deadlock, I mean that transaction A and B are not truly
deadlocked based on the rows they have locked and/or waiting for, but
are deadlocked because of a side effect of Oracle's implementation of row locks.

After some simple trial and error I did it.

With two windows and about 7 simple SQL statements I get...

ORA-00060: deadlock detected while waiting for resource

when, at the time of the ORA-60, there was no row level deadlock.

Anyone want to guess how?

For the answer, I would appreciate you reading my article on the subject
entitled "Row Level Locking in Oracle" at www.tlingua.com/articles/rl.html.

I'm sure some alert reader will be the first to post his answer here, on AskTom.

If no one posts a correct answer within a week, I'll post mine.

Tom Kyte
April 21, 2004 - 12:15 pm UTC

you ran out of ITL entries in the block header, hot block syndrome. I can do it with less sql statements.

this statement:


I bet it would be possible to put transaction "B" in a state
where it was needlessly waiting for transaction "A" to commit or
rollback.


is false, you have not proven that -- needlessly is the key word. it is not needless, it is necessary.

simple fix would be on this small hot table to either

o limit rows/block
o increase the initrans.

Clarification

Scott Martin, April 22, 2004 - 8:53 pm UTC

I meant to clarify that it is truly a false deadlock
based on the rows themselves No outside resource (space
allocation, itl entry, etc.) is involved. No artificially
constrained environment. Just a pure side effect of being
forced to wait on a transaction when all you really want
is the row. I pretty much gave it away there...

Tom Kyte
April 23, 2004 - 10:44 am UTC

then you used savepoints and rolled back to a savepoint after a select for update that was blocking the other guy.

start with:

drop table t;

create table t ( x int );
insert into t values ( 1 );
insert into t values ( 2 );
commit;



Now do this in three sessions (session 3 is not really relevant, just proves a point)


session 1 session 2 session 3
------------------- ------------------ ----------------------
update t
set x = 1
where x = 1;

savepoint foo;
select * from t
where x = 2
for update;

select *
from t
where x = 2
for update;
BLOCKS on session 2
rollback to
savepoint foo;


select *
from t
where x = 2
for update;
does not block, showing
row is not locked


update t
set x = 1
where x = 1;
deadlocks



But, it still goes back to resource gathering and the order in which they are gathered.


yup. rollback to savepoint was the key...

Scott Martin, April 24, 2004 - 12:37 am UTC

Yup.
Any answer involving rollback to savepoint will do.
The goal was to find a way to have a transaction
unlock a row while still remaining active. Rollback
to savepoint does the trick. My example was going to involve
single row updates instead of select for update but it is
the same idea. One curiosity of my example is that
session 3 can update the very row "out from under" the
desire of session 2 to do the same thing... (Your session
3 did something similar).

drop table t;

create table t ( x int );
insert into t values ( 1 );
insert into t values ( 2 );
insert into t values ( 3 );
commit;

session 1 session 2 session 3
------------------- ------------------ ----------------------

update t
set x = 1
where x = 1;

savepoint foo

update t
set x = 2
where x = 2;
update t
set x = 2
where x = 2;
BLOCKS on session 1
rollback to
savepoint foo
update t
set x = 2
where x = 2;
Confirming row no
longer locked by 1
commit;
awakens on session 1's
release of the TX lock
but now
BLOCKS on session 3!


"but I was there first", grimaced session #2...

deadlock on inserts

Dave, April 27, 2004 - 5:56 pm UTC

If we have only row-level locking and never escalate it, how come I get deadlock with two sessions doing inserts into the same table? Is it posssible at all?

I thought it's because of the lock escalation but now can't get it...
Thank you,


Blocker of the Row...

Muhammad Waseem Haroon, May 26, 2004 - 4:19 am UTC

Hi Tom,

this is my first and I hope you will help me.

Session # 1:

SQL> Connect Scott/Tiger@oralnx
Connected.

SQL> Select *
  2  From   Emp
  3  Where  Empno = 7369
  4  For update [NoWait];

    EMPNO ENAME      JOB             MGR HIREDATE        SAL      COMM    DEPTNO
--------- ---------- --------- --------- --------- --------- --------- ---------
     7369 SMITH      CLERK          7902 17-DEC-80       800                  20


Session # 2:


SQL> Connect Scott/Tiger@oralnx
Connected.

Update Emp
Set    Ename = 'ENAME'
Where  Empno = 7369;


Hung...

How Can I Found the Machine Name [using Rowid or by another way] of the User Who has been Locked that Row?
I am Working on Forms and getting an error when I am updating this Row. 

"Could not Reserve Record (2 tries). Keep Trying ?"
In the Replacement of this Error , I want the Machine Name of the Blocker who has been locked that Row.

For that I have tried to Create a Trigger to find a blocker but its not giving me the right answer :(
and i think this is not the right way.
---ON-ERROR Trigger

DECLARE
    
    ERRCODE       NUMBER := MESSAGE_CODE; 
    V_ROW_OBJECT  NUMBER;
    V_ROW_FILE    NUMBER;
    V_ROW_BLOCK   NUMBER;
    V_ROW_NUMBER  NUMBER;
    V_SESS        NUMBER;
        USERNAME      VARCHAR2(100);
        MACHINE       VARCHAR2(100);
    
BEGIN 
 
----IF ERRCODE = ##### THEN
     
  SELECT     DBMS_ROWID.ROWID_OBJECT(ROWID),
         DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID),
         DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID),
         DBMS_ROWID.ROWID_ROW_NUMBER(ROWID)     
  INTO       V_ROW_OBJECT,
             V_ROW_FILE,
         V_ROW_BLOCK,
         V_ROW_NUMBER    
  FROM       EMP
  WHERE      EMPNO = :EMPNO;

  Select     osuser||'@'||terminal INTO USERNAME
  From       v$session
  WHERE      ROW_WAIT_OBJ#          = V_ROW_OBJECT
  AND        ROW_WAIT_FILE#         = V_ROW_FILE  
  AND        ROW_WAIT_BLOCK#        = V_ROW_BLOCK 
  AND        ROW_WAIT_ROW#          = V_ROW_NUMBER;
  
  MESSAGE('Record is Updating by the User : '||USERNAME);
  MESSAGE('Record is Updating by the User : '||USERNAME);    
    
----END IF;
    
EXCEPTION
    
    WHEN NO_DATA_FOUND THEN 
    MESSAGE(SQLERRM);
    MESSAGE(SQLERRM);
    
    WHEN OTHERS THEN 
    MESSAGE(SQLERRM);
    MESSAGE(SQLERRM);
    
END;


if u Please Give me the Example then
I Shell be Very thankful to you.
 

Tom Kyte
May 26, 2004 - 8:16 am UTC

page up to read the review entitled "Which Rows are locked by a session"

you may generate a list of people that have rows locked in this table using v$lock (look for TM locks where id1 = object id of this table).



dba_locks on RAC

READER, May 26, 2004 - 10:06 am UTC

1. Why don't I see DBA_LOCKS on a RAC DB
2.Why does block has a value of 2 when I do a select * from v$lock in a RAC DB

Thanks

Tom Kyte
May 26, 2004 - 12:44 pm UTC

1) just run $ORACLE_HOME/rdbms/admin/catblock.sql

2) that was corrected in 9.2, contact support and reference 2155747

Public vs Private Thread

Reader, May 26, 2004 - 6:05 pm UTC

I execute the following sql on a two node RAC .

SELECT inst_id,GROUP#,THREAD# FROM gv$log
INST_ID GROUP# THREAD#
------- ------ -------
1 1 1
1 2 1
1 3 2
1 4 2
2 1 1
2 2 1
2 3 2
2 4 2
8 rows selected

Both the threads are enabled as PRIVATE .
I got the same results when they were configured as PUBLIC.

As per the documentation
Each Instance has its own set of Redo logs which is the thread of online logs .
Then why are the instances seeing both the threads .

Any help in clarifying this will be highly appreciated .

Also,what are the advantages of having the threads as PRIVATE vs PUBLIC

Thanks ,


Tom Kyte
May 27, 2004 - 8:36 am UTC

now, join that to gv$logfile and you'll see each has it's own set of files.

each instance does have it's own set of files.

Locking Problem.

A reader, June 02, 2004 - 11:10 am UTC

Hi Tom,

I have a table which contains xmltype columns. Here is the create table statement.

CREATE TABLE TabL_FileContent
(
FileID NUMBER
,SequenceData SYS.XMLTYPE
,TypData SYS.XMLTYPE
,FileContent BLOB
,ResultData SYS.XMLTYPE
)
XMLTYPE COLUMN SequenceData
STORE AS OBJECT RELATIONAL
XMLSCHEMA "file:X:/Moehwald/DB/CR/Vorlagen/Ablauf/xmlabldaten.xsd"
ELEMENT "MEPSequenceData"
XMLTYPE COLUMN TypData
STORE AS OBJECT RELATIONAL
XMLSCHEMA "file:X:/Moehwald/DB/CR/Vorlagen/Ablauf/typdaten.xsd"
ELEMENT "Data"
XMLTYPE COLUMN ResultData
STORE AS OBJECT RELATIONAL
XMLSCHEMA "file:X:/Moehwald/DB/CR/Vorlagen/Ablauf/XMLResultMep2000.xsd" ELEMENT "MEPOutput"
-- 1 "XMLDATA"."MEPOutputData"."Sequences"."Sequence"
varray RESULTDATA."XMLDATA"."MEPOutputData"."Sequences"."Sequence"
store as table SEQUENCE_TABLE
(
(constraint SEQUENCE_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 2 Name
varray "Name"
store as table NAME_TABLE
(
(constraint NAME_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
) return as LOCATOR
-- 2 ViewName
varray "ViewName"
store as table VIEW_NAME_TABLE
(
(constraint VIEW_NAME_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
) return as LOCATOR
-- 2 MeasPoint
varray "MeasPoint"
store as table MEAS_POINT_TABLE
(
(constraint MEAS_POINT_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 3 MeasPointSteps
varray "MeasPointSteps"
store as table MEAS_POINT_STEPS_TABLE
(
(constraint MEAS_POINT_STEPS_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 4 MeasPointStep
varray "MeasPointStep"
store as table MEAS_POINT_STEP_TABLE
(
(constraint MEAS_POINT_STEP_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 5 "StepGeneralMeas"."STEPGENERALMEASCOLUMN"
varray "StepGeneralMeas"."STEPGENERALMEASCOLUMN"
store as table SET_GENERAL_TABLE
(
(constraint SET_GENERAL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 5 "SetPhase"."SetVar"
varray "SetPhase"."SetVar"
store as table SET_VAR_TABLE
(
(constraint SET_VAR_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 6 "VarSetValues"."VarSetValue"
varray "VarSetValues"."VarSetValue"
store as table VAR_SET_VALUE_TABLE
(
(constraint VAR_SET_VALUE_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 6 "VarSequData"."VARSEQUDATACOLUMN"
varray "VarSequData"."VARSEQUDATACOLUMN"
store as table SET_VARSEQUCOL_TABLE
(
(constraint SET_VARSEQUCOL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
)
-- 5 "MeasPhase"."MeasVar"
varray "MeasPhase"."MeasVar"
store as table MEAS_VAR_TABLE
(
(constraint MEAS_VAR_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 6 "VarMeasValues"."VarMeasValue"
varray "VarMeasValues"."VarMeasValue"
store as table VAR_MEAS_VALUE_TABLE
(
(constraint VAR_MEAS_VALUE_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 6 VarSequData
varray "VarSequData"
store as table MEAS_VARSEQUDATA_TABLE
(
(constraint MEAS_VARSEQUDATA_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 7 VARSEQUDATACOLUMN
varray VARSEQUDATACOLUMN
store as table MEAS_VARSEQUCOL_TABLE
(
(constraint MEAS_VARSEQUCOL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
)
)
-- 5 "StepGeneral"."STEPGENERALCOLUMN"
varray "StepGeneral"."STEPGENERALCOLUMN"
store as table STEP_GENERAL_TABLE
(
(constraint STEP_GENERAL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 5 "WaitPhase"."WaitVar"
varray "WaitPhase"."WaitVar"
store as table WAIT_PHASE_VAR_TABLE
(
(constraint WAIT_PHASE_VAR_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 6 "VarSequData"."VARSEQUDATACOLUMN"
varray "VarSequData"."VARSEQUDATACOLUMN"
store as table WAIT_VARSEQUCOL_TABLE
(
(constraint WAIT_VARSEQUCOL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 6 "VarMeasValues"."VarMeasValue"
varray "VarMeasValues"."VarMeasValue"
store as table WAIT_VARMEASVALUE_TABLE
(
(constraint WAIT_VARMEASVALUE_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
)
)
)
)
-- 2 STDUP
varray STDUP
store as table STDUP_TABLE
(
(constraint STDUP_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 3 "STDUPSequenceData"."STDUPSequenceData.Column"
varray "STDUPSequenceData"."STDUPSequenceData.Column"
store as table STDUP_SEQUDATACOL_TABLE
(
(constraint STDUP_SEQUDATACOL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 3 "STDUPMeasData"."STDUPMeasData.Column"
varray "STDUPMeasData"."STDUPMeasData.Column"
store as table STDUP_MEASDATACOL_TABLE
(
(constraint STDUP_MEASDATACOL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
)
)
-- 1 "XMLDATA"."MEPInputData"."UsedDatas"."UsedData"
varray RESULTDATA."XMLDATA"."MEPInputData"."UsedDatas"."UsedData"
store as table USED_DATA_TABLE
(
(constraint USED_DATA_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 2 UsedInpDatum
varray "UsedInpDatum"
store as table USED_INP_DATUM_TABLE
(
(constraint USER_INP_DATUM_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
)
-- 1 "XMLDATA"."General"."GENERALCOLUMN"
varray RESULTDATA."XMLDATA"."General"."GENERALCOLUMN"
store as table GENERAL_COLUMN_TABLE
(
(constraint GENERAL_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
-- 1 "XMLDATA"."MEPInputData"."UsedDevices"."Device"
varray RESULTDATA."XMLDATA"."MEPInputData"."UsedDevices"."Device"
store as table USED_DEVICE_TABLE
(
(constraint USED_DEVICE_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
-- 2 "Konfiguration"."KonfigFile"
varray "Konfiguration"."KonfigFile"
store as table KONFIGFILE_TABLE
(
(constraint KONFIGFILE_PKEY primary key (NESTED_TABLE_ID, ARRAY_INDEX))
)
)
/

I have a view based on this table.
CREATE OR REPLACE VIEW VW_FILECONTENT
AS SELECT * FROM TABL_FILECONTENT
/

Now when i try to acquire lock on this view i get the following error message.

select fileid from vw_filecontent where fileid=260778 for update
/


ERROR at line 1:
ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.

Can you please let me know the problem.i think because of the presence of nested tables, this problem has come.
Thanks.

Tom Kyte
June 02, 2004 - 11:33 am UTC

what happens if you select from the table itself? (and do you have a seriously smaller example?)

A reader, June 02, 2004 - 12:09 pm UTC

Hi tom,

here is a test case.

CREATE TYPE satellite_t AS OBJECT
(
name VARCHAR2(20),
diameter NUMBER);
/

CREATE TYPE nt_sat_t AS TABLE OF satellite_t;
/

CREATE TYPE planet_t AS OBJECT
(
name VARCHAR2(20),
mass NUMBER,
satellites nt_sat_t);
/


CREATE TYPE nt_pl_t AS TABLE OF planet_t;
/

CREATE TABLE stars (
name VARCHAR2(20),
age NUMBER,
planets nt_pl_t)
NESTED TABLE planets STORE AS planets_tab
(NESTED TABLE satellites STORE AS satellites_tab);


create or replace view view_test
as
select * from stars
/


INSERT INTO stars
VALUES('Sun',23,
nt_pl_t(
planet_t(
'Neptune',
10,
nt_sat_t(
satellite_t('Proteus',67),
satellite_t('Triton',82)
)
),
planet_t(
'Jupiter',
189,
nt_sat_t(
satellite_t('Callisto',97),
satellite_t('Ganymede', 22)
)
)
)
)
/

select age from view_test where age=23 for update
/

Thanks.


Tom Kyte
June 02, 2004 - 1:14 pm UTC

create or replace type tabType as table of number
/
create table t ( x int, y tabtype ) nested table y store as y_tab;
create or replace view v as select x, y from t;
select * from t for update;
select * from v for update;


reproduces it. I opened bug 3666744 for this. It is the nested table causing the issue, i don't see any workaround short of

- don't use nested table
- don't include nested table in view
- don't use view

sorry.

row exclusive lock - clarification

Raaghid, June 09, 2004 - 3:04 am UTC

Example:
sess 1
update dept set deptno=deptno where deptno=10;


sess 2
update dept set deptno=deptno where deptno=10;

when i put the above sql, it will get locked.

But when i put the following sql, it does not, since it
is affecting some other row
update dept set deptno=deptno where deptno=10;

SID SERIAL# PROCESS USERNAME TERMINAL TYPE LMODE LREQUEST OBJECT
---------- ---------- -------------------- ------------------------------ ---------------- ------------ ---------------------------------------- ---------------------------------------- --------------------------------------
16 739 1884:1868 SCOTT RIYAZ DML/DATA ENQ RX NONE SCOTT.DEPT
16 739 1884:1868 SCOTT RIYAZ TRANSAC ENQ X NONE RS+SLOT#851991 WRP#1486
17 1953 1944:1332 SCOTT RIYAZ DML/DATA ENQ RX NONE SCOTT.DEPT
17 1953 1944:1332 SCOTT RIYAZ TRANSAC ENQ X NONE RS+SLOT#917506 WRP#1167

My question:
------------
1. what is : RS+SLOT#851991 WRP#1486 (Lmode X / Type Transac)
2. I have a dount in your statment in this page:
"the locks are all table level entries actually. You will not see individual row
level locks in v$lock."

In the above my example, row has got locked, and it got listed. pl clarify.

Tom Kyte
June 09, 2004 - 7:21 am UTC

you say "but when I put the following sql....." -- but that sql is the same sql and would get blocked???


1) you tell us -- it is your query getting that information and you didn't share the query with us?

2) where is the information as to what ROW is locked? tell you what, do this:

update dept set deptno = deptno;

that'll update 4 rows. how many entries in v$lock will you see? not 4. You do not see the individual row locks in there.

correction

Raaghid, June 10, 2004 - 3:11 am UTC

sorry major typing error. last sql is updating for dept no = 20, so there will be no lock

It should be:
Example:
sess 1
update dept set deptno=deptno where deptno=10;


sess 2
update dept set deptno=deptno where deptno=10;

when i put the above sql, it will get locked.

But when i put the following sql, it does not, since it
is affecting some other row
update dept set deptno=deptno where deptno=20;

In nutshell my question is: why this is happening.
16 739 1884:1868 SCOTT RIYAZ
TRANSAC ENQ X NONE
RS+SLOT#851991 WRP#1486
Thanks again


Tom Kyte
June 10, 2004 - 7:53 am UTC

yes, and my answer stands

there is not an entry per lock.
there is an entry per locked row

and you *still* haven't shown us the magic query you are running so I cannot explain the output -- but it looks like someone is decoding id1/id2 to provide the table name and the rollback segment slot/scn wrap information.

More information about locked objects

Arun Gupta, June 10, 2004 - 9:44 am UTC

Tom,
We sometimes run into a situation in our production database that one session locks certain tables and then other sessions just wait for locks to be released. I have two questions:
a) Is there a way to find out what a session was doing just before locking situation started? I could only think of turning auditing on which will make the system very slow.
b) Reading about locks, I somehow got an impression that it is possible to find out which rows have been locked by a session by looking at the ITL in block header. If this is correct, how do I do it? I already know details about the blocker and blocked sessions, the table which has been locked, the lock mode held and requested.

Thanks

Tom Kyte
June 10, 2004 - 4:59 pm UTC

a) you could peek at v$open_cursor, it won't be everything, it won't be sequential but short of tracing -- it will be it.

b) if you dump a block, sure, but by the time you figured out the block, dumped it, read it, processed it -- problem is probably "long gone".

Magic query

Raaghid, June 11, 2004 - 5:13 am UTC

Th query I used for getting the lock is: (may be from this site also, not sure)

select s.sid, s.serial#,
substr(decode(s.process, null,
decode(substr(p.username,1,1), '?', upper(s.osuser), p.username),
decode( p.username, 'ORACUSR ', upper(s.osuser), s.process)
) ,1,20) process,
nvl(s.username, 'SYS ('||substr(p.username,1,4)||')') username,
decode(s.terminal, null, rtrim(p.terminal, chr(0)),
upper(s.terminal)) terminal,
decode(l.type,
-- Long locks
'TM', 'DML/DATA ENQ', 'TX', 'TRANSAC ENQ',
'UL', 'PLS USR LOCK',
-- Short locks
'BL', 'BUF HASH TBL', 'CF', 'CONTROL FILE',
'CI', 'CROSS INST F', 'DF', 'DATA FILE ',
'CU', 'CURSOR BIND ',
'DL', 'DIRECT LOAD ', 'DM', 'MOUNT/STRTUP',
'DR', 'RECO LOCK ', 'DX', 'DISTRIB TRAN',
'FS', 'FILE SET ', 'IN', 'INSTANCE NUM',
'FI', 'SGA OPN FILE',
'IR', 'INSTCE RECVR', 'IS', 'GET STATE ',
'IV', 'LIBCACHE INV', 'KK', 'LOG SW KICK ',
'LS', 'LOG SWITCH ',
'MM', 'MOUNT DEF ', 'MR', 'MEDIA RECVRY',
'PF', 'PWFILE ENQ ', 'PR', 'PROCESS STRT',
'RT', 'REDO THREAD ', 'SC', 'SCN ENQ ',
'RW', 'ROW WAIT ',
'SM', 'SMON LOCK ', 'SN', 'SEQNO INSTCE',
'SQ', 'SEQNO ENQ ', 'ST', 'SPACE TRANSC',
'SV', 'SEQNO VALUE ', 'TA', 'GENERIC ENQ ',
'TD', 'DLL ENQ ', 'TE', 'EXTEND SEG ',
'TS', 'TEMP SEGMENT', 'TT', 'TEMP TABLE ',
'UN', 'USER NAME ', 'WL', 'WRITE REDO ',
'TYPE='||l.type) type,
decode(l.lmode, 0, 'NONE', 1, 'NULL', 2, 'RS', 3, 'RX',
4, 'S', 5, 'RSX', 6, 'X',
to_char(l.lmode) ) lmode,
decode(l.request, 0, 'NONE', 1, 'NULL', 2, 'RS', 3, 'RX',
4, 'S', 5, 'RSX', 6, 'X',
to_char(l.request) ) lrequest,
decode(l.type, 'MR', decode(u.name, null,
'DICTIONARY OBJECT', u.name||'.'||o.name),
'TD', u.name||'.'||o.name,
'TM', u.name||'.'||o.name,
'RW', 'FILE#='||substr(l.id1,1,3)||
' BLOCK#='||substr(l.id1,4,5)||' ROW='||l.id2,
'TX', 'RS+SLOT#'||l.id1||' WRP#'||l.id2,
'WL', 'REDO LOG FILE#='||l.id1,
'RT', 'THREAD='||l.id1,
'TS', decode(l.id2, 0, 'ENQUEUE',
'NEW BLOCK ALLOCATION'),
'ID1='||l.id1||' ID2='||l.id2) object
from sys.v_$lock l, sys.v_$session s, sys.obj$ o, sys.user$ u,
sys.v_$process p
where s.paddr = p.addr(+)
and l.sid = s.sid
and l.id1 = o.obj#(+)
and o.owner# = u.user#(+)
and l.type <> 'MR'
UNION ALL /*** LATCH HOLDERS ***/
select s.sid, s.serial#, s.process, s.username, s.terminal,
'LATCH', 'X', 'NONE', h.name||' ADDR='||rawtohex(laddr)
from sys.v_$process p, sys.v_$session s, sys.v_$latchholder h
where h.pid = p.pid
and p.addr = s.paddr
UNION ALL /*** LATCH WAITERS ***/
select s.sid, s.serial#, s.process, s.username, s.terminal,
'LATCH', 'NONE', 'X', name||' LATCH='||p.latchwait
from sys.v_$session s, sys.v_$process p, sys.v_$latch l
where latchwait is not null
and p.addr = s.paddr
and p.latchwait = l.addr
/


Tom Kyte
June 11, 2004 - 3:52 pm UTC

yes, so I guessed right -- about what that field is (no, not my query). you should be able to look at the query and determine what the data you are viewing is...

ora - 8103

jasdeep, June 16, 2004 - 3:57 pm UTC

hi tom
i am facing
this error right now
that while taking export i am getting ora - 8103
exp -00008 errors
as a matter of fact sometimes while exporting agian
this error doesnt appears
that on the table where it is occuring is our main table
and if it is deleted as definition of error says
our work would have been halted.
what can be the other cause of this error




Tom Kyte
June 16, 2004 - 4:04 pm UTC

someone is either dropping the table you are exporting or truncating it while you are exporting. "the object no longer exists" that you wanted to export.

A reader, June 16, 2004 - 4:27 pm UTC

no user has priveldge to do this kind of operation


Tom Kyte
June 16, 2004 - 4:31 pm UTC

sorry, but someone does.

audit, you'll see.

A reader, June 16, 2004 - 4:31 pm UTC

can it be block corruption error
as search from mettalik appears to be like that



Tom Kyte
June 16, 2004 - 4:38 pm UTC

details? what note are you referring to.

A reader, June 16, 2004 - 4:57 pm UTC

ora-8103 on export - for certain tables 424931.995


Tom Kyte
June 16, 2004 - 6:07 pm UTC

cannot find any notes by the number.

A reader, June 16, 2004 - 5:01 pm UTC

i have run the query select count(*) on it and it is producing 3093200 records which is approx what i am expecting.
and if the table is truncated or deleted my work will not going untill now as it is the only major table in our database.

Tom Kyte
June 16, 2004 - 6:08 pm UTC

are you doing a direct path export and is this table extending (adding new extents) frequently?

A reader, June 16, 2004 - 7:47 pm UTC

yes i am doing direct path export and we have RAC and there is still space left on this patition.



Tom Kyte
June 17, 2004 - 7:54 am UTC

contact support, you might be running into a situation whereby the table extends (allocates a new extent) as you are exporting and in the direct=y mode, that has been known to throw this error.

workaround, direct=n

(hopefully, you are not using export as a backup, you are just trying to extract a copy for a test system or something right...)

Finding the referenced MetaLink doc id....

Mark J. Bobak, June 17, 2004 - 2:30 am UTC

Tom,

To find Doc ID 424931.995, go to advanced search,
put that number in the 'Document ID' field, and make sure
the 'Technical Forum' checkbox is checked.



Tom Kyte
June 17, 2004 - 9:44 am UTC

that is someone hypothesizing that the 8031 is block corruption. that note does not lead anyone to believe "it is caused by" that. they had to file a tar to get a resolution. in fact, a close read of it would lead us away from block corruption (as the event to skip them had no effect)

this would be as meaningful as overhearing a conversation:

"my car won't start, is it because the catalytic convertor is broken"

"well, if you turn the key and it doesn't turn the engine over, no, it isn't"

"i turned the key and the engine didn't turn over"

and coming to the conclusion that it was the catalytic convertor (incorrectly)

Getting locking information is very slow

Logan Palanisamy, June 29, 2004 - 2:45 pm UTC

Tom,

I have been successfully using the following query from your site for over two years, both in 8.1.7 and in 9iR2.

select
(select username from v$session where sid=a.sid) blocker,
a.sid,
' is blocking ',
(select username from v$session where sid=b.sid) blockee,
b.sid
from v$lock a, v$lock b
where a.block = 1
and b.request > 0
and a.id1 = b.id1
and a.id2 = b.id2;

For some reason, today it is running for more than 30 minutes. It took less than 3 minutes when I ran it only about a month ago. To the best of my knowledge, nothing has changed at the RDBMS level since then. What could be the problem?

If it matters, we restarted the instance three weeks ago.

Thanks for all your help.

Tom Kyte
June 29, 2004 - 4:29 pm UTC

how long does a simple select * from v$lock take.

Commit in another process

A reader, July 06, 2004 - 7:59 pm UTC

Hi Tom,

We have some bugs in the code that causes "dangling transaction", without committing database changes. Do you know if it's possible to commit in another process?

Thanks.

Tom Kyte
July 06, 2004 - 8:38 pm UTC

Yes, I do know.

Thankfully, it is quite impossible.

Think about the ramifications, talk about the left hand not knowing what the right hand is doing, this would be that in spades.

about the only thing you can do is kill it, then fix it.

Commit in other processes

A reader, July 07, 2004 - 12:41 pm UTC

I understand there are good reasons to not publishing it. But does Oracle internally has a back-door for doing this? Guess you wouldn't tell either if there is indeed one... *_*

Tom Kyte
July 07, 2004 - 1:07 pm UTC

no, there is no facility that I'm aware of -- in any way shape or form. It is just beyond "thinkable" to be in a situation like this, really.

dreadfully deadlocked

RD, July 19, 2004 - 6:42 pm UTC

Hi Tom,
We have developers in our company who are working on a internet billing project for an University with about 25000 students. The students when logged into the internet are logged and the logs are passed and turned into database updates ( table called Accounts is updated). There are 2 threads doing the updates and each transaction does about 70-100 updates per call of about 1.5 seconds.Both threads can pickup the same student(s) to update his/her account. Transaction is committed then.
This approach is causing massive deadlocks...
What approach would you suggest for this scenerio???

TO get rid of the deadlocks they have now ordered the students in alphabatical order before updates and the deadlocks are not there anymore. But I think it's just a matter of time before they have them again.Even if not, I still don't think it's the best way to avoid deadlocking.
Am I wrong??

Also the table Accounts is not being referenced or referencing any other tables so no foreign keys exist.

Always appreciate your suggestions,

Regards,
RD.

Tom Kyte
July 19, 2004 - 7:16 pm UTC

the solution would be to split the logs out so that a student does not appear in two different logs -- that would remove the deadlock situation. What happened was thread1 updated george, thread2 updated mary, thread1 tried to update mary (gets blocked) thread2 tried to update george -- bamm, deadlock.

if thread1 is all about mary and thread2 is all about george, no deadlock.

So, sorting the file probably reduced the chance of occurence as "mary" records are colocated and processed by thread1 and "george" records are colocated and processed by thread2. it would only be if your split routine let thread1 have mary and george and thread2 have mary and george would you start deadlocking again.

you'r the man Tom!!!! thanks

RD, July 19, 2004 - 9:51 pm UTC

Did just that and works fine.

Mr RD from NZ

A reader, July 21, 2004 - 12:29 am UTC

plz explain how u did that

selecting all existing tables

Andreas Svensson, July 26, 2004 - 6:30 am UTC

Hi Tom!
How can I select all tables name form my data base?

Tom Kyte
July 26, 2004 - 7:33 am UTC

select owner, object_name, object_type from dba_objects
where object_type = <whatever you want....>



Create trigger

A.S, July 27, 2004 - 7:10 am UTC

Hi, Thanks a lot for answer of my previous questions, which were really good. Now I like to create a trigger, which will update a row of another table soon after I insert values in the first table. I tried a lot (in sqlplus, included in oracle 10g) but failed. I hope u can help me. My table is like so:
Create table T1
(AName varchar2(25),
Type varchar2(15),
Stock_Info number,
Item_Id number);
Create table T2
(BNumber number,
Id number,
quantity number,
AName varchar2(25));
Here AName is pk for T1 and fk for T2, BNumber and Id is pk for T2. I create a trigger like
Create Trigger T1_Info
After insert on Table T2
FOR EACH ROW
WHEN (new.quantity IS NOT NULL)
update table T1 set Stock_Info = Stock_Info-new.quantity
WHERE quantity = new.quantity;
......
But it gives compiling errors all the time. I also tried with BEGIN and END but no result.
Best Regards,

Tom Kyte
July 27, 2004 - 7:36 am UTC

this is simple syntax stuff? there are lots of examples in the application developers guide for triggers.

Please check it out:
</code> http://docs.oracle.com/docs/cd/B10501_01/appdev.920/a96590/adg13trg.htm#376 <code>

you need to use :new in the body of the trigger, you are missing the begin for the trigger block.


Updating two rows in different table

A.S, July 28, 2004 - 10:47 am UTC

Hi Tom!
Thanks a lot. I am just wondering if it is possible to create a trigger which will update two different rows in tow table. If it is possible then provide me a link continging exemples.

Best regards,


Tom Kyte
July 28, 2004 - 1:17 pm UTC

umm, how about the Application Developers Guide - the chapter on triggers.

...
begin
update t2 set x =y where a=b;
update t3 set m=n where l=q;
end;
/



Dave Aldridge, August 06, 2004 - 9:39 am UTC

<quote>
A truncate is just shorthand for:

o drop
o create
o add indexes and grants
<\quote>

Can you clarify whether you mean this literally, Tom? I can see that truncate is equivalent to this (plus adding triggers, MV logs etc), but this isn't what oracle actually does internally surely.

Tom Kyte
August 06, 2004 - 10:20 am UTC

every object has an object_id -- this is what we grant on, what we use as the primary key.

every segment that has "space" -- uses storage -- has a data object id associated with it. that is the 'data"

when you truncate, object_id stays the same -- but the data object id changes. we really do "drop" and "create" (but not grant and stuff -- that is logical)

Dave Aldridge, August 06, 2004 - 12:16 pm UTC

Maybe this is purely conceptual, but would it be fair to say that the "logical object" definition remains as good as untouched, while the physical data segment associated with it is recreated? And that this is why dependencies are not affected, because they are dependencies on the logical object rather than the physical?

Tom Kyte
August 06, 2004 - 1:24 pm UTC

correct -- that would be it exactly.

the object_id related stuff is untouched (grants, etc)
the data_object_id related stuff is dropped and created

and it cascades out to the indexes.

Dave Aldridge, August 07, 2004 - 2:13 pm UTC

Ah, that's a very useful analogy then, because it also applies to partitioned tables (where the table object has no data object id and each partition object does) and to partition exchanges (where the object id of the exchanged partition and table remain the same, and they exchange their data object id's).

Thanks Tom

locks on indexes

Henry Rojas, August 24, 2004 - 11:48 am UTC

Hi Tom

I have a question:
when a session locks a index? this because a I have to sessions on waits and the locked objects are indexes on both sessions

thanks



Tom Kyte
August 24, 2004 - 1:03 pm UTC

how are you "measuring that"



Questions on Locking

Henry rojas, August 24, 2004 - 1:32 pm UTC

I can see this on top session from OEM

Tom Kyte
August 24, 2004 - 3:24 pm UTC

so, what is it showing you that indicates "index locked"

DIfference between V$SESSION in oracle8i & oracle9i ...

VKOUL, September 12, 2004 - 11:16 pm UTC

Please go through the following

##### From session A Oracle 8i

SQL> update scott.dept set deptno=deptno;

4 rows updated.

SQL> 

##### From session B Oracle 8i

SQL> @vip_dev
SQL> select * from v$lock where sid=8;

ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
-------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
05527C54 05527D20          8 TX     262154        334          6          0       1495          0
02AADC70 02AADC84          8 TM       3535          0          3          0       1495          0
02AADBF8 02AADC0C          8 TM       3538          0          4          0       1495          0

SQL> 
SQL> select addr, xidsqn from V$transaction;

ADDR         XIDSQN
-------- ----------
02AD733C        334

SQL> 
SQL> select sid, taddr, lockwait, sql_hash_value, sql_address, prev_hash_value, prev_sql_addr
  2  from   v$session
  3  where sid=8;

       SID TADDR    LOCKWAIT SQL_HASH_VALUE SQL_ADDR PREV_HASH_VALUE PREV_SQL
---------- -------- -------- -------------- -------- --------------- --------
         8 02AD733C              3726624394 032D45FC      3726624394 032D45FC

SQL> 
SQL> select sid, saddr, hash_value, address, sql_text from v$open_cursor where sid=8;

       SID SADDR    HASH_VALUE ADDRESS  SQL_TEXT
---------- -------- ---------- -------- ------------------------------------------------------------
         8 028D0F6C 3726624394 032D45FC update scott.dept set deptno=deptno

SQL> 

##### From session A Oracle 9i

SQL> update scott.dept set deptno=deptno;

4 rows updated.

SQL> 

##### From session B Oracle 9i

SQL> @vip_prod
SQL> select * from v$lock where sid=10;

ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
-------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
6BBA143C 6BBA1548         10 TX     196651        516          6          0       2307          0
6BB4E074 6BB4E088         10 TM      30137          0          3          0       2307          0

SQL> 
SQL> select addr, xidsqn from V$transaction;

ADDR         XIDSQN
-------- ----------
6BBA143C        516

SQL> 
SQL> select sid, taddr, lockwait, sql_hash_value, sql_address, prev_hash_value, prev_sql_addr
  2  from   v$session
  3  where  sid=10;

       SID TADDR    LOCKWAIT SQL_HASH_VALUE SQL_ADDR PREV_HASH_VALUE PREV_SQL
---------- -------- -------- -------------- -------- --------------- --------
        10 6BBA143C                       0 00            3726624394 6A4F86A8

SQL> 
SQL> select sid, saddr, hash_value, address, sql_text from v$open_cursor where sid=10;

       SID SADDR    HASH_VALUE ADDRESS  SQL_TEXT
---------- -------- ---------- -------- ------------------------------------------------------------
        10 6C210C48 3726624394 6A4F86A8 update scott.dept set deptno=deptno

SQL> 

Q1 : Why is current SQL's hash going in PREV columns in Oracle 9i, whereas it looks like goes to both CURRENT and PREV in Oracle 8i

e.g.

(Oracle 9i)

SQL_HASH_VALUE SQL_ADDR PREV_HASH_VALUE PREV_SQL
-------------- -------- --------------- --------
             0 00            3726624394 6A4F86A8

(Oracle 8i)

SQL_HASH_VALUE SQL_ADDR PREV_HASH_VALUE PREV_SQL
-------------- -------- --------------- --------
    3726624394 032D45FC      3726624394 032D45FC

Thanks
 

Tom Kyte
September 13, 2004 - 7:38 am UTC

guess they fixed the bug. session A has no current sql in process.

the current one is documented as "... the SQL statement that is currently being executed". no sql is being executed, so it looks like they are cleaning it up properly when the session is inactive.

questions regarding locks and materialized views and compile

anto, September 22, 2004 - 7:02 pm UTC

Hi Tom,

I have got a couple of questions

a) Can we compile a materialized view, while another session is doing a refresh of this materialized view ? Will the session doing the compile wait, till the refresh is complete ?

b) If an 'alter <db_object_type> <db_object_name > compile' hangs(waits), will this showup in v$lock with condition where request > 0 (db_object_type can be a materialized view or a stored procedure or any other database object). We had this issue(alter materialized view ... compile was hanging) in our production database and hence the question. Is there any way we can find out why the 'alter ... compile' is hanging or not getting completed ?

thanks
Anto




Tom Kyte
September 22, 2004 - 7:53 pm UTC

a) if you fire this up:

ops$tkyte@ORA9IR2> create materialized view mv
  2  build deferred
  3  refresh on demand
  4  as
  5  select a.object_id id1, b.object_id id2
  6    from all_objects a, all_objects b;
 
Materialized view created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> exec dbms_mview.refresh('MV');
 


and in another window do this:

ops$tkyte@ORA9IR2> alter materialized view mv compile;


it'll block (the compile) indefinitely.  the refresh is a "compile" already.

2) and while that is hanging out:

ops$tkyte@ORA9IR2> select
  2        (select username from v$session where sid=a.sid) blocker,
  3         a.sid,
  4        ' is blocking ',
  5         (select username from v$session where sid=b.sid) blockee,
  6             b.sid
  7    from v$lock a, v$lock b
  8   where a.block = 1
  9     and b.request > 0
 10     and a.id1 = b.id1
 11     and a.id2 = b.id2
 12  /
 
BLOCKER                               SID 'ISBLOCKING'
------------------------------ ---------- -------------
BLOCKEE                               SID
------------------------------ ----------
OPS$TKYTE                              12  is blocking
OPS$TKYTE                              11


shows that and we can see:


OPS$TKYTE(11,274) ospid = 4794 command = 0 program =
sqlplus@localhost.localdomain (TNS V1-V3) dedicated server=4795
Wednesday 19:31  Wednesday 19:34 last et = 20227
alter materialized view mv compile
--------------------
OPS$TKYTE(12,99) ospid = 4768 command = 2 program =
sqlplus@localhost.localdomain (TNS V1-V3) dedicated server=4769
Wednesday 19:30  Wednesday 19:34 last et = 110873
INSERT /*+ APPEND */ INTO "OPS$TKYTE"."MV" select a.object_id id
1, b.object_id id2
  from all_objects a, all_objects b

11 is the alter compile, 12 is the refresh...
 

A reader, September 23, 2004 - 2:57 pm UTC


Blocked sessions

A reader, September 23, 2004 - 3:52 pm UTC

Tom,
What are the possible reasons for running into situations with blocked sessions.

Tom Kyte
September 24, 2004 - 9:30 am UTC

too numerous to list here -- think about it.... most of them should be intuitive? (i try to lock a row you locked, i try to lock X that you have already locked)

Blocked sessions

A reader, September 23, 2004 - 6:52 pm UTC

Tom,
When we run the query select * from dba_waiters - we get the results below.

WAITING_SESSION HOLDING_SESSION LOCK_TYPE
--------------- --------------- --------------------------
MODE_HELD
----------------------------------------
MODE_REQUESTED LOCK_ID1 LOCK_ID2
---------------------------------------- ---------- ----------
890 740 Transaction
Exclusive
Share 786433 3141

On examining the SQLs' behind the sessions 740 and 890 - we have found that the session 740 is an update on table_1 and session 890 is an insert on table_2.
Both the update and insert SQLs are container managed beans(and so transcations are automatically taken care of by the EJB container).
That being the case why are we running into blocked sessions and
What are the possible reasons for running into situations with blocked sessions.

Thank you

the query used for examining the SQLs is given below

SELECT TO_CHAR( sid, '999' ) AS sid
, TO_CHAR( piece, '999' ) AS line
, cur_prev AS c
, SUBSTRB
( TRANSLATE
( sql_text
, CHR(9) || CHR(10) || CHR(13)
, ' '
)
, 1, 64
) AS sql
FROM (
SELECT s.username AS username
, 'c' AS cur_prev
, s.sid AS sid
, q.piece AS piece
, q.sql_text AS sql_text
FROM v$session s
, v$sqltext q
WHERE s.sql_hash_value = q.hash_value
AND s.sql_address = q.address
AND ( s.username LIKE 'O2K%'
OR s.username LIKE 'SAFENET_ADMIN%'
)
UNION
SELECT s.username AS username
, 'p' AS cur_prev
, s.sid AS sid
, q.piece AS piece
, q.sql_text AS sql_text
FROM v$session s
, v$sqltext x
, v$sqltext q
WHERE s.sql_hash_value = x.hash_value (+)
AND s.sql_address = x.address (+)
AND x.address IS NULL
AND s.prev_hash_value = q.hash_value
AND s.prev_sql_addr = q.address
AND ( s.username LIKE 'O2K%'
OR s.username LIKE 'SAFENET_ADMIN%'
)
) t
ORDER BY sid, cur_prev, piece
/



Tom Kyte
September 24, 2004 - 10:18 am UTC

<quote>
and so transcations
are automatically taken care of by the EJB container
</quote>

hehehe... oh sigh. ok, anyway.


table1 and table2? are they parent child? is table1 parent of table2? is this "cool beans" thing updating a primary key per chance? is the fkey in table2 indexed?

what other sql does the blocker do? do you know?

SQLTEXT

VKOUL, October 12, 2004 - 7:44 pm UTC

Hi Tom

Welcome Back !!!

Is it possible to get SQLTEXT for all uncomitted DMLs fired from an Oracle session ?

Tom Kyte
October 12, 2004 - 7:57 pm UTC

nope.



"exchange deadlocks" again

Vladimir Andreev, October 14, 2004 - 7:29 am UTC

Hi Tom,

I'm curious about what "exchange deadlocks" might mean. I've read your previous answer above (quoting the Reference guide), but I still can't find out what a "block exchange" is. The only clue I have is that it happens during index scans only (at least until 9i), and after a "buffer busy waits" (reason code 210) wait.

Thanks,
Flado

Tom Kyte
October 14, 2004 - 10:33 am UTC

we are trying to "exchange" a block we have locked in a low mode of locking -- for one at a higher level. we are promoting a lock basically -- we are exchaning are "low locked" block for one at a higher level (and locking is what you need for a deadlock to happen...)

'Blocked sessions

A reader, October 15, 2004 - 7:59 am UTC

Reg. the subject 'Blocked sessions September 23, 2004 ' above

>><quote>
>>and so transcations
>>are automatically taken care of by the EJB container
>></quote>
>>
>>hehehe... oh sigh. ok, anyway.
>>
>>
>>table1 and table2? are they parent child? is table1 parent of table2? is this
>>"cool beans" thing updating a primary key per chance? is the fkey in table2
>>indexed?
>>
>>what other sql does the blocker do? do you know?

table1 and table2 are not parent child tables
The bean is not updating a primary key
FK's in table2 are indexed

Found out from the application log that the update statement(SQL 1) threw a SQLException(integrity constraint) - a value that was not supposed to be put in was being put in. After fixing the code to pass the proper range of FK values, we don't see any blocked sessions against table1 now.

My question
1) Once we get the SQL Exception(integrity constraint) the transcation is rolled back(right!). Why is the SQL exception leading to a blocked session.
2) Reg. >>is the fkey in table2 indexed? I have read in your book that if the FK is not indexed, it locks the child table. And also remenber reading on this site that in later version of oracle (after 9.2.0.4 ?), even if the fk in table2 is not indexed - the child table will not be locked. Is this correct.

Would apprecitae your expert comments on points #1 and #2 above.

Thank you



Tom Kyte
October 15, 2004 - 11:49 am UTC

1) i cannot say -- i'm not following the logic here at all. but you just said "we were updating the wrong rows" so I guess ANYTHING is possible -- you had a bug.

2) it is still locked, for a shorter period of time but it is STILL locked and unindexed fkeys are still "deadlock city"

Blocked session

A reader, October 17, 2004 - 10:47 pm UTC

Sorry for the confusion, let me try to explain.

update employee set name = 'ABC', dept_id= 223 where employee_id = 5;

Say the values for dept_id are from 1 to 5 in the dept table. - since there is no dept_id 223, the application log had an FK constraint error for dept_id. The transcation should have rolledback at this time. Would this situation lead to a blocked session (if the statement, cursor or connection is not closed in the application).



Tom Kyte
October 18, 2004 - 7:53 am UTC

"the transaction should have rolledback"

did it roll back or not? the statement being open/closed is not relevant, the TRANSACTION being left "unended" definitely will (locks are released when you commit, rollback, or do something like "disconnect from the database" -- which of course ends your transaction)

Qt. on Redo Log

Sagar, October 22, 2004 - 9:03 am UTC

Query:
select substr(name,1,25) Name,
substr(value,1,15) "VALUE (Near 0?)"
from v$sysstat
where name = 'redo log space requests';
Result:
Name Value(Near 0?)
redo log space requests 13473

My Question is, Does this result show that i have to add new Redo Log Files to the Log File group

Tom Kyte
October 22, 2004 - 5:42 pm UTC

back to one of my favorite types of questions.

Hey -- i've got one for you. On my last car trip, I stopped and waited at 500 red lights.

Is that

a) good
b) bad
c) indifferent
d) none of the above
e) all of the above

you pick one, I'll show the others are true. you change your mind and pick another, i'll show the others (not the one you just changed to) are true.

That is a number, like "42". Is 42 good?


is that 13,473 requests in 5 minutes, 5 hours, 5 days, 5 months, 5 years?


What you really want to do is see if you are waiting on this -- do you see lots of log waits? do you see "cannot allocate new log" messages in your alert?



expert one on one q

A reader, October 23, 2004 - 5:19 pm UTC

in expert one on one pa 102 (old wrox edition)
you say:
"In a single user database locks are not necessary..."

What is in a single user database, the user runs jobs?
this can result in locking related issues, is not it?



Tom Kyte
October 23, 2004 - 6:22 pm UTC

you don't have a single user anymore if they "run jobs" (which I assume you mean they run multiple things)

a single user database has -- a single user. not the same user logged in 10 times, a single user -- solitary, one...

well..

A reader, October 26, 2004 - 10:37 pm UTC

looks like i misunderstood...
if i have logged in and if i run a job as myself does
not that run in the same database session? Which
implies that one can run into a situation where only
you are logged in but still locking issues arise, is
not it?


Tom Kyte
October 27, 2004 - 7:09 am UTC

if you run a job as yourself, in that session then you have that one job running and you are still "single user"

not understanding this train of thought. a session does one thing at a time, you are in a single user database (single user, single session, one)

blocking lock issues

j, November 05, 2004 - 10:50 am UTC

hi tom,

we are facing some serious problems with blocking locks every now and then within a "legacy" application based on oracle 9i.

when those problems occur we can find out who is blocking who (and force the blockee to logoff in order to "resolve" the conflict).

but we have to track down what happens to provide a solution/fix. the users report that the application runs into the issue only if they use a certain dialog. but unfortunately they can't get this behaviour reproduced on purpose.

that 's why tracing won't be of great help (if applicable at all) to find out the reason(s) why. in addition the code on the database side isn't "instrumented" to support further investigation, and - last but not least - we are forced to use the "minimal impact analysis approach".

which of the choices left (if any) would you take before touching the code in order to produce proper information of what 's going on until a blocking lock appears?

Tom Kyte
November 05, 2004 - 5:11 pm UTC

well, at least you are

<quote>
forced to use the "minimal impact analysis approach"
</quote>

which can also be read to mean "anything goes", you just have to pick the path of least resistance (which could be very impactful :)

but -- what you might be able to do is

o look at v$open_cursor and see what cursors the blocker/blockee have opened
o look at v$lock to see all of the objects each has row locks on

that might be sufficient to figure out "where" in each application you were?

j., November 08, 2004 - 4:47 am UTC

one of those blocking sessions owned almost 170 open cursors ...

is there any way to know the order in which those cursors got created and/or used?

Tom Kyte
November 08, 2004 - 4:32 pm UTC

No, there is not -- not without tracing or some other instrumentation on your part.

why does Oracle put a lock here ?

Matthias Rogel, November 08, 2004 - 10:46 am UTC

Hallo Tom,

please look at this:

Setup:
create table temp(t integer primary key);
create table temp2(t references temp(t));
create index t2_idx on temp2(t);

Session 1:
insert into temp values(1);

Session 2:
lock table temp2 in exclusive mode;

Question:
Why does Session 1 block Session 2 ?
Why does Oracle put a lock here ?

Thanks for reply.



Tom Kyte
November 08, 2004 - 5:07 pm UTC

the integrity constraint...

it gets a TM lock with lmode=2, row-S... pretty much the lowest level of locking, but a lock none the less.

these TM locks are done for two reasons:

a) to reserve DML access to the table
b) to prevent DDL on the table.

In this case, b) is relevant to you.


So, you cannot lock it in exclusive mode, but you can in "share" mode:

ops$tkyte@ORA9IR2> create table temp(t integer primary key);
 
Table created.
 
ops$tkyte@ORA9IR2> create table temp2(t references temp(t));
 
Table created.
 
ops$tkyte@ORA9IR2> create index t2_idx on temp2(t);
 
Index created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> insert into temp values(1);
 
1 row created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select type, lmode, object_name
  2    from v$lock, user_objects
  3   where sid = (select sid from v$mystat where rownum=1)
  4     and type = 'TM'
  5     and id1 = object_id
  6  /
 
TY      LMODE OBJECT_NAME
-- ---------- ------------------------------
TM          3 TEMP
TM          2 TEMP2
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          lock table temp2 in exclusive mode;
  5          commit;
  6  end;
  7  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4
 
 
ops$tkyte@ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          lock table temp2 in SHARE mode;
  5          commit;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 

to prevent DDL on the table.

Matthias Rogel, November 09, 2004 - 3:33 am UTC

ok, thank you very much Tom,
of course Oracle has to prevent DDL on the table.

of course "of course", but ...

Matthias Rogel, November 10, 2004 - 10:38 am UTC

Hallo Tom,

of course I answered "of course"
(because you mentioned something I didn't think of
namely
"b) to prevent DDL on the table.")

but:
why has Oracle to prevent DDL on temp2 here ?
I cannot think of any Use Case where -
in the situation given -
DDL on temp2 would cause Violation of Data Integrity.

(I always thought the main purpose of locking is
protecting data integrity, and that Oracle uses locks as economical as possible)

so:
1. which DDL on temp2 could cause violation of Data Integrity here ?
2. (if answer to 1. is empty) why has Oracle to prevent DDL on the temp2 in the situation given ? (what am I missing)

Thank you anyway for maintaining my favourite site on www.

Tom Kyte
November 10, 2004 - 12:21 pm UTC

your transaction is dependent on it, that is all -- it isn't "your data" integrity, it is dependency. you've referenced that fkey, it cannot be modified now.


it is the lowest level lock possible here remember.

1) didn't say it would hurt data integrity, it is the dependency mechanism as work here.

2) because we do.... we are dependent on the fkey here now, fkey is constraint on table, table is temp2. no ddl to temp2.


thanks

Matthias Rogel, November 11, 2004 - 4:11 am UTC

Thank you Tom for improving my understanding of how oracle works

Hoping this is still on subject......

Robert, November 11, 2004 - 10:47 am UTC

Tom,

Is it possible to do something like an "insert...NOWAIT" statement?

We have multiple processes inserting rows into a 3rd party application table and need to be able to gracefully handle duplicates.

The primary key is: account_id, account_id_seq
where account_id_seq is 0,1,2...n for each account_id.

We calculate the new row's account_id_seq by:
select max(account_id_seq)+1
from <table>
where account_id = :v_account_id

Thanks,

Robert.

Tom Kyte
November 11, 2004 - 10:49 am UTC

can we fix the problem -- the botched algorithm??

select max(account_id_seq)+1 is "not very smart (tm)"

why would you not use a sequence?

"Not our Fault"

Robert, November 11, 2004 - 11:06 am UTC

Tom,

This is the way the 3rd party application is designed.
The account_id_seq field is to create a unique key in combination with the account_id.

(1) If Oracle knows that an inserted record causes a PK violation with another uncommited record.... why not have an option to immediately return with an error (e.g. NOWAIT)... instead of waiting until the blocking transactions commits or rollbacks?
(2) Any ideas on how to get around this problem within the confines of the 3rd party app design?

Thanks,

Robert.

Tom Kyte
November 11, 2004 - 11:12 am UTC

"This is the way the 3rd party application is designed."

that would be an oxymoron if I every heard of one :)

I see what it is supposed to do, however anyone that can spell database (neat how that is a word typed entirely with the left hand, i happen to be left handed...) should know it is also *wrong* (from a concurrency perspective and from an application implementation one -- it screams out "lets insert duplicates!!!")


but what you are saying is that even if there were a NOWAIT option, so what? you apparently cannot fix the code, and nowait would be a code change and if you could stick in a nowait, we can CERTAINLY stick in a sequence and fix it!

for #3 (there is that 'design' word again :)

See

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:340617419132 <code>

hopefully the application gracefully deals with ora-54's

Thanks!

Robert, November 11, 2004 - 12:16 pm UTC

Tom,

(1) Thanks for the DBMS_LOCK idea.....Any bad side effects on setting enqueue_resources to 100,000 (or so)?

(2) I still don't see why Oracle can't implement "INSERT...NOWAIT"? You would handle the ORA-54 just as you would with an "UPDATE..NOWAIT" or your DBMS_LOCK idea (vs. waiting 2 hours for the other transaction to commit)... Comments?

Thanks,

Robert.

Tom Kyte
November 11, 2004 - 2:46 pm UTC

well, they consume memory. seems high unless you are really active (but you cannot be really active, not with a "designed" 3rd party application like that one)....

right now, nowait is purely a "select for update", "lock table" thing (not update) -- but, anyone with support can file enhancement requests ;)

Running Version 8.1.7.4

Robert, November 11, 2004 - 12:25 pm UTC

Tom,

I forgot to mention on my above question, we are running Oracle 8.1.7.4.

Robert.

Repackaged final question into single post.....

Robert, November 11, 2004 - 12:41 pm UTC

Tom,

<Running 8.1.7.4>

(1) Thanks for the DBMS_LOCK idea.....Any bad side effects on setting
enqueue_resources to 100,000 (or so)?

(2) I still don't see why Oracle can't implement "INSERT...NOWAIT"? You would
handle the ORA-54 just as you would with an "UPDATE..NOWAIT" or your DBMS_LOCK
idea (vs. waiting 2 hours for the other transaction to commit)... Comments?

Thanks,

Robert.



Enhancement Request Filed!

Robert, November 11, 2004 - 3:22 pm UTC

Tom,

Per your suggestion I filed an enhancement request for this. (seems very logical to me).

One final question, please:
How can I find the memory used by 'enqueue_resources'?

I tried...
select * from v$sgastat
where lower(name) like '%enq%';

But it returned 0 rows.

Thanks,

Robert.


Tom Kyte
November 11, 2004 - 4:22 pm UTC

it is an SGA thing.

ops$tkyte@ORA9IR2> show parameter enqueue
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
enqueue_resources                    integer     968

ops$tkyte@ORA9IR2> show sga
 
Total System Global Area  305730740 bytes
Fixed Size                   451764 bytes
Variable Size             201326592 bytes
Database Buffers          100663296 bytes
Redo Buffers                3289088 bytes


ops$tkyte@ORA9IR2> alter system set enqueue_resources = 100000 scope=spfile;
 
System altered.
 
ops$tkyte@ORA9IR2> connect / as sysdba
Connected.
ops$tkyte@ORA9IR2> startup force
ORACLE instance started.
 
Total System Global Area  322507976 bytes
Fixed Size                   451784 bytes
Variable Size             218103808 bytes
Database Buffers          100663296 bytes
Redo Buffers                3289088 bytes
Database mounted.
Database opened.


ops$tkyte@ORA9IR2> select (322507976-305730740)/1024/1024 from dual;
 
(322507976-305730740)/1024/1024
-------------------------------
                     16.0000191
 
ops$tkyte@ORA9IR2>
 

Very much most useful!

Robert, November 11, 2004 - 4:33 pm UTC

Thanks, Tom!

Tom Kyte
November 12, 2004 - 6:51 am UTC

oh, one thing to point out -- the SGA is allocated in granules in 9i -- so, that 16 meg isn't all about the enqueue resources -- it is just that I caused the sga to grow by a couple of granules (they are 4, 8, 16m depending)

Hi Vidya sends you his good wishes

Vidya Sagar, November 17, 2004 - 9:06 am UTC

Can we import data into a table whose name is different to its existing name from a dmp file.

Tom Kyte
November 17, 2004 - 11:02 am UTC

only via a view (in 9i and before, without data pump) -- you could create a view as the old name, imp with ignore=y

imp just issues "insert into TABLE_NAME ("COLUMNS...." ) values ( .... );



Thank You

Vidya Sagar, November 18, 2004 - 12:53 am UTC

Actually we have a table that had no constraint keys with 20 million + records.
As a performance issue was raised while retrieving data from this table as part of fine tuning we had taken a backup of this table as .dmp file and then dropped the table.
We created Primary key, Indexes etc. on this and then we had new records inserted from Aug'04.
Now the user wants data for the month of July. In this context i wanted your suggestion.

Tom Kyte
November 18, 2004 - 10:25 am UTC

"as part of fine tuning" -- that sounds more like "as part of going back and redesigning the system to use database stuff, something we didn't do in the first place for some unknown reason..."

anyway,

import the table into another schema and let them at it? 20 million rows is pretty small.

Thank you

Vidya, November 19, 2004 - 4:32 am UTC

Can we import data from a dmp file, into an existing table in Oracle V 7.1.



Tom Kyte
November 19, 2004 - 10:54 am UTC

sure, as long as the dmp file was made by a version of oracle less than or equal to 7.1 (eg: 7.1 imp can read a 7.1 or before exp file, but not a 9i exp file)

Row Lock waits on index?

K U, November 19, 2004 - 10:00 am UTC

On complaints of 'slowness', I found V$segstat view (10.1.0.2 database on Solaris2.8) contains exessive number of 'row lock waits' on certain objects, which were all found to be INDEXES. (The database was bounced only 30 hrs earlier)
I would like to know how indexes are handled while locking in transactions. In this case, there was not a single 'row lock wait' found for any table, instancewide.
I appreciate your attention to this question.

Thanks,
KU


Tom Kyte
November 19, 2004 - 11:55 am UTC

what is "excessive" and have you determined this to be what sessions are actually WAITING on?

excessive needs lots of qualifications.

(me, i'd rather see what people are waiting on, rather than collecting everything people MIGHT be waiting on -- and fixing what they actually wait for, rather then what they might be waiting for.  you might even "fix" something that a process was waiting for -- but no one cared much about -- letting it go faster and taking yet more of the resource your end users are really waiting for...)


The row lock waits occur during index block splitting in a multi-user environment.  They are incremented even when it was POSSIBLE you waited (meaning, you may not have waited very long if at all). You can see them in a small test:

ops$tkyte@ORA10G> create table t ( x char(255), y char(255), z char(255) );
 
Table created.
 
ops$tkyte@ORA10G> create index t_idx1 on t(x);
 
Index created.
 
ops$tkyte@ORA10G> create index t_idx2 on t(y);
 
Index created.
 
ops$tkyte@ORA10G> create index t_idx3 on t(z);
 
Index created.
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> break on obj skip 1
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> select (select object_type || '.' || object_name
  2            from dba_objects
  3                   where object_id = obj#) obj, statistic_name, value
  4    from v$segstat
  5   where obj# in ( select object_id from user_objects where object_name like 'T%' )
  6     and value > 0
  7   order by 1
  8  /
 
OBJ             STATISTIC_NAME            VALUE
--------------- -------------------- ----------
INDEX.T_IDX1    space allocated           65536
                space used                 8086
                db block changes             16
                logical reads                32
 
INDEX.T_IDX2    space allocated           65536
                db block changes             32
                space used                 8086
 
INDEX.T_IDX3    space allocated           65536
                space used                 8086
                db block changes             32
 
TABLE.T         space allocated           65536
                db block changes             16
 
 
12 rows selected.
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> create or replace procedure do_insert
  2  as
  3  begin
  4          for i in 1 .. 1000
  5          loop
  6                  insert into t values ( i, i, i );
  7          end loop;
  8  end;
  9  /
 
Procedure created.
 
ops$tkyte@ORA10G> variable n number
ops$tkyte@ORA10G> exec dbms_job.submit(:n,'do_insert;');
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G> exec dbms_job.submit(:n,'do_insert;');
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G> exec dbms_job.submit(:n,'do_insert;');
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G> exec dbms_job.submit(:n,'do_insert;');
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G> exec dbms_job.submit(:n,'do_insert;');
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G> commit;
 
Commit complete.
 
ops$tkyte@ORA10G> show parameter job
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
job_queue_processes                  integer     10
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> declare
  2          n number;
  3  begin
  4          loop
  5                  select count(*) into n from user_jobs;
  6                  exit when n=0;
  7                  dbms_lock.sleep(3);
  8          end loop;
  9  end;
 10  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> select (select object_type || '.' || object_name
  2            from dba_objects
  3                   where object_id = obj#) obj, statistic_name, value
  4    from v$segstat
  5   where obj# in ( select object_id from user_objects where object_name like 'T%' )
  6     and value > 0
  7   order by 1
  8  /
 
OBJ             STATISTIC_NAME            VALUE
--------------- -------------------- ----------
INDEX.T_IDX1    space allocated         3145728
                space used              1773142
                row lock waits               23
                db block changes           8432
                buffer busy waits            63
                physical writes             269
                ITL waits                     3
                logical reads             13328
 
INDEX.T_IDX2    space allocated         3145728
                logical reads             15200
                buffer busy waits            31
                db block changes           8000
                physical writes             264
                ITL waits                     2
                row lock waits               17
                space used              1773142
 
INDEX.T_IDX3    space allocated         3145728
                logical reads             14032
                buffer busy waits            29
                db block changes           8048
                physical writes             260
                ITL waits                     3
                row lock waits                6
                space used              1773142
 
TABLE.T         space allocated         5242880
                space used              4003043
                physical writes             450
                db block changes           8016
                buffer busy waits            43
                logical reads             10400
 
 
30 rows selected.




<b>so, i would encourage you to see what your important applications are actually waiting on, not what they could be -- might be -- maybe waiting for</b>
 

questions on locking

A reader, November 20, 2004 - 3:01 pm UTC

Hi tom ,
discussion is most useful.
Excellent. I have a small clarification on account lock.
if a account is locked due to 3 to 4 attempts with invalid passwd then account will lock. If any application is pointing then it will not retrive data. Am I correct.
if so how any I find out who tryed that many times.

Thanks
Raju

Tom Kyte
November 20, 2004 - 3:36 pm UTC

You cannot find out who tried that many times -- by definition they never successfully IDENTIFIED themselves!

if you enable auditing, you can see information on the failed attempts such as the machine they tried logging in from and such which you might find useful.

Select for Update

N.Balasubramanian, December 05, 2004 - 11:59 pm UTC

I have read your first book and understood that there is no lock manager in oracle. When the server process goes to the block to update the row, it finds that the row is either free or locked by another transaction. But my doubt is this.
Let us assume we construct a cursor with a where clause (not the entire table) and with a select for update which retrieves 10000 rows. All the rows are not locked when the cursor is opened. Only when the actual FETCH takes place, the locking takes place. (It is my understanding). But when it is processing 1000th row, another transaction may modify 9000th row and commit it. Then what is the use of our locking the rows with FOR UPDATE. Please explain.

Tom Kyte
December 06, 2004 - 11:33 am UTC

<quote>
All the rows are not
locked when the cursor is opened.
</quote>

ahh -- but they are!


drop table t;
create table t as select * from all_objects;
variable x refcursor
variable y refcursor
alter session set sql_trace=true;

begin
open :x for select * from t for update;
open :y for select * from t;
end;
/

SELECT * FROM T FOR UPDATE

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 4 0 0
Execute 1 1.12 1.74 394 877 48144 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 1.12 1.75 394 881 48144 0
********************************************************************************
SELECT * FROM T

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 45 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.01 0.00 0 45 0 0


the for update changes the behavior, the stable set of rows must be identified AND THEN returned.


see
</code> http://asktom.oracle.com/~tkyte/wc.html <code>

for "why" -- in order to select for update the CONSISTENT set of rows, we must do the same thing as an UPDATE does (and would be subject to the same exact restart conditions)

Select for update

N.Balasubramanian, December 06, 2004 - 10:57 pm UTC

Thank you Tom. So, in a normal cursor (without select for update), the rows are not locked when the cursor is opened and they get locked as and when the rows are fetched. whereas in the case of a cursor with a select for update clause, the rows are locked when the cursor is opened.

Tom Kyte
December 07, 2004 - 10:03 am UTC

the rows are NOT LOCKED (that would be the other databases) in a simple select from table. they are NEVER LOCKED in a simple select like that.

Simple Select statement

N.Balasubramanian, December 08, 2004 - 1:58 am UTC

Yes. Yes. The rows are never locked when they are fetched in a simple select statement. Thank you for the correction.

A reader, December 09, 2004 - 11:54 am UTC

Tom,

Let's suppose there is a remote database table undergoes frequent things that lock multiple rows of that table. Eg: a new index creation. There is a local application that does inserts into the remote table. It's obvious that the ora-02049 will occur. I understand _DISTRIBUTED_LOCK_TIMEOUT can be increased to 300 (5 mins). If the remote table doesn't release locks after 5 mins, obviously ora-02049 will occur again. Is it mandatory that the application be designed to implement try again logic until it finds that the lock released? I believe it's not a deadlock scenario and therefore the application should go for the try again approach. Please clarify.

Tom Kyte
December 09, 2004 - 3:18 pm UTC

"a new index creation" -- doesn't have to lock anything, they can be online.


the application would have to catch that error and try again, there is no other way. increasing the timeout would not be something I would suggest.

How to relaese the lock?

Sanjay Jha, December 15, 2004 - 12:01 pm UTC

Tom,
I have the following problem:
system@WLPISAT1> select count(*) from wlpi11.notifierpost;
select count(*) from wlpi11.notifierpost
*
ERROR at line 1:
ORA-01591: lock held by in-doubt distributed transaction 3.1.7118

I tried to release the lock:
system@WLPISAT1> commit force '3.1.7118';
commit force '3.1.7118'
*
ERROR at line 1:
ORA-02058: no prepared transaction found with ID 3.1.7118

system@WLPISAT1> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('3.1.7118');
BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('3.1.7118'); END;

*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "SYS.DBMS_TRANSACTION", line 86
ORA-06512: at line 1

I log on as sys then I try again:
sys@WLPISAT1> execute dbms_transaction.purge_lost_db_entry('3.1.7118');
BEGIN dbms_transaction.purge_lost_db_entry('3.1.7118'); END;

*
ERROR at line 1:
ORA-01453: SET TRANSACTION must be first statement of transaction
ORA-06512: at "SYS.DBMS_TRANSACTION", line 65
ORA-06512: at "SYS.DBMS_TRANSACTION", line 85
ORA-06512: at line 1

Please help.

Tom Kyte
December 15, 2004 - 2:30 pm UTC

commit;
execute dbms_transaction.purge_lost_db_entry('3.1.7118');



It did not work.

Sanjay Jha, December 15, 2004 - 3:05 pm UTC


sys@WLPISAT1> select * from v$version;

BANNER
----------------------------------------------------------------------------------------------------
Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
PL/SQL Release 8.1.6.0.0 - Production
CORE 8.1.6.0.0 Production
TNS for HPUX: Version 8.1.6.0.0 - Production
NLSRTL Version 3.4.0.0.0 - Production


sys@WLPISAT1> commit;

Commit complete.


sys@WLPISAT1> execute dbms_transaction.purge_lost_db_entry('3.1.7118');
BEGIN dbms_transaction.purge_lost_db_entry('3.1.7118'); END;

*
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYS.DBMS_TRANSACTION", line 94
ORA-06512: at line 1


Tom Kyte
December 15, 2004 - 6:19 pm UTC

please contact support.

Oracle Support resolved the problem, but your

Sanjay Jha, December 16, 2004 - 10:23 pm UTC

Tom,
As it turned out, there were some "abnormal" behaviour by Oracle and we had to do "something" artificial.
I had shutdown and restarted the database instance even then the lock did not get released.
First thing Oracle support asked me to do was to verify whether there were any entries in pending_trans$ or pending_session$, and in my case there were no records in these. Then I was asked to run the following query:
SQL>SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
KTUXESTA Status,
KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!='INACTIVE'
AND ktuxeusn= 3;
This told us that there is indeed a trace of transaction in RBS # 3 in slot 1 with sequence number 7118 that is why 3.1.7118. (I beleive that after restaring the database the instance recovery did bring back this in RBS#1). 
Then of course there was a "fake" entry made in pending_trans$ and pending_session$ for Local_tran_id='3.1.7118' ,
SQL>alter system disable distributed recovery;
SQL>insert into pending_trans$ (
LOCAL_TRAN_ID,
GLOBAL_TRAN_FMT,
GLOBAL_ORACLE_ID,
STATE,
STATUS,
SESSION_VECTOR,
RECO_VECTOR,
TYPE#,
FAIL_TIME,
RECO_TIME)
values( '3.1.7118', /* <== Replace this with your local tran id */
306206, /* */
'XXXXXXX.12345.1.2.3', /* These values can be used without any */
'prepared','P', /* modification. Most of the values are */
hextoraw( '00000001' ), /* constant. */
hextoraw( '00000000' ), /* */
0, sysdate, sysdate );

SQL>insert into pending_sessions$ 
values( '3.1.7118',/* <==Replace only this with your local tran id */
1, hextoraw('05004F003A1500000104'), 
'C', 0, 30258592, '', 
146
);
SQL>commit;

And then 
SQL>commit force '3.1.7118';worked and everything was resolved.
Of course we had to issue following afterwords,

SQL>delete from pending_trans$ where local_tran_id='3.1.7118';
SQL>delete from pending_sessions$ where local_tran_id='3.1.7118';
SQL>commit;
SQL>alter system enable distributed recovery;
Everything is fine thenafter.
I have few questions:
Q1. In due course would these entries in Rollback Segment been overwritten and that would have solved the problem? (May be that explains why we have this problem resolved by itself in past).
Q2. Why RECO could not clean this up by itself? I saw one RECO unix process running.
Q3. Was it a case when data block header got "corrupted" so the lock information was not released? I must mention a sttement made in a forum (
http://forums.bea.com/bea/message.jspa?messageID=200602098
) where they point to a "serious bug" in Oracle with respect to locking in case of in-doubt transactions, your thoughts please.
and lastly, do you have any suggestions to prevent this in future. (I searched on web and what I heard from people supporting this application in my place over the years, there have been many instances of this problem caused by Tuxedo/Weblogic ), please address it here.

Thanks a lot Tom in advance. 

Tom Kyte
December 17, 2004 - 7:46 am UTC

please work bugs with support -- this is what they do.

Clarification

A reader, December 30, 2004 - 4:48 pm UTC

Hi Tom,

In one of the discussion thread above, you mentioned that you can view only the current statement and the other statements might not be even in the shared pool.
1.Then does that mean Oracle will do a hard parse next time?
2. I ran the script you had provided above to detect locks on my development environment and it takes a long time to run. Is there any other script that I can make use of to detect locks.
3. What is the meaning of ROW_WAIT_OBJ#/FILE#/BLOCK# in V$SESSION if they are not equal to -1. If they are populated with positive values when there are table locks, how can I find the blocking and blocked transactions

Tom Kyte
December 30, 2004 - 6:11 pm UTC

1) if the statement is not in the shared pool -- yes, a hard parse must be done

2) you could use gtt's (global temporary tables) and insert into them the contents of these two v$views and join the gtt's (v$ queries can be expensive)

3) the query to find the blockers is above... but the meaning of the numbers in those columns are "thats the object id of the thing waited on, the file the row of interest is in and the block in that file" -- add that with the row# and you have everything you need to get the rowid (using dbms_rowid)

Temp tables different

Gabriel, January 14, 2005 - 11:01 am UTC

Hello Tom,

Can you please tell me if there are any differences between the way oracle handles locks on global temporary tables and heap tables? How does oracle keep tracks of which rows belong to which session?

Thank you,

Tom Kyte
January 14, 2005 - 7:55 pm UTC

each session gets their own segment.

temporary tables are dynamically allocated segments that exist in the tablespace of the current user. Meaning - my temp table data might be in TEMP1 while yours is actually way over in TEMP2...



A reader, January 19, 2005 - 11:05 am UTC


Can you explain the concept of RS and SRX locking ?

Parag Jayant Patankar, January 21, 2005 - 3:12 am UTC

Hi Tom,

Do make my understanding very clear will you pl kindly explain locking modes

1. RX ( Row exclusive )
2. RS ( Row share mode )
2. RSX ( Row share exclusive mode )

and when they will be useful ? ( kindly be more elaborate on concept and usefullness of RSX )

Q2. for insert/update/delete RX and RS locks are permitted. I can understand RX for particular row or rows which are candidate for insert / update / delete but what is the purpose and usefullness of RS in such case ?

thanks & regards


Tom Kyte
January 21, 2005 - 8:04 am UTC

Have you seen the chapter (well written) in the Concepts guide that describes each of these, says what they do and gives examples of the types of statements that cause each?

</code> http://docs.oracle.com/docs/cd/B10501_01/server.920/a96524/c21cnsis.htm#3017 <code>

Pl Clarify for understanding of locks

Parag Jayant Patankar, January 22, 2005 - 5:18 am UTC

Hi Tom,

After going thru CONCEPTS manual and application developers guide of locking as suggested by you in this thread, it is making me more confused. I have following questions to you.

Q1. In my earlier question to you ( </code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:25323841260334
) you said that 

<Quote>
do you have my book "Expert one on one Oracle"
the TX is not a row lock, TM is the "row lock" actually.
...
<quote>
but in concept manual it is very clearly written ROW LOCKS (TX) and TABLE LOCKS (TM). I am really confused by this because rather than oracle manual(s) I am beliving on you, So which one is correct ?

Q2. In 
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96590/adg08sql.htm#2483 <code>it is written that

<quote>
ROW SHARE and ROW EXCLUSIVE table locks offer the highest degree of concurrency.

You might use these locks if:

Your transaction needs to prevent another transaction from acquiring an intervening share, share row, or exclusive table lock for a table before the table can be updated in your transaction. If another transaction acquires an intervening share, share row, or exclusive table lock, no other transactions can update the table until the locking transaction commits or rolls back. <=== ***** statement 001 ******

Your transaction needs to prevent a table from being altered or dropped before the table can be modified later in your transaction
<quote>

Question 2 ==> What does mean "highest concurrency" here ?

What documentation want to say in "statement 001" ? ( I have understood meaning of it but I can not linked to practical situation where it is happening and where it will be required )

Q3 if I do update on emp table it is showing me following in v$lock

ADDR KADDR SID TY ID1 ID2 LMODE
-------- -------- ---------- -- ---------- ---------- ----------
20158AB4 20158B80 19 TX 65557 113607 6
3848C228 3848C23C 19 TM 77614 0 3

Is it showing TX ( Row Lock ) having lmode 6 ( Exclusive lock ) ? if yes why documentation of concept not saying anything about it ? concept manual is saying only these locks about TM not about TX

<quote>
A table lock can be held in any of several modes: row share (RS), row exclusive (RX), share (S), share row exclusive (SRX), and exclusive (X). The restrictiveness of a
table lock’s mode determines the modes in which other table locks on the same table can be obtained and held <quote>

Q4 when TX lock is getting appeared in v$lock ? because my understanding from your book "Expert ..." is TX lock is acquired when transaction initiates its first change and it is held until transaction performs commit or rollback. It is for queuing mechanism so other sessions can wait for transaction to complete.

If I lock a table for future transactions it is not showing TX lock in v$lock. locking SQL ommand is it not considered as a part of starting point of a transaction ?

Q5. Can you tell me practical use of share row exclusive lock by application ?

thanks & regards
pjp

Tom Kyte
October 27, 2009 - 11:47 am UTC

q1: the confusion arises from the fact that people waiting for a row lock block on the TX lock (the transction lock, the single TX lock I get when I start a transaction)

ops$tkyte@ORA9IR2> select sid, type, id1, id2 from v$lock  where sid = (select sid from v$mystat where rownum=1 );
 
no rows selected
 
ops$tkyte@ORA9IR2>  exec dbms_output.put_line( dbms_transaction.LOCAL_TRANSACTION_ID(true) );
7.38.860
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2> select sid, type, id1, id2 from v$lock  where sid = (select sid from v$mystat where rownum=1 );
 
       SID TY        ID1        ID2
---------- -- ---------- ----------
        10 TX     458790        860
 
ops$tkyte@ORA9IR2>


<b>now see -- I haven't updated a single thing.  I have a transaction however, the 'TX' thing is my "transaction".  When and if someone was to get blocked by ME, they would get blocked on my TX lock.  For example:</b>

ops$tkyte@ORA9IR2> update emp set ename = ename where rownum = 1;
 
1 row updated.
 

  1* select sid, type, id1, id2, block from v$lock  where sid = (select sid from v$mystat where rownum=1 )
ops$tkyte@ORA9IR2> /
 
       SID TY        ID1        ID2      BLOCK
---------- -- ---------- ---------- ----------
        10 TX     458790        860          0
        10 TM      37224          0          0
 
ops$tkyte@ORA9IR2>


<b>that tm lock shows I have row locks now on the object with the id 37,224 (or that i COULD have row locks -- i would get that upon the update of zero rows as well)

Now, if someone else gets blocked by me...</b>

ops$tkyte@ORA9IR2> /
 
       SID TY        ID1        ID2      BLOCK
---------- -- ---------- ---------- ----------
        10 TX     458790        860          1
        10 TM      37224          0          0


<b>see how they get blocked on me -- on my TX, not on my TM, on my TX..  they are waiting for a row lock there</b>


q2: higher concurrency means there is the opportunity to do things at the same time that if we used more powerful locks you could not.



TX is your transaction, it isn't really a "lock" protecting a piece of data (see, I got one without touching data at all -- just by beginning a transaction).  It is a powerful lock however that others can be made to wait on -- until it disappears (i commit or rollback).

We call it an "enqueue", you are "enqueued waiting for that transaction to commit or rollback (finish in short)".  You are in a queue, in a line and the key to this line, the lock, is the TX lock. 

Hi,

sns, January 25, 2005 - 12:09 pm UTC

I have a wierd situation in 9.2.0.5 database.
I am analyzing the tables owned by user A serially by executing my own anonymous pl/sql block in a session.
There is a view owned by the same user that uses 9 tables out of some 100.

The problem is, when the analyze job starts it progress smootly until it hits the table that is part of the view.
It hangs for ever until we kill the analyze job session.

What we observed is, there is a library cache lock in the session wait table the moment analyze job starts analyzing the table which is used in the view.

I am not sure why this kind of clash happens. Any idea?

Thanks

Tom Kyte
January 25, 2005 - 1:21 pm UTC

nope, I suggest filing a tar with support, they can dump more supporting information if you get to the "hang" again.

(the "view" seems perhaps not relevant -- why do you think that there is this view there is some connection?

sns, January 25, 2005 - 3:02 pm UTC

I agree that view is not the culprit. However, if I comment out the tables in my analyze list that are part of the view, then the analyze job sails smoothly and completes. This made us to think that view and analyze together may be the culprit for library cache lock.

In fact, the size of the tables that are in the view definition are very small (few hundered rows).

What else could be the reason?

Tom Kyte
January 25, 2005 - 3:22 pm UTC

can you reproduce this in a schema with 2 tables and a view?

I have another question regarding the ON_LOCK procedure

A reader, January 26, 2005 - 5:49 pm UTC

Is there any possibility to override the on_lock procedure defined in Oracle FOrms.

I have a Form with the ON_LOCK trigger and the block is a simple update block for a single table.

But the ON_LOCK procedure is not catching up.Instead I'm getting the COULD NOT RESERVE RECORD (2 tries) KEEP TRYING?
Error message.

Any info?




Tom Kyte
January 27, 2005 - 7:43 am UTC

yes, you create your own on_lock trigger.

but -- in your case, doing so would be "a bad idea(tm)"

do you see that perhaps it is trying to tell you "sorry, but someone else has this record locked, you lose"

ON_LOCK

A reader, January 27, 2005 - 5:45 pm UTC

No The ON_LOCK procedure is not at all catching up.
Forms is acting as if I don't have the ON_LOCK trigger in my code.


Tom Kyte
January 28, 2005 - 7:12 am UTC

please contact support then, if what you say is "true", it would be "not correct"

(and as I stated above, even if it works -- it would be *wrong* to do it)

Questions on Trigger

sam, February 10, 2005 - 5:51 pm UTC

Tom,

Do we have any mechanism that we can know the time of commit & record that time in table somehow.

What I need is something like on commit trigger. So that I can note a time of commit.

Thanks for your help as always

Tom Kyte
February 11, 2005 - 7:46 pm UTC

whats the goal here, what are you trying to accomplish -- maybe I can suggest something given the problem description.

(why would the commit time -- which you could sort of record from the app by:


begin do_commit; end;


instead of

commit;

and have do_commit do

insert into ....
commit;



Who is (really) blocking?

max, February 12, 2005 - 2:31 pm UTC

hi tom,

i 've observed (but didn't understand) the following:

-- 1st session (SID 15)
select * from test for update ;

-- 2nd session (SID 12)
select * from test where num = 1 for update ;

-- 3nd session (SID 13)
select * from test where num = 2 for update ;

-- 4th session (monitoring)

select * from sys.dba_waiters
WAITING_SESSION HOLDING_SESSION LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2
--------------- --------------- --------- --------- -------------- -------- --------
13 12 Transaction None Exclusive 196654 3046
12 12 Transaction None Exclusive 196654 3046
13 13 Transaction None Exclusive 196654 3046
12 13 Transaction None Exclusive 196654 3046
13 15 Transaction Exclusive Exclusive 196654 3046
12 15 Transaction Exclusive Exclusive 196654 3046

6 row(s) retrieved

from my point of view sessions 12 and 13 waited for session 15 to release locks held. as expected there has been no waiter left when session 15 ended its transaction ...

so, why are session 12 and 13 listed as BLOCKERS in DBA_Waiters?

Tom Kyte
February 12, 2005 - 3:35 pm UTC

with l as
(select rownum r, x.* from v$lock x)
select
(select username from v$session where sid=a.sid) blocker,
a.sid,
' is blocking ',
(select username from v$session where sid=b.sid) blockee,
b.sid
from l a, l b
where a.block = 1
and b.request > 0
and a.id1 = b.id1
and a.id2 = b.id2
/

that I know what it does -- and what it shows (and would show 2 rows).

the mode_held = none rows are "ignorable" there in dba_waiters (appears that there is a cartesian result going on -- if you have 4 people waiting, there are 16 ignorable rows, 3 people waiting -- 9, 2 people -- 4)




max, February 12, 2005 - 4:54 pm UTC

that 's really great.

before i 've failed with DBA_Waiters i 've read some other articles covering locks that mention predicates such as v$session.lockwait is NULL for blockers and NOT NULL for blockees, v$lock.id1 = id of locked object in case v$lock.type = 'TM' and so on ... where did you get the information from how to join those views and which filter to apply to which column (e.g. v$lock.block = 1, v$lock.request > 0)?

sometimes sources don't even have a timestamp or any other information to which release they apply to.

as apposed to some other approaches your query generates correct/expected results for all my test cases -- i really appreciate that. but although i believe it is robust and nothing undocumented i can't figure that out from the documentation (i 've read so far). would you mind to give some background information on how you came up with that?

could you please show me the path from your query to the locked object?

thank you very much for your valuable help and advice?

Tom Kyte
February 12, 2005 - 5:05 pm UTC

it is just a self join of v$lock to itself. did you read the original article above?

6 from v$lock a, v$lock b
7 where a.block = 1
8 and b.request > 0
9 and a.id1 = b.id1
10 and a.id2 = b.id2


a.block = 1 -- this row is a blocker
b.request > 0 -- the other row is trying to get a lock, 0 = "none"
id1/id2 are the resource identifiers -- what is trying to be locked.

so, we find all of the blockers and join them up to people waiting on the resource they are blocking.

(everything on this site has a date associated with it and the examples always have the version in the prompt -- the above material is actually from Expert one on one Oracle -- my first book)

how to find locked object ...

max, February 12, 2005 - 5:08 pm UTC

is it sufficient to join v$session.row_wait_obj# and all_objects.object_id?

i remember a constraint v$session.row_wait_obj# != -1 and v$session.status = 'ACTIVE' and v$session.type = 'USER' -- but can't remember anymore whether it applies to the "state" of v$session.row_wait_obj# (valid or not).

can you confirm that?

Tom Kyte
February 12, 2005 - 5:20 pm UTC

a constraint?


but yes, you can take the row wait obj# to all objects

as for your last two replies

max, February 12, 2005 - 7:21 pm UTC

hi tom,

as for "constraint": i 've read that v$session.row_wait_obj# is valid only if those conditions are met. is that true?

and YES, i know, there are always dates and releases associated to threads on *YOUR* site (one reason to prefer it). but sometimes i just use some other internet sources too ;o)

thank you for explaining v$lock a little bit more. i think its column named "block" is a quite good example of what i wanted to say. for this column i can only take "the lock is blocking another lock" as comment from documentation. but from that the "1" you 've used to query v$lock is really not obvious (to me). it 's very much the same with v$lock.id1/2 -- just explained as "lock identifier #1/2 (depends on type)" -- you 've used to self join ...

one of my favourite samples is the comment on dba_dml_locks.last_convert: "the last convert" (whatever that means) :o(

so i have been (very) curious to know whether you have any meta model documenting the relationships between dictionary views as well as their contents in *more* detail. maybe i 've just missed such part (of great help) in documentation. did i?

meanwhile i've tested your query and found something interesting but once again not clear to me.

could you please have a look at the following two test cases?

1st test case:
--------------
1st session: select single row for update
2nd session: attempt to select the same row for update (blocked)
3rd session: attempt lock table (blocked)

after that sequence your query gives:

2nd blocked by 1st
3rd blocked by 1st
3rd blocked by 2nd

and after releasing 1st only one entry remains: 3rd blocked by 2nd (which is what i expected).

2nd test case:
--------------
1st session: lock table
2nd session: attempt to select single row for update (blocked)
3rd session: attempt to select the same row for update (blocked)

here your query only generates:

2nd blocked by 1st
3rd blocked by 1st

as apposed two the 1st test case there is NO entry showing 3rd session to be blocked by the 2nd session.
but after releasing the lock held by the 1st session such a new entry pops up: 3rd blocked by 2nd.

i 've inspected some other dictionary views to find out, whether the 3rd session is really not blocked by the 2nd session until the 1st session releases its lock.
is it or is that a problem of the query i used?

Tom Kyte
February 13, 2005 - 9:08 am UTC

that is a predicate, the use of constraint confused me. yes, you need an active session with a positive obj# in there.

I use the same details as you -- i have access only to the same resources as you really (metalink, the docs). I do have access to other "people" perhaps via email lists but that is about it. I do not read the source code at night.


in your 2cd example, one of the two sessions will only become blocked by the other when they realize they want the same row(s). It is not known yet, they haven't started reading data -- they are blocked by that table lock.

thank you for sharing your knowledge ...

max, February 13, 2005 - 10:45 am UTC


Update record generate deadlocks

Roland, February 14, 2005 - 8:43 am UTC

It seems like

update table
set row = record;

updates the key and generate deadlocks, so if you dont use fk-index on all of the fk, dont use the update row.

Simple to code, and it happend to me.

Tom Kyte
February 14, 2005 - 9:07 am UTC

well, you are updating the parent primary key using that. and that (along with delete from parent) are the triggers for locking a child table that has an unindexed foreigh key.

you can use

update ( select c1, c2, c3, c4, c5, c6
from table
where primary_key = P_KEY )
set row = record;

if you have a record that has just the columns you actually want to update in it

(i'm not a big fan of the "set row=record" syntax personally, see also
</code> https://www.oracle.com/technetwork/issue-archive/2013/13-jul/o43asktom-1958803.html <code>
Insert and Update from a Record

Questions on Trigger

sam, February 14, 2005 - 10:36 am UTC

Tom,

Thanks for replying back.
Sorry for late reply from my side.

"" whats the goal here, what are you trying to accomplish -- maybe I can suggest
something given the problem description.
""

The problem description is as below.

Couple of processing inserting into notfn table.
The table notfn looks like notfn_id , process_id , insert_time etc.

The notfn_id is populated with a sequence.

One more process reads from the notfn table and process the rows based on notfn_id.

The problem is we need to process in order of commit of record, not by notfn_id which could be not in order depending on the sequence of events. So time or the correct order that the record was inserted in the notfn determines the processing. The commit is part of insert transaction which have lot of business logic.

Waiting for your reply.

sam

Tom Kyte
February 14, 2005 - 1:31 pm UTC

why not use a queue then? if you need to process something first in, first out, you just described "a queue"?

select for update, where condition no index

A reader, February 14, 2005 - 2:28 pm UTC

Tom,
When I run the SQL below, will the whole table be locked if there is no index on the column col2?
SELECT COL1 FROM TABLE1 WHERE COL2 = 'A' for update;

Thank you

Tom Kyte
February 14, 2005 - 5:44 pm UTC

just where col2 = 'A' -- those are the only rows you are asking for.

no such thing as lock escalation in Oracle.

Questions on Trigger

sam, February 14, 2005 - 3:36 pm UTC

Tom,

Thanks for replying back.

Are you referring to DBMS_JOB ?? when you referencing as queue ?
I don't think dbms_job will be well received in my group.

Is there any other solution other than using dbms_jobs ??

Sam


Tom Kyte
February 14, 2005 - 5:59 pm UTC

advanced queues, a queueing mechanism, messages.


why do you need them in "commit" order -- you are not writing your own replication are you????

Questions on Trigger

sam, February 14, 2005 - 6:15 pm UTC

It's not replication but sort of messaging implemented in Java.

The ordering is not so important , but the way a process which processes rows in the queue keeps track is by notfn_id. So for last run last processed notfn_id = 50 , the process which reads the table queries for notfn_id > 50. Since all the processed are not marked as processed.

So order in which rows are committed is important.

Now one obvious question is why not mark rows as processed ? It little lengthy to answer.

So I need some kind of ordering to keep track of my last processed notfn_id.



Tom Kyte
February 14, 2005 - 6:52 pm UTC

tell them to use jms on top of AQ

then they can still be "java cool" with JMS but use the database to actually do stuff for them (without them knowing about it)



strange things happened when I tried your sql

James Su, February 16, 2005 - 2:40 pm UTC

hello Tom,

When I tried to join v$lock and v$session, it was blocked:

sys@DEV32> SELECT COUNT(1) FROM V$LOCK A;

COUNT(1)
----------
21

sys@DEV32>
sys@DEV32> SELECT COUNT(1) FROM V$SESSION B;

COUNT(1)
----------
48

sys@DEV32>
sys@DEV32> SELECT COUNT(1) FROM V$LOCK A,V$SESSION B WHERE A.SID=B.SID;

The third select was blocked and never returned. I tried it on three different databases, all of them 9i. Can you tell me why? Thanks.

Tom Kyte
February 16, 2005 - 2:56 pm UTC

yes, sort of. querying v$ tables is like querying a data structure, they are in general "not real tables"

you'll find subquery factoring to be something very useful with. for example. I doubt that query "hung", more likely "you got impatient" with it.


consider:



with a as ( select v$lock.*, rownum r from v$lock ),
b as ( select v$session.*, rownum r from v$session )
SELECT COUNT(*)
FROM A, B
WHERE A.SID=B.SID

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 3 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.01 0.00 0 0 3 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.02 0.01 0 3 3 1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 228

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
17 HASH JOIN
17 VIEW
17 COUNT
17 NESTED LOOPS
17 HASH JOIN
18 VIEW
18 UNION-ALL
18 VIEW
18 UNION-ALL
0 FIXED TABLE FULL X$KDNSSF
18 FIXED TABLE FULL X$KSQEQ
0 FIXED TABLE FULL X$KTADM
0 FIXED TABLE FULL X$KTCXB
60 FIXED TABLE FULL X$KSUSE
17 FIXED TABLE FIXED INDEX X$KSQRS (ind:1)
10 VIEW
10 COUNT
10 FIXED TABLE FULL X$KSUSE



SELECT COUNT(*)
FROM V$LOCK A,V$SESSION B
WHERE A.SID=B.SID

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 6.67 6.55 0 0 15360 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 6.67 6.56 0 0 15360 1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 228

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
17 NESTED LOOPS
5120 MERGE JOIN CARTESIAN
10 NESTED LOOPS
60 FIXED TABLE FULL X$KSUSE
10 FIXED TABLE FIXED INDEX X$KSUSE (ind:1)
5120 BUFFER SORT
512 FIXED TABLE FULL X$KSQRS
17 VIEW
92161 UNION-ALL
92161 VIEW
92161 UNION-ALL
0 FIXED TABLE FULL X$KDNSSF
92161 FIXED TABLE FULL X$KSQEQ
0 FIXED TABLE FULL X$KTADM
0 FIXED TABLE FULL X$KTCXB



Lock by unique constraint

Melinda, February 17, 2005 - 10:13 am UTC

You mention inserts being blocked due to:
o unique/primary key constraints (both inserting same value)
Could you please clarify in more detail how this works internally for unique constraints. I can understand how it knows there is a lock for primary key constraints, as it identifies the row based on the PK columns and sees it is locked by the info stored against it in the block. But, for a unique constraint, it is a different row, so how does it identify/store that this is blocked?

Eg:
create table fdr.locktest (col1 number, col2 number,
CONSTRAINT PK$locktest PRIMARY KEY (col1) using index,
CONSTRAINT UK$locktest unique (col2) using index);

session 1 does:
insert into locktest values (1,2);

then session 2 does:
insert into locktest values (2,2);

session 2 is blocked by session 1, but the row itself is different based on the PK. So, apart from the row for (1,2) being marked as locked, where is the lock which tells it that (<any other value,2) is locked?
thanks

Tom Kyte
February 17, 2005 - 1:21 pm UTC

what do you mean "but for a unique constraint it is a different row"?

a primary key is a unique constraint+not null


the rows are different regardless of primary key or not primary key-- they are just "two rows".

forget primary key for a minute, as it is really just

o unique constraint
o not null constraints

not much more, nothing "special" about it.

Unique constraints

Melinda, February 18, 2005 - 6:19 am UTC

I see what you mean. It was confusing me by thinking of PKs and UKs as different things. So, it is just looking for all rows which match any of the unique keys of the row being inserted to see if any of those rows are already locked. thanks - its clear now.

Ratnam, March 03, 2005 - 10:29 am UTC

Hi Tom,
I need your help to design the logic usig locking mechanisam.
My requirement.
I have 2 processes which are using the same staging table for transformation. These 2 process will start in 2 diffrent times.
I have a situation before completing the process1, process2 is getting start and it is cleaning up the staging table and using for its transformation. I am loosing the output in process1.
Please expain me how to come over this.

Thanks in advance.

Ratnam

Tom Kyte
March 03, 2005 - 10:52 am UTC

insufficient details to design a system for you here.

do you want them to

a) work at the same time
b) wait for eachother to finish?

Ratnam, March 04, 2005 - 1:25 am UTC

Hi Tom,
Thanks for your inputs.
I want to run these 2 process in different timings.
Here my requirement is if process 2 starts before completing the process1 how to handle.
I want to make process2 wait until process1 complete if process2 starts before process1 completes.

Thanks
Ratnam


Tom Kyte
March 04, 2005 - 7:59 am UTC


create or replace procedure run_serial( p in varchar2 )
as
l_status number;
begin
l_status := dbms_lock.request
( id => 123, -- use whatever you like,
-- but use the same in both places
lockmode => dbms_lock.x_mode,
release_on_commit => FALSE );
if ( l_status = 0 )
then
do_your_process;
else
raise_application_error( -20000,
'lock request totally failed... ' || l_status );
end if;
l_status := dbms_lock.release( 123 );
exception
when others
then
l_status := dbms_lock.release( 123 );
raise;
end;
/


you must have DIRECT access to dbms_lock granted to you -- but you could use any serialization technique, like a one row table:

create table run_one_at_a_time( x int );
insert into run_one_at_a_time values ( 1 );


and your code would:


select * from run_one_at_a_time FOR UPDATE;
run your process, using an autonomous transaction if it commits
commit;



what if we have another process say , process3

pasko, March 04, 2005 - 10:13 am UTC

Hi Tom,

Great Technique for serial process Execution.

what if i have a third process , say process3 which should run after process2 completes ?

Thanks in advance.

Tom Kyte
March 04, 2005 - 10:59 am UTC

use same technique? insufficient data to say anything more. for example, can process3 run simply if process2 is not running (if it must run after, seems last step of process2 is to run process3)

process1->process2->process3

pasko, March 04, 2005 - 12:44 pm UTC

Hi Tom,

thanks for your Follow-up

i was thinking how could i use the above Technique to control serial Process Execution in this particular order, always:

process1->process2->process3

without calling any of the processes from another one.

If we use the above Technique ,
process1->process3-process2 sequence could be possible , which in this case should not occur.

I think it could be implemented with AQ , but i was thinking of a non-AQ solution , like the Technique you described above.



Tom Kyte
March 04, 2005 - 1:54 pm UTC

but you are not looking for a "make sure something isn't currently running", you are looking for "run these in order"

that would be AQ, DBMS_JOBS or the scheduler in 10g.

Or, just have process 1 invoke 2 which invokes 3.

Space Manamgement Issues in Oracle

Vidya Sagar, March 17, 2005 - 3:48 am UTC

Wed Mar 16 18:53:30 2005
SMON: following errors trapped and ignored:
ORA-01575: timeout waiting for space management resource
===================================================
PROCESS STATE
-------------
Process global information:
process: 88423b70, call: 88445380, xact: 0, curses: 8842de28, usrses: 8842de28
----------------------------------------
SO: 88423b70, type: 1, owner: 0, flag: INIT/-/-/0x00
(process) Oracle pid=6, calls cur/top: 88445380/88445380, flag: (a) SYSTEM
int error: 0, call error: 0, sess error: 0
(latch info) wait_event=0 bits=0
O/S info: user: oracle7, term: ?, ospid: 29871
OSD pid info: pid: 74af, image:
----------------------------------------
SO: 8842de28, type: 3, owner: 88423b70, flag: INIT/-/-/0x00
(session) trans: 0, flag: (51) USR/- BSY/-/-/-/-/-
oct: 0, prv: 0, user: 0/SYS
last wait for 'enqueue' seq=3342 wait_time=201
name|mode=53540006, id1=0, id2=0
----------------------------------------
SO: 88445380, type: 2, owner: 88423b70, flag: INIT/-/-/0x00
(call) sess: cur 8842de28, rec 0, usr 8842de28; depth: 0
===================================================
CURRENT SESSION'S INSTANTIATION STATE
-------------------------------------
current session=8842de28
Wed Mar 16 18:53:47 2005
SMON: following errors trapped and ignored:
ORA-01575: timeout waiting for space management resource

v$lock.BLOCK

Sami, March 20, 2005 - 6:16 pm UTC

Dear Tom, Thanks for all your help in the past.

Env :- Oracle 8.1.7, 2 Node OPS

Questions Regarding v$lock. I looked at 
http://download-west.oracle.com/docs/cd/A87860_01/doc/server.817/a76961/ch380.htm#5397

but still I couldn't understand few things very clearly.

1) Oracle doc says v$lock.block is "The lock is blocking another lock", but

What is the difference between v$lock.block value of 0,1,2.
In my environment I see the value of 2 for all the v$lock records.
 

SQL> l
    1  select * from v$lock
    2* where request >0
  SQL> /
   
  ADDR     KADDR    SID TY ID1 ID2 LMODE REQUEST   CTIME BLOCK
  -------- -------- --- -- --- --- ----- ------- ------- -----
  DFD608C0 DFD608D0 295 PS   1  20     4       6  518376     2
  DFD60600 DFD60610 886 PS   1  13     4       6 1036777     2


2) My system is running fine for a quite long period of time. Why do I see many Media Recovery lock here?

SQL> select * from v$lock;
 
ADDR     KADDR     SID TY ID1 ID2 LMODE REQUES CTIME BLO
-------- -------- ---- -- --- --- ----- -----  ----- ---
DFD61580 DFD61590    4 MR   1   0     4     0   0    2
DFD61540 DFD61550    4 MR   2   0     4     0   0    2
DFD61500 DFD61510    4 MR   3   0     4     0   0    2
DFD614C0 DFD614D0    4 MR   4   0     4     0   0    2
DFD61480 DFD61490    4 MR   5   0     4     0   0    2
DFD61440 DFD61450    4 MR   6   0     4     0   0    2
DFD61400 DFD61410    4 MR   7   0     4     0   0    2
DFD613C0 DFD613D0    4 MR   8   0     4     0   0    2
DFD61380 DFD61390    4 MR   9   0     4     0   0    2
DFD61340 DFD61350    4 MR  10   0     4     0   0    2
DFD61300 DFD61310    4 MR  11   0     4     0   0    2
DFD612C0 DFD612D0    4 MR  12   0     4     0   0    2
DFD61280 DFD61290    4 MR  13   0     4     0   0    2
DFD61240 DFD61250    4 MR  14   0     4     0   0    2
DFD61200 DFD61210    4 MR  15   0     4     0   0    2
DFD611C0 DFD611D0    4 MR  16   0     4     0   0    2
DFD61180 DFD61190    4 MR  17   0     4     0   0    2
DFD61140 DFD61150    4 MR  18   0     4     0   0    2
DFD61100 DFD61110    4 MR  19   0     4     0   0    2
DFD610C0 DFD610D0    4 MR  20   0     4     0   0    2
DFD61080 DFD61090    4 MR  21   0     4     0   0    2
DFD61040 DFD61050    4 RT   1   2     6     0   0    2

 

Tom Kyte
March 20, 2005 - 6:47 pm UTC

In OPS (rac in 9i and above),

0 - no one is blocked by this lock
1 - there are waiters blocked on this lock
2 - this is global enqueue, so we can't tell

in 9ir2 and above, this view is reported to work in a clustered environment as well.

MR locks are normal and always there. The backgrounds have them and they are "normal"

HH

HH, April 06, 2005 - 7:39 am UTC

HI Tom, I have a PLSQL problem:
In one PLSQL procedure I must make DDL operation.
Unfortunately this DDL affect one of tables over that I have a view. This view is the moust used object in all PLSQL packages. All PLSQL packages are invalidate, but packages will auto compile after next call. That's the way it is, but sometimes competitive sessions errors occured: ORA-096xx Can't find object being called.
First my idea is recompile invalidate objects, I try with: execute immediately 'alter package....' occured self deadlock.
Do you have any idea.
Tanks, HH.


Tom Kyte
April 06, 2005 - 9:15 am UTC

why "must" you do this in production

and what version are you using.

HH

HH, April 06, 2005 - 10:03 am UTC

I made merge through dblink and synchronize data of one table.
"must" because after merge I switch table from merge with one of tables of view (these tables have synonyms) I switch synonyms with "CREATE OR REPLACE SYNONYM".... This is the DDL over my view. PLSQL packages are invalidated. In this moment another sessions worked over view with them and began problems.



Tom Kyte
April 06, 2005 - 1:27 pm UTC

in 10g, that'll no longer invalidate.

HH

HH, April 06, 2005 - 10:05 am UTC

I'am sorry my version is 9.2.0.5.0

Select Statement Hangs often

Kumar, April 06, 2005 - 12:40 pm UTC

Hello Tom,

I was reading one of the replies from you about 'select on dictionary tables taking very long' on this topic. I also have a similar issue. Any select statement on few tables takes very long time(hangs)often but the same SQL runs in a second all other times. Please note that it is a simple select statement without any for update clause.

After recyling the database, the select statement runs faster but this situation comes back after couple of days on the same set of tables.

We are using 9i release 2.

Can you please advise how to go about solving this type of issue.

Thanks.



Tom Kyte
April 06, 2005 - 2:16 pm UTC

turn on sql trace and see what you are waiting for.

search this site for 10046 to see many examples

TM Locking

A reader, April 07, 2005 - 5:02 pm UTC

Hi Tom,
I executed a DB procedure in parallel with different arguments. This procedure after preparing the dynamic sql, inserts data in same table. The target table's PK has been disabled, and there is no index, and NO FK. I found that one session acquired TM lock in exclusive mode, and other is waiting. I was under the impression that multiple session inserts (without FK, index, PK) should not produce lock in EXCLUSIVE mode. Please advise.
Regards

Tom Kyte
April 07, 2005 - 5:08 pm UTC

are you doing insert /*+ APPEND */ or just insert?

show us something...

TM Lock

A reader, April 08, 2005 - 7:31 am UTC

Thanks Tom.
Being DW monthly batch process, all insert statements are prepared with /*+ append */
Regards

Tom Kyte
April 08, 2005 - 8:29 am UTC

the only way to do PARALLEL direct path loads is to let Oracle do it.

only one session can append into a table at a time, unless those "sessions" are really parallel query processes managed by Oracle.

Locks with parallel inserts

A reader, April 08, 2005 - 5:25 pm UTC

Tom,
Thanks for your clarification.
Regarding:-
"the only way to do PARALLEL direct path loads is to let Oracle do it". Do you mean under such situations I should remove /*+ APPEND */ hint. As per your book "Effective Oracle by Design", page 410 (table 7-1), append hint gives much better performance than conventional path. So, if I remove /*+ APPEND */, then WhatI need to do (i.e., in oracle init.ora parameters etc.) to let Oracle do it?
btw: I am using Oracle 9.2 on AIX 5.2L.
Regards

Tom Kyte
April 08, 2005 - 6:03 pm UTC

you would use a parallel direct path insert (eg: not do it yourself parallelism, but Oracle parallel DML parallelism)

else they go one by one using append.

removing append will let them process in parallel, but using the conventional path.

How do know?

A reader, April 09, 2005 - 10:20 pm UTC

Hi Tom,
In dynamic sql preparation script, I removed /*+ APPEND */ from INSERT stmnt. I enabled parallel DML in DB procedure, as
EXECUTE IMMEDIATE 'ALTER SESSION ENABLE PARALLEL DML';
I executed DB procedure five times with different argument in parallel through scheduling tool. Now, I can see that there are NO TM locks in exclusive mode. Since I executed procedures in parallel, so I did not put any parallel hint or put table in parallel degree. I read in Oracle DW manual that /*+ APPEND */ hint is optional when parallel DML is enabled. Now, how do I know that data is being inserted in "direct path insert"?
Regards

Tom Kyte
April 10, 2005 - 9:40 am UTC

your choices are

a) one plsql routine running that does PDML (parallel dml) on the table

or

b) do it yourself parallelism that uses conventional path sql.


you cannot have both.

Thanks a lot!

A reader, April 11, 2005 - 6:19 am UTC

Hi Tom,
Thanks.
Your continous and timely help will always keep you on THE top. Who cares about Don! By looking at all this debate, at least I am not going to buy any stuff written by Don!
Regards and All the Best!

Analyze table and Library_cache_lock

John Deek, April 14, 2005 - 5:02 pm UTC

Hello Sns,

There was a posting related to this from "Reviewer: sns from austin,tx"

We are also facing the similar problem. Can you please let me know whether you found the root cause.

Thanks,
John.


Tom Kyte
April 14, 2005 - 5:19 pm UTC

no, they never got back to me. Unless I can understand the sequence of events (something support is pretty good at pulling out), it would be guessing

Analyze table and Library_cache_lock

John Deek, April 15, 2005 - 7:18 pm UTC

Thanks Tom.

Here is the sample of hang analysis output given by the DBA.

==============
HANG ANALYSIS:
==============
Found 122 objects waiting for <cnode/sid/sess_srno/proc_ptr/ospid/wait_event>
<0/154/9535/0xe62cd9f8/25871/library cache lock>
Open chains found:
Chain 1 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<0/53/1665/0xe62d61d0/1209/No Wait>
-- <0/154/9535/0xe62cd9f8/25871/library cache lock>
-- <0/227/14499/0xe62d3488/2578/library cache lock>
-- <0/22/14/0xe62e8aa8/19930/library cache pin>

I have the trace file when this happened again (though not the one correspoinding to the above hang analysis) but when I tried proof read it, I am not sure why it does not give the details.

TKPROF: Release 9.2.0.3.0 - Production on Fri Apr 15 18:32:17 2005

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Trace file: /home/wasuser/dt.txt
Sort options: default

********************************************************************************
count = number of times OCI procedure was executed
cpu = cpu time in seconds executing
elapsed = elapsed time in seconds executing
disk = number of physical reads of buffers from disk
query = number of buffers gotten for consistent read
current = number of buffers gotten in current mode (usually for update)
rows = number of rows processed by the fetch or execute call
********************************************************************************
Trace file: /home/wasuser/dt.txt
Trace file compatibility: 9.00.01
Sort options: default

1 session in tracefile.
0 user SQL statements in trace file.
0 internal SQL statements in trace file.
0 SQL statements in trace file.
0 unique SQL statements in trace file.
47099 lines in trace file.


Here is the first few lines of raw trace file.

/local/apps/oracle/admin/POR_RDD2/udump/por_rdd2_ora_19762.trc
Oracle9i Enterprise Edition Release 9.2.0.3.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production
ORACLE_HOME = /local/apps/oracle/product/9.2.0
System name: SunOS
Node name: cmcpds01
Release: 5.8
Version: Generic_108528-19
Machine: sun4u
Instance name: POR_RDD2
Redo thread mounted by this instance: 1
Oracle process number: 23
Unix process pid: 19762, image: oracle@cmcpds01 (TNS V1-V3)

*** SESSION ID:(172.13803) 2005-04-14 08:41:49.091
*** 2005-04-14 08:41:49.091
ksedmp: internal or fatal error
Current SQL statement for this session:
SELECT TEAM_MEMBER.RESP_NBR AS C_5156,TEAM_MEMBER.FNEN_ID AS C_5155,TEAM_MEMBER.PHONE_NBR AS C_5152,TEAM_MEMBER.MAI_CD AS C_5151,TEAM_MEMBER.AUXILIARY_INFO AS C_5150,GOVT_ISSUED_ID.VERFD_DT AS C_5142,GOVT_ISSUED_ID.VERFD_BY AS C_5141,GOVT_ISSUED_ID.VERIFY_STS AS C_5140,GOVT_ISSUED_ID.EXPIRY_DT AS C_5139,GOVT_ISSUED_ID.EFFECTIVE_DT AS C_5138,GOVT_ISSUED_ID.ISSUE_DT AS C_5137,GOVT_ISSUED_ID.ISSUING_POL_ENTITY AS C_5136,GOVT_ISSUED_ID.ISSUING_REG_BODY_NM AS C_5135,GOVT_ISSUED_ID.GIS_CD AS C_5134,GOVT_ISSUED_ID.GID_CD AS C_5133,GOVT_ISSUED_ID.GOVT_ISSUED_ID AS C_5132,GOVT_ISSUED_ID.CLT_OID AS C_5131,GOVT_ISSUED_ID.OID AS C_5130,GOVT_COMPLIANCE.VERFD_DT AS C_5129,GOVT_COMPLIANCE.VERFD_BY AS C_5128,GOVT_COMPLIANCE.CHGD_DT AS C_5127,GOVT_COMPLIANCE.CHGD_BY AS C_5126,GOVT_COMPLIANCE.VERIFY_STS AS C_5125,GOVT_COMPLIANCE.SND_B_NOTICE_DT AS C_5124,GOVT_COMPLIANCE.EXPIRY_DT AS C_5123,GOVT_COMPLIANCE.FST_B_NOTICE_DT AS C_5122,GOVT_COMPLIANCE.EFFECTIVE_DT AS C_5121,GOVT_COMPLIANCE.C_NOTICE_DT AS C_5120,GOVT_COMPLIANCE.W8_EXPIRY_DT AS C_5119,GOVT_COMPLIANCE.W8_EFFECTIVE_DT AS C_5118,GOVT_COMPLIANCE.WFE_CD AS C_5117,GOVT_COMPLIANCE.WFT_CD AS C_5116,GOVT_COMPLIANCE.W8_PERM_RES_CTRY AS C_5115,GOVT_COMPLIANCE.WTS_CD AS C_5114,GOVT_COMPLIANCE.TIN_CERTIFD_DT AS C_5113,GOVT_COMPLIANCE.WHOLD_CERTIF_NBR AS C_5112,GOVT_COMPLIANCE.GII_OID AS C_5111,GOVT_COMPLIANCE.OID AS C_5110,CLIENT.CONTRA_CUSTOMER_ID AS C_5104,CLIENT.SND_LOCAL_ORG_CODE AS C_5103,CLIENT.PRI_LOCAL_ORG_CODE AS C_5102,CLIENT.LOB_ID AS C_5101,CLIENT.CRS_CD AS C_5100,CLIENT.MOTHER_FULL_NM AS C_5099,CLIENT.FATHER_FULL_NM AS C_5098,CLIENT.CUST_MAIDEN_NM AS C_5097,CLIENT.MTS_CD AS C_5096,CLIENT.FRCH_DEPT_BIRTH AS C_5095,CLIENT.CTRY_OF_BIRTH AS C_5093,CLIENT.DT_OF_BIRTH AS C_5092,CLIENT.JPMC_EMPL_GID AS C_5089,CLIENT.ICT_CD AS C_5088,CLIENT.GENERATION AS C_5087,CLIENT.SUFFIX AS C_5086,CLIENT.PREFIX AS C_5085,CLIENT.PRV_CD AS C_5084,CLIENT.TITLE_DESC AS C_5083,CLIENT.PREFERRED_NM AS C_5082,CLIENT.LAST_NM AS C_5081,CLIENT.MIDDLE_NM AS C_5080,CLIENT.FIRST_NM AS C_5079,CLIENT.BCT_CD AS C_5078,CLIENT.LOCAL_ORG_CODE AS C_5077,CLIENT.INC_CD AS C_5075,CLIENT_TEAM.OID AS C_5266,CLIENT.CGT_CD AS C_5072,CLIENT.LGC_CD AS C_5071,CLIENT_TEAM.CTR_CD AS C_5262,T_ORGANIZATION.ORG_DESC AS C_6216,CLIENT.EQO_CD AS C_5070,CLIENT.NIT_CD AS C_5068,CLIENT.SHORT_NM AS C_5067,CLIENT.LONG_NM AS C_5066,CLIENT.LEGAL_NM AS C_5065,CLIENT.HIGH_SENS_IND AS C_5062,T_ORGANIZATION.ORG_CURSORTCD AS C_6207,T_ORGANIZATION.CO_CD AS C_6206,T_ORGANIZATION.ORG_NO AS C_6205,CLIENT.BRP_CD AS C_5059,CLIENT.CTRY_DOMICILE AS C_5052,CLIENT.CTRY_NATIONALITY AS C_5051,CLIENT.ACTIVE_SINCE_DT AS C_5050,CLIENT.SUBTYPE AS C_5049,CLIENT.CUSTOMER_ID AS C_5048,CLIENT.OID AS C_5047,CLIENT_TEAM.CLT_OID AS C_5215,CLIENT_TEAM.TEM_OID AS C_5214,CLIENT.CC2_CD AS C_6330,CLIENT.CONFIDENTIAL_NM_IND AS C_6329,T_NDS_DESC_CODE.DESC_CODE AS C_5366,T_NDS_DESC_CODE.CLT_OID AS C_5365,T_NDS_DESC_CODE.OID AS C_5364,D_ACCOUNT.APN_CD AS C_5362,D_ACCOUNT.OID AS C_5361,TEAM_MEMBER.CHGD_DT AS C_5166,TEAM_MEMBER.VERFD_DT AS C_5164,TEAM_MEMBER.VERFD_BY AS C_5163,TEAM_MEMBER.VERIFY_STS AS C_5162,TEAM_MEMBER.EXPIRY_DT AS C_5161,TEAM_MEMBER.EFFECTIVE_DT AS C_5160,TEAM_MEMBER.RESP_CREATE_DT AS C_5159,TEAM_MEMBER.TEAM_NBR AS C_5158,TEAM_MEMBER.RESP_NM AS C_5157 FROM TEAM_MEMBER,CLIENT_TEAM,D_ACCOUNT,GOVT_ISSUED_ID,T_ORGANIZATION,CLIENT,T_NDS_DESC_CODE,GOVT_COMPLIANCE WHERE (TEAM_MEMBER.OID = '4812326' ) AND ( CLIENT_TEAM.CTR_CD = 'DATA OWNER' AND TEAM_MEMBER.TMR_CD = 'DATA OWNER' ) AND ( D_ACCOUNT.APN_CD = 'DDA' ) AND ( GOVT_ISSUED_ID.GID_CD = 'SSN_TIN' ) AND ( T_ORGANIZATION.ORG_CORPORATE_VIEW = 'Y' OR T_ORGANIZATION.ORG_CORPORATE_VIEW IS NULL ) AND CLIENT_TEAM.TEM_OID = TEAM_MEMBER.TEM_OID AND CLIENT.OID = GOVT_ISSUED_ID.CLT_OID AND CLIENT.OID = D_ACCOUNT.CLT_OID AND CLIENT.OID = CLIENT_TEAM.CLT_OID AND CLIENT.PRI_LOCAL_ORG_CODE = T_ORGANIZATION.ORG_NO(+) AND CLIENT.OID = T_NDS_DESC_CODE.CLT_OID(+) AND GOVT_ISSUED_ID.OID = GOVT_COMPLIANCE.GII_OID (+) ORDER BY CLIENT.OID
----- Call Stack Trace -----
calling call entry argument values in hex
location type point (? means dubious value)
-------------------- -------- -------------------- ----------------------------
ksedmp()+328 CALL ksedst()+0 00000000B ? 000000000 ?
000000000 ? 00000004A ?

Tom Kyte
April 15, 2005 - 7:26 pm UTC

those are good for support to work with, please work this with support.

column level locking ?

Matthias Rogel, April 26, 2005 - 3:59 am UTC

five stars for the thread

I never understood the "for update" clause correct.

What is it for ?

I always thought (hoped), it was supplied to support column-level-locking sometimes,
so that Session 1 could safely update columns a,b,c,...
without getting in trouble with Session 2 updating columns x,y,z simolutanleously

however - doesn't seem to work in 9.2

create table temp(a number, b number);
insert into temp (a,b) values(1,2);
commit;

declare
cursor c is select * from temp for update of a;
procedure lock_col_b is
pragma autonomous_transaction;
cursor d is select * from temp for update of b nowait;
begin
open d;
rollback;
end;
begin
open c;
lock_col_b;
end;
/

still gives a
declare
*
FEHLER in Zeile 1:
ORA-00054: resource busy and acquire with NOWAIT specified
ORA-06512: at line 5
ORA-06512: at line 7
ORA-06512: at line 12


are there any plans to change this ?

is there any difference between
cursor c is select * from temp for update of a;
and
cursor c is select * from temp for update;
at all ?

Tom Kyte
April 26, 2005 - 7:30 am UTC

we have row locking only -- there is no concept of column level locking.

You can achieve that with optimistic concurrency control. You don't lock until you are ready to update. You would use a checksum or hash of the data.

Say you had a table with a primary key PK:

create table t ( pk, a, b, c, d, e, f );


You wanted to update a,b,c in one form, they want to update d, e, f in another.


You read out pk, a, b, c and compute a checksum/hash of pk+a+b+c. They do the same for pk+d+e+f.

When you goto update you would:

select pk, a, b, c from t where pk = :x for update;
compute checksum/hash and verify it is the same as before
if ( same )
then
update
else
raise failure
end;


and commit/rollback. They do the same. The lock is taken for a second during the for update/update and released immediately.



no star for my question

Matthias Rogel, April 26, 2005 - 4:01 am UTC

sorry, of course I know when to use
for update
and what is it for.

Just want to know the answer to the last questions

Thanx

Tom Kyte
April 26, 2005 - 7:35 am UTC

for update of a can be used to tell oracle which table you intend to update (and hence it should lock)


ops$tkyte@ORA9IR2> create table t1( x int primary key);
 
Table created.
 
ops$tkyte@ORA9IR2> create table t2 ( a int primary key references t1, b int );
 
Table created.
 
ops$tkyte@ORA9IR2> insert into t1 values (1);
 
1 row created.
 
ops$tkyte@ORA9IR2> insert into t2 values (1,1);
 
1 row created.
 
ops$tkyte@ORA9IR2> commit;
 
Commit complete.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select object_name, object_id from user_objects where object_name in ('T1','T2');
 
OBJECT_NAME                     OBJECT_ID
------------------------------ ----------
T2                                  40656
T1                                  40654
 
ops$tkyte@ORA9IR2> begin
  2     for x in ( select x,a,b from t1, t2 where t1.x = t2.a for update of A )
  3     loop
  4         null;
  5          end loop;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2> select type, id1, (select object_name from user_objects where object_id = id1) oname
  2  from v$lock where sid = (select sid from v$mystat where rownum=1);
 
TY        ID1 ONAME
-- ---------- -----
TX     655386
TM      40656 T2
 
ops$tkyte@ORA9IR2> commit;
 
Commit complete.
 
ops$tkyte@ORA9IR2> begin
  2     for x in ( select x,a,b from t1, t2 where t1.x = t2.a for update of X )
  3     loop
  4         null;
  5          end loop;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2> select type, id1, (select object_name from user_objects where object_id = id1) oname
  2  from v$lock where sid = (select sid from v$mystat where rownum=1);
 
TY        ID1 ONAME
-- ---------- -----
TX    1179681
TM      40654 T1
 
ops$tkyte@ORA9IR2> commit;
 
Commit complete.



<b>the lock is on T1 or T2 depending on which column we say 'for update of'</b>
 

*****

Matthias Rogel, April 26, 2005 - 8:54 am UTC

so

cursor c is select * from temp for update of a;

cursor c is select * from temp for update;

are the same

Tom Kyte
April 26, 2005 - 9:01 am UTC

given a single table like that, yes.

RE : Pls clarify

A reader, July 20, 2005 - 10:02 am UTC

Hi Tom,

I read the discussion regarding 'Locking and Concurrency' in your book Expert-One-on-One Oracle and here are my questions for which your feedback will be really helpful to confirm my understanding.

1. In that discussion, you mentioned that Oracle does not maintain a list of rows that have been locked, but the locking info. is stored as an attribute of data (in the form of ITL maintained in the data block header containing the locked row). Is my understanding correct?
2. The size of ITL entries is controlled by the two block storage parameters INITRANS and MAXTRANS
3. I have two transactions T1 and T2 executing an update on table T whose rows are in block B1.
Scenario 1
==========
Transaction T1 is updating row R1 in table T and
transaction T2 is updating row R2 in table T.

Scenario 2
==========
Transaction T1 is updating row R1 in table T at time t1
Transaction T2 is also updating row R1 in table T at
time t2 and transaction T1 is still active and not
committed

Here is my question :
a. Now the block B1 holding R1 and R2 will have two ITL
entries containing the transaction ids for T1 and T2
scenario 1. Right?. If not pls. explain

The following scenario below is where I am having
confusion.

b. In the first case, the two transactions can run
simultaneously without an enqueue lock.
In the second case T2 gets blocked and waits for T1
to complete.
The ITL entry in the block header only specifies that
a row in that block has been locked. How and where
does Oracle maintain the information that row R1 in T
has been blocked by T1 so T2 should wait as opposed
to the first case where T1 and T2 can proceed
independently since they are blocking different rows
in the same block. ie. How does Oracle make that
distinction based on the ITL entry

4. Is the algorithm in both scenarios on the following lines of pseudo-code before locking the row(s) :

Obtain the block address containing the row(s)
Identify the ITL entries in the block header
For each ITL entry
Loop
Check if the transaction id for the ITL entry is
active
If active
Then
Identify the rows that are affected by the
transaction.
(If any rows required by the new transaction
have already been locked by the active
transaction)
Then
Place the session requesting the lock into
the queue to be notified later (V$lock)
Else
Obtain the lock on these rows so other
sessions know and proceed with the
transaction
End If
Else
Put an entry in the ITL table with this
transaction id. Also mark the row(s) affected by
this transaction as being locked so that other
transactions trying to lock this row should wait
End If
End Loop;

Your feedback in this regard will be really helpful to confirm my understanding

Tom Kyte
July 20, 2005 - 12:55 pm UTC

1) yes
2) yes, in 9i, in 10g and above only initrans counts, maxtrans is ignored
3) a) two transactions -> two, yes.
b) the transaction stuff points to the rbs and the rbs knows who owns what
transaction stuff.

4) why not just simplify to "goto row, see if locked, if not, lock it - else wait on person who has it locked"

that is how I think about it.

Pls Help

A reader, July 20, 2005 - 1:22 pm UTC

Tom,

I have a question on a transaction locking multiple rows. When a single transaction locks multiple rows,
a. Will the ITL contain one single entry for the transaction id and a flag indicating that the row has been locked (or)
b. Will the ITL contain multiple entries with the same transaction id for each row locked.
My understanding is that only (a) will be true. But in one of the article I read "Interested Transaction Lists (ITL) Waits Demystified" by Arup Nanda, I see the following statement.
....
When a row in the block is locked for the first time, the transaction places a lock in one of the slots with the rowid of the row that is has locked.
When the same transaction or another one locks another row, the information is stored in another slot and so on and so forth.
.......

My understanding is that there will be only 1 row in the ITL entry even when the same transaction locks another row. However, Oracle maintains a flag in the row directory indicating if the row is locked or not. Please clarify if my understanding is not correct.

Tom Kyte
July 21, 2005 - 3:54 pm UTC

simple test (in 9ir2).

load up a block with N rows
set maxtrans to N-1
update all of the rows.

does it fail?


or, set maxtrans to two. VERIFY using three sessions that it is two (session 1 updates row 1, session 2 row 2, session 3 gets blocked on row 3 update...)

then start over and have session 1 update rows 1 and 2... can session 2 get row three?



with maxtrans = 2, two TRANSACTIONS are permitted (9i and before, 10g maxtrans is 255 regardless)

Q from expert one-on-one

Menon, July 31, 2005 - 1:12 pm UTC

From my (well worn out!;)) expert one-on-one, Wrox edition, page 103:
I quote
"You should never escalate lock..."

What I understand is this:
Even if you are locking all rows of a table, you really
dont need to escalate a lock to table level in Oracle
since there is no material overhead in maintaining locks.
From the number of locks point of view you dont
save anything from reducing the number of locks
from 10000 (for a 10000 row table) to 1 because
of this. In other databases, since locks are
scarce resources, it makes sense to lock the table
once you hit a threshold % age of rows - hence the
lock escalation.

Is there anything else you want add to the above?

Also, do you know of any current non-Oracle databases
that where locking does not incur signficant overhead?

Thank you!

Tom Kyte
July 31, 2005 - 1:41 pm UTC

see
</code> http://asktom.oracle.com/~tkyte/wc.html <code>

for why a large batch update of most/all of the rows in a table might think about locking the table before it begins (if you know you will locking most/all of the rows, you can prevent your self from getting blocked or restarting if others are simultaneously trying to update single rows in there as well)

thanx...

Menon, July 31, 2005 - 1:46 pm UTC

I have read that very informative thread before.
Barring the
case of large number of rows, was my understanding
of what you meant in the book correct? That is
in general, no need to escalate locks since
locks are not scarce resource and hence you wont save
anything by reducing the number of locks (from 10000
row-level to 1 table-level)


Tom Kyte
July 31, 2005 - 1:58 pm UTC

correct

Thanx!

Menon, July 31, 2005 - 2:03 pm UTC


What is "CI Exclusive" lock?

Peter Tran, August 30, 2005 - 9:46 pm UTC

Hi Tom,

We're having performance problem with dropping tables. I ran a test on this database creating a simple table and immediately dropping it.

ptran@OGRE> create table t (i int);

Table created.

Elapsed: 00:00:00.18
ptran@OGRE> drop table t;

Table dropped.

Elapsed: 00:00:32.07

When I trace the file I find:

drop table t


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.02 23.90 0 10 9 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.02 23.90 0 10 9 0

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 49

Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
enqueue 6 2.99 15.34
rdbms ipc reply 5 1.99 8.53
log file sync 1 0.16 0.16
SQL*Net message to client 1 0.00 0.00
SQL*Net message from client 1 0.04 0.04

With the raw trace file:

WAIT #3: nam='enqueue' ela= 2997924 p1=1128857606 p2=1 p3=5
WAIT #3: nam='enqueue' ela= 2997586 p1=1128857606 p2=1 p3=5
WAIT #3: nam='enqueue' ela= 2997492 p1=1128857606 p2=1 p3=5
WAIT #3: nam='enqueue' ela= 2997594 p1=1128857606 p2=1 p3=5
WAIT #3: nam='enqueue' ela= 2997496 p1=1128857606 p2=1 p3=5
WAIT #3: nam='enqueue' ela= 352702 p1=1128857606 p2=1 p3=5
WAIT #3: nam='rdbms ipc reply' ela= 1991462 p1=5 p2=21474836 p3=0
WAIT #3: nam='rdbms ipc reply' ela= 1991825 p1=5 p2=21474834 p3=0
WAIT #3: nam='rdbms ipc reply' ela= 1991748 p1=5 p2=21474832 p3=0
WAIT #3: nam='rdbms ipc reply' ela= 1991771 p1=5 p2=21474830 p3=0
WAIT #3: nam='rdbms ipc reply' ela= 564743 p1=5 p2=21474828 p3=0

Using your enqueue_decode decode function, I get:

ptran@OGRE> select enqueue_decode(1128857606) from dual;

ENQUEUE_DECODE(1128857606)
----------------------------------------------------------
CI Exclusive

1) What's CI Exclusive?
2) Why is the enqueue so high on a drop table?

Thanks,
-Peter

Tom Kyte
August 31, 2005 - 1:09 pm UTC

it is waiting for the checkpoint of the blocks owned by this table to complete (thats the CI enqueue - checkpoint).

We have to checkpoint the blocks before we drop to make the drop "safe" in the event of a crash.

You are seeing the checkpoint taking place here.

weired situation (library cache lock),

sns, September 02, 2005 - 7:54 am UTC

We have a query that joins on 5 different tables (couple of them are on different schemas). When we try to execute the query the session freezes and even when we try to explain plan the query, its gone.

However, when we try to do a count(*) on each table it works fine.

We tried to do a explain on two tables-->worked fine, three tables --> worked fine, four tables --> worked fine and 5 tables--> freezes.

We created a temp table and used instead of the 5th one. It worked fine.

We tried to trace the session by running the query, the session freezed as well as the trace file did not grow even for an hour and later we had to kill the session.

I have the information of that particular SID:
Oracle User sid-serial CMD TAB_NAME WAIT_EVENT WAIT_TIME STATE
--------------- ------------- -------- ------------------------- ------------------------- --------- ----------
ROLLUP_FIN_EUR 623-69 SELECT FIR.CHANNELS library cache lock -1 WAITED SHO
RT TIME

ROLLUP_FIN_EUR 623-69 SELECT FIR.ORDER_HEADER_CAN library cache lock -1 WAITED SHO
RT TIME

ROLLUP_FIN_EUR 623-69 SELECT FIR.ORDER_SUMMARY_CAN_USD library cache lock -1 WAITED SHO
RT TIME

ROLLUP_FIN_EUR 623-69 SELECT FIR.PRODUCT_HIERARCHIES library cache lock -1 WAITED SHO
RT TIME

ROLLUP_FIN_EUR 623-69 SELECT ROLLUP_FIN_EURO.SQLN_EXPL library cache lock -1 WAITED SHO
AIN_PLAN RT TIME

ROLLUP_FIN_EUR 623-69 SELECT UGCP.GCP_IND_ORD_CAN library cache lock -1 WAITED SHO
RT TIME

Also I have the SQL from v$sqlarea when I tried to do a explain plan.
B1 B2 B3 SQL_TEXT STATUS VERSION_COUNT PARSE_CALLS
------------ ---------- ---------- -------------------------------------------------- -------- ------------- -----------

29083 623 69 explain plan set statement_id = '1' into ROLLUP_FI KILLED 1 0
N_EURO.SQLN_EXPLAIN_PLAN for SELECT /*+ USE_HASH
(oi oh) USE_HASH (ch) USE_HASH (od) USE_HASH (ph)
ORDERED */ oi.resell_group_code, oi.resell_to
p_parent, oi.resell_hierarchy, oh.ACCT_EXEC
, oh.ACTUAL_SHIP_CODE
, oh.ADVERTISEMENT_CODE , o
h.ASSOC_ORDER_NUM , oh.BUSINESS_U
NIT_ID , oh.CANCEL_CODE
, oh.COLLECTION_SITE_CODE ,
oh.CONTRACT_CODE , oh.COUNTRY_
CODE , oh.CURRENCY_CODE
, oh.CUSTOMER_NUM ,
oh.DELL_ORDER_TYPE , oh.DELLWA
RE_STATUS , oh.DELLWARE_STATUS_DA
TE , oh.DPS_NUM
, oh.DPS_TYPE , oh.EXTR
ACT_DATE , oh.FISCAL_MONTH
, oh.FISCAL_QUARTER
, oh.FISCAL_WEEK_NUM , oh.FI

I don't know why. Have you seen this before.

the database is 10.0.4.1 and its a 3 node RAC.

Thanks,

Tom Kyte
September 03, 2005 - 7:04 am UTC

please utilize support to diagnose an issue like this.

library cache,

sns, September 03, 2005 - 7:31 am UTC

Oracle support are not very clear about the problem. The TAR is still open.

What I was wondering is have you come across a similar situation before?

Thanks,

Tom Kyte
September 03, 2005 - 9:00 am UTC

Nope, if I had - I would have mentioned it.

Help with hanging query on v$lock with cost based optimizer

Steve, September 17, 2005 - 6:37 pm UTC

We're trying to debug some deadlocking issues with 10G RAC server, so I ran the first query at the top of this thread. The query hung, and never came back. I recycled the database, so mine was the only session, ran the query again, and it never came back (never = 15 minutes). After a few init.ora mods, I found out that the query would come back immediately when I changed optimizer_mode=RULE, but would hang forever with optimizer_mode=ALL_ROWS or FIRST_ROWS.

Here's the query I ran:

select username,
from v$lock, v$session
where v$lock.sid = v$session.sid

This query never returned, but the following one did (even with the cost based optimizer enabled):

select username,
from v$lock, v$session
where v$lock.sid + 0 = v$session.sid + 0

I did a count(*) on v$lock and v$session, and there were less than 100 rows in each.

After finding the problem, we found that it did not hang on an Oracle 9.0.1 instance, but did hang on our 10.1.0.2 standalone server as well as the 10.1.0.4 RAC server.

I'm sure we can submit a bug for this if needed, but I'm wondering if there is some init.ora parameter that might be causing this. Our instance is using the standard out of the box init.ora parameters.


Tom Kyte
September 17, 2005 - 11:49 pm UTC

it would have eventually returned.

What I've been doing with v$ tables has been:

with lock as ( select v$lock.*, rownum r from v$lock ),
sess as ( select v$sess.*, rownum r from v$session )
select ........


to "copy" them out (they are not read consistent anyway, very expensive to query - lots of latching, this can make a huge difference)



follow up on hanging query

Steve, September 18, 2005 - 12:09 am UTC

Thanks for the quick response. But I'm a little confused. You say it would have eventually returned. I'm having trouble figuring out any explanation for how a join of two v$ tables with < 100 rows each can take over 15 minutes to return on a dual processor Sun v480 with the cost base optimizer turned on and can return instantly with the rule based optimizer on. In both cases the machine was completely idle except for Oracle, which had just been restarted with a single user connection established.

Perhaps there are some latching initialization parameters that we have set too low that would cause it to hang?

Any ideas of what we could look into?

Tom Kyte
September 18, 2005 - 12:39 am UTC

different plans -- did you compare them.



One final question on the hanging query

Steve, September 18, 2005 - 1:03 am UTC

They definiteley have different execution plans, but I'm still not seeing any execution plan that could result in that kind of time being used. I think there were 25 rows in v$session and less than 60 rows in v$lock, So, the max rows returned in a cartesian product would by 1500 rows. In reality, the query only returns about 10 rows. let me ask it this way:

Does it take over 15 minutes when you run the query on any 10G instance that you have access to? Is it normal for a join of 2 tiny tables to take 15 minutes to execute, or does it sound like something is wrong?

I've gotten lots of good info from your site, so I'm hoping you can point me to some are to look at for problems.

Tom Kyte
September 18, 2005 - 1:13 am UTC

v$ tables require latched access in most cases

latches are locks
locks are serialization devices

did you have more than one user on this system?

v$lock etc.

Jonathan Lewis, September 18, 2005 - 6:55 am UTC

I'd guess you've got PROCESSES set to a reasonably large value - something in excess of 1000 to get a 15 minutes of CPU burn.

Do an explain plan against your query, and you'll find that it does something pretty horrid - I think a nested loop instantiating a view that is a union all of 4 big x$ that need to be scanned.

"processes" dictates enqueue_resources, dml_locks, transactions - which all go in to that view. It also controls v$session, which is driving the nested loop.

a) Tom's suggestion (inline view with no_merge, or subquery factoring) eliminates the nested loop
b) have you collected typical stats on the x$ - you can do this in 10g with dbms_stats.gather_fixed_objects_stats (it may take a few minutes). Once the optimizer has a good idea of the size of your x$, it will probably do something smart without using Tom's trick.

General warning - do NOT run queries against production systems that have large values for processes/sessions until you have tested them on a development system with a similar number of active processes/sessions




Hanging v$lock query

Steve, September 18, 2005 - 10:20 am UTC

Jonathan, thanks for the response. We have processes set to 200, and sessions set to 500. I can run the query and have it hang right after starting the database, when I'm the only user using it. It is a test machine, and nothing else is going on on that machine at the time either. At startup, there are only about 26 processes and sessions.

I'll run the dbms_stats.gather_fixed_objects_stats procedure to see if that makes a difference.

Tom Kyte
September 18, 2005 - 11:31 am UTC

(i would still rewrite the query, try to get a snapshot of the v$ views and then query that)

v$ and x$

Jonathan Lewis, September 18, 2005 - 11:25 am UTC

I'm a little surprised that your timings are so bad with relatively low values. I'll have to try some smaller values on my machine. Check also:
transactions
enqueue_resources
dml_locks

Bear in mind, some v$ queries have to walk the X$ - so the number of rows in v$transaction (for example) is irrelevant, it's the number of slots in x$ktcxb that would cause the effect.


Timings

Jonathan Lewis, September 19, 2005 - 7:13 am UTC

I've just run the query (with no stats) with your settings for processes (200) and sessions (500), and on my laptop with a 2.8 GHz CPU, and immediately after startup, it took 5 minutes 31 seconds to complete.

Running a trace against it, the 'obvious' problem is that v$session in 10g includes a join to the X$ sitting under v$event_name. This multiplies up the number of times a bad plan does a nested loop view instantiation. So the creation of the thing that is (approximately) v$lock happened over 43,000 times on my system.

I forgot to mention one of the things derived from processes (or sessions if you've set it manually - it defaults to something like processes + 10%)and that was the enqueue_locks, which is even bigger than the enqueue_resources. Check v$resource_limit to see the max values you've implicitly allowed for enqueue_resources and enqueue_locks - they are probably in the thousands.

If you don't mind the curiosity: why do you have sessions so much larger than processes; are you running a lot of sessions through shared servers, or are you doing connection pooling and n-tier authentication properly.


Timings

Steve, September 19, 2005 - 5:11 pm UTC

Jonathan, Thanks again for the response. I'm not sure why sessions was set higher than processes, as I just came in to help out a friend who was having Oracle problems. I used to know alot about Oracle, but now I know a little.

I think they used to have shared servers turned on, but that was one of the first things we turned off. Connection pooling is already being done in the application server. I think we'll remove the session parameter from sga and let it get set automatically based on processes.

Enqueue_Resources and enqueue_locks were in the thousands (3-4K, as I recall). Should we stick with the implicit values or explicitly change them?

Also, they had sga_target and sga_max set to 3GB. I saw some articles that recommended turning off automatic memory management, so I turned set sga_target=0. Is that the right thing to do?

thanks.

session locking

Vivek, October 02, 2005 - 5:06 pm UTC

Tom,

I am having session locking issues in my application, i had set up an event alert (user block) in OEM , it does tell me which session is holding the other sessions and via fixit job i am getting the session waiting and the sql waiting. What i want to know, is it possible to find what sql was executing at blocker session when the 'user block' event fired up.

Thanks
Vivek

Tom Kyte
October 02, 2005 - 5:40 pm UTC

it isn't really relevant - the sql the blocking session executed probably happened WELL BEFORE it actually blocked anyone.

You want to know the objects it has that are being used to block others and that information is in v$lock.

Undo FOR UPDATE NO WAIT

Thiru, October 14, 2005 - 3:11 pm UTC

Tom,

I have the following statements in my session:

update emp set empname='xyz' where empno=100;
...and other dml statements.
and then.
select * from dept where deptno=10 for update nowait;

I do have some more dml after this that I need to do. How do I undo the update nowait statement so that other sessions could go ahead and lock that row?

I thought of only a commit or a rollback. But is there any other way?

Thanks again.

Tom Kyte
October 14, 2005 - 5:56 pm UTC

commit or rollback - that is it.

why do you need to lock the row? if you *need* to lock it - how could you just "give it up" again without being finished?

A reader, October 16, 2005 - 5:15 pm UTC

Why do we see ITL waits on the index block during inserts to the table? Shouldnt we be seeing those kind of waits only during updates/deletes?

Tom Kyte
October 16, 2005 - 5:37 pm UTC

an insert is just like an update or delete is to an index. In an index - the data has a "place" where it needs to go. if 500 people all insert the letter "A" into an indexed column - they will all goto the same block(s) in the index.

you may need to set initrans higher for this index in the future.

A reader, October 16, 2005 - 9:55 pm UTC

Why do we see ITL and row lock waits without any activity on the blocks(inserts/deletes/updates)?

SQL>  create table t ( x char(255), y char(255), z char(255) );

Table created

SQL> create index t_idx1 on t(x);

Index created

SQL> 
SQL> create index t_idx2 on t(y);

Index created

SQL> create index t_idx3 on t(z);

Index created

SQL> break on obj skip 1
SQL> 
SQL> select (select object_type || '.' || object_name
  2              from dba_objects
  3                     where object_id = obj#) obj, statistic_name, value
  4      from v$segstat
  5     where obj# in ( select object_id from user_objects where object_name like 'T%' )
  6         and value > 0
  7       order by 1
  8  /

OBJ                                                                              STATISTIC_NAME                                                        VALUE
-------------------------------------------------------------------------------- ---------------------------------------------------------------- ----------
INDEX.T_IDX2                                                                     logical reads                                                            96
INDEX.T_IDX2                                                                     db block changes                                                         48
INDEX.T_IDX2                                                                     row lock waits                                                            2
INDEX.T_IDX2                                                                     physical reads                                                            3
INDEX.T_IDX2                                                                     ITL waits                                                                 6
INDEX.T_IDX3                                                                     logical reads                                                           144
INDEX.T_IDX3                                                                     physical reads                                                           12
INDEX.T_IDX3                                                                     physical writes                                                           6
INDEX.T_IDX3                                                                     db block changes                                                         16
TABLE.T                                                                          logical reads                                                           192
TABLE.T                                                                          db block changes                                                         48
TABLE.T                                                                          physical reads                                                           13
TABLE.T                                                                          physical writes                                                           6

13 rows selected

SQL>  

Tom Kyte
October 17, 2005 - 7:14 am UTC

I cannot reproduce in 9ir2, 10gr1, 10gr2 - however, if you use DATAOBJ# instead of obj#, can you still reproduce

(no version from you? mine were all of the current production releases..)

A reader, October 18, 2005 - 12:54 pm UTC

Neither could I - I was on 9ir2. Thanks for your help.

Unexpected drop down in performance

Praveen, October 19, 2005 - 9:32 am UTC

Tom,

I created a new package that perform a data loading operation from a few old tables (1 million+ records) into a new set of tables (more normalized). I had tested the package for a small set of data of about 6000 records and was loading data at the rate of about 100 records per sec. Now when running the package for a full set of data, although it started running fine at the same speed as mentioned earlier, it gets suddenly slowed down to a horrible rate of 1 record in a few minutes! This happens after about 10% of total data loading is completed. Initially I thought it could be because of some other process is going on parallely in the system, that assumption is ruled out soon as this is the only one process running. I went through the code looking for any resource leakage possiblities or locking issues that might arise, but could find nothing since most of the transactions are staright forward and not much complexities involved in it.

The things I have taken cared for are;

1) all the open cursors, ref cursors are closed
2) arrays are deleted when finished with
3) bind variables are in place
4) sqls when executed individually are giving a good response time.
5) indexes are at the proper places etc.

I strongly believe, that the only thing that causes the problem is the application is waiting for some sort of locks. But how to find it out!? Where & when?

Could you please tell me a few things about:

1) How you would approach (diagonising) such a situation?
2) What are the possible bottleneck points that you would look into (and taken care of) during a huge data loading operation like this?
3) How to discover them- at runtime - (I means when the performans drops down mid-way) ?
4) What are the tools that may come to one's help.

Your answer is most apreciated

Regards
Praveen

Tom Kyte
October 19, 2005 - 9:49 am UTC

I would trace it against the full load of data. stop it now. turn on sql_trace, run it, stop it.

then review that tkprof against a tkprof from when the tables were "empty" (remember OPTIMIZER THINKS TABLES ARE EMPTY - that is sort of "key" and could be a big part of the problem - a query that works great with 0 records starts to work "not so great" with 1000 records and so on)

Deadlock on undo segment???

Oren Nakdimon, October 19, 2005 - 11:07 am UTC

Tom, when can an undo segment be a resource involved in a deadlock?

I got a deadlock between a session that does INSERTs into a table and a session that does UPDATEs to the same table.
The "Rows waited on:" were:
Session 160: obj - rowid = 002A97DE - AAKpfeAAUAAAP26AAA
(dictionary objn - 2791390, file - 20, block - 64954, slot - 0)
Session 143: obj - rowid = 00000000 - D/////AAwAAABPEAAA
(dictionary objn - 0, file - 48, block - 5060, slot - 0)

Note that session 143 (that did the UPDATEs) waited for an object with rowid=00000000 in file 48 which belongs to the UNDO tablespace.

Thanks,
Oren.



Tom Kyte
October 19, 2005 - 12:35 pm UTC

show me more of the trace file.

p1/p1text etc for enq: TX - row lock contention

Bipul, October 19, 2005 - 12:22 pm UTC

Hi Tom.

What does the p1,p1text, p2,p2text, p3 and p3text represents for event

"enq: TX - row lock contention"

For example

In the following output from v$session

event -> enq: TX - row lock contention

p1 - 1415053318
p1text - name|mode

p2 - 458759
p2text - usn<<16 |slot

p3 - 570996
p3text - sequence

what does it waiting for ? A sequence? Which sequence?

The rdbms version is 10.1.0.4. I couldn;t find much information in Oracle manual. The performance tuning guide

</code> http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10752/instance_tune.htm#16342 <code>

has some information on this wait event , but doesn't explain the p1, p2 etc.


Thanks
bipul


Tom Kyte
October 19, 2005 - 1:00 pm UTC

metalink Note 34566.1

that describes how to decode these, can you see it?

re: enqueue document

Bipul, October 19, 2005 - 4:42 pm UTC

Yes, I can access it.

Thanks
bipul

Re:Unexpected drop down in performance

Praveen, October 20, 2005 - 2:43 am UTC

But the application just picks data from a set of source tables (which are static) and puts it into a set of new tables. No querying on the destination tables are taking place. All inserts are done with /*+append*/ hint. Hence the optimizer assumption (about table statistics) at the begining of the transaction could be the same at any later point also.

As you said I will have to go through the trace files generated. (I have no idea why it takes so much pain for the DBAs to understand the need of giving access permissions to developers for tuning purposes (atleast)). Meanwhile i take a look into the v$session data as given below.

SELECT ROWNUM, LOCKWAIT, ACTION, CURRENT_QUEUE_DURATION, BLOCKING_SESSION_STATUS, BLOCKING_SESSION, EVENT, P1TEXT, P2TEXT, P3TEXT, WAIT_CLASS, WAIT_TIME, SECONDS_IN_WAIT, STATE FROM v$session WHERE status = 'ACTIVE' AND osuser = 'username';

Output: (The text is formatted)
ROWNUM LOCKWAIT ACTION CURRENT_QUEUE_DURATION BLOCKING_SESSION_STATUS BLOCKING_SESSION EVENT P1TEXT P2TEXT P3TEXT WAIT_CLASS WAIT_TIME SECONDS_IN_WAIT STATE
1 Debug Test Window - Script for p 0 UNKNOWN pipe get handle address buffer length timeout Idle 0 769 WAITING
2 Test Window - Script for procedu 0 NOT IN WAIT db file scattered read file# block# blocks User I/O -1 0 WAITED SHORT TIME
3 SQL Window - New 0 NOT IN WAIT SQL*Net message to client driver id #bytes Network -1 0 WAITED SHORT TIME

The EVENT for the second row shows "db file scattered read" and its corresponding WAIT_CLASS = "User i/o". Does it indicates anything dubious?

Thanks, Tom


Tom Kyte
October 20, 2005 - 8:12 am UTC

I told you what I would do.


(the append is scary to me, sounds like you are doing slow by slow processing, append would be totally inappropriate there).


I can scarcely read the supplied output above.

Stored procedure execution

Girish Kumar, October 20, 2005 - 11:49 pm UTC

How do I know, whether a stored procedure(incase if fired from say VB, JAVA etc) is still runnning or not from SQL Plus??

Tom Kyte
October 21, 2005 - 8:10 am UTC

search this site for showsql, it is a script that shows you what sql other sessions are running (or use any one of a billion tools that do that...)

package source code locked

A reader, December 08, 2005 - 2:16 pm UTC

Tom,
i tried to recompile a package and it hung. and it appeased that the souce code being used. I could not verify the lock on v$locked_object.
How do I look for the info?

Thanks!

Sean

Tom Kyte
December 09, 2005 - 1:16 am UTC

dba_ddl_locks

OK

Kumar, December 14, 2005 - 1:22 am UTC

Hi Tom,
1)what do the lock types in v$lock denote ..
   like " MR,RT,TS,XR"

2)When to go for explicitly locking tables using the command
  SQL> lock table .... in .. mode

Please do reply.
Bye!!

 

Tom Kyte
December 14, 2005 - 8:10 am UTC

1) </code> http://docs.oracle.com/docs/cd/B19306_01/server.102/b14237/enqueues.htm#i855817 <code>

2) when you need or want to serialize access to that table, for example, when you know you will modify most, if not all, of the rows in a table - might as well lock it to prevent other smaller transactions from blocking you (and preventing lost updates). eg: a batch.

Lock timeout in local transaction?

Purushoth, January 04, 2006 - 7:54 pm UTC

Tom,

I have a question about lock timeout in local transaction. How can one specify the max wait time for obtaining lock (not through FOR UPDATE WAIT)?

We have a system (built on J2EE )which is facing lot of performance issues lately. A separate background job updates the tables using serialized isolation level, in the mean time small transactions try to update the table and the DML statements uses optimistic lock resulting in all the java threads trying to update the tables getting blocked.

I understand the design has to be relooked but I hope there is way to get around the problem of waiting for too long to get the lock. I thought about killing sessions by monitoring CTIME in v$lock but this will not be great idea as the JDBC Connection gets killed and application server has to incur the overhead of creating the physical connection.

Is there a simple way to return ORA-00054?

Thanks

Tom Kyte
January 05, 2006 - 9:48 am UTC

you can only do it via the select for update wait <n>


By the way - in optimistic concurrency controls, the applications *should not be getting blocked!!!* unless they have done it wrong. You

a) read data out at time T1. You remember something about the data (the old values you read out, a timestamp on the row, ora_rowscn)

b) at time T2 you decide to update that row. USING THE DATA you remembered in a) you lock the row in question using select for update nowait - if

1) you get the row and the data matches what you remember, you can update
2) you get ora-54 resource busy you tell end user "sorry, looks like you'll
lose, someone else has that row locked"
3) you get zero rows - meaning the data was modified, you tell end user "you
lose"

step 2 can be modified to use WAIT (to block) or WAIT N to block for N
seconds - but that is your choice (oracle forms uses NOWAIT for example)




You need to look at the logic of the application - yes, there is a simple way to return the ora-54 and that is to use the command that returns it...


Thanks

A reader, January 05, 2006 - 2:09 pm UTC

I misused the word "optimistic locking". We do updates just based on primary keys and that's unfortunate.
I wonder if ever Oracle will come up with parameter to set the block wait timeout at session level. Thanks for your response!!

Tom Kyte
January 05, 2006 - 2:30 pm UTC

It is worse than unfortunate, it is called "lost update" - it is a classic, basic database related issue and you would appear to be suffering from it in a huge way.

That is, you have a bug in your developed code, a rather large one.

If you are

a) reading a record out - remembering the primary key
b) letting the end user update it (on screen)
c) letting something else update it
d) then taking the result of B and updating the row again by primary key.....

I ask you - why bother with (c) at all? You just overwrote their changes. Why the heck would you bother with (c) since it gets overwritten with the results of (a) and (b) - without anyone ever trying to reconcile that.

Lost update...

Purushoth, January 05, 2006 - 7:45 pm UTC

Tom, Lost update will be issue only when multiple transaction try to update the same columns without any locking. In my case only one user transaction (with primary key) will be able to update the record. The other update is a concurrent program which runs on the background and update just couple of columns (these columns were not updated by the user transaction). Breaking the contentious table into two will resolve the issue but this involves code change. Once again thanks for the reply! I still hope oracle allows to configure the max wait time for acquiring lock in future release.

Tom Kyte
January 06, 2006 - 1:13 pm UTC

How do you know that? How do you know that the same record is not selected out by two other users?

You still have a bug if you ask me.

Is the following approach is acceptable?

Rustam Kafarov, January 27, 2006 - 8:29 am UTC

Hi. could I use following approach for optimistic blockicking:
1) add column VERSION NUMBER DEFAILT 0 that updated only through trigger before update for ech row where we increase version value like that: :new.version := :old.version + 1;
2) put update statment into procedure that does
begin
select ...
from ...
where ID = :id and
version = :version
for update nowait;
-- check for row count;
if sql%rowcount = 0
then raise_application_error(...);
end if;
do update ...
exception
check for resource busy errorend
end;
3) revoke update <table> from <user>
4) grant execute on <proc> to <user>
That means that table will be updated only via this proc. This proc will avoid to update version column by 2 sessions at same time usign select for update.

What do you thing about this approach with version column?

Tom Kyte
January 27, 2006 - 8:54 am UTC

sounds a lot like this cut and paste from my recent book :)

except for the trigger part.

<quote source=Expert Oracle: Database Architecture>
Optimistic Locking Using a Version Column

This is a simple implementation that involves adding a single column to each database table you wish to protect from lost updates. This column is generally either a NUMBER or DATE/TIMESTAMP column. It is typically maintained via a row trigger on the table, which is responsible for incrementing the NUMBER column or updating the DATE/TIMESTAMP column every time a row is modified.

The application you want to implement optimistic concurrency control would need only to save the value of this additional column, not all of the before images of the other columns. The application would only need to verify that the value of this column in the database at the point when the update is requested matches the value that was initially read out. If these values are the same, then the row has not been updated. 

Let’s look at an implementation of optimistic locking using a copy of the SCOTT.DEPT table. We could use the following Data Definition Language (DDL) to create the table:

ops$tkyte@ORA10G> create table dept
  2  ( deptno     number(2),
  3    dname      varchar2(14),
  4    loc        varchar2(13),
  5    last_mod   timestamp with time zone
  6               default systimestamp
  7               not null,
  8    constraint dept_pk primary key(deptno)
  9  )
 10  /
Table created.

Then we INSERT a copy of the DEPT data into this table:

ops$tkyte@ORA10G> insert into dept( deptno, dname, loc )
  2  select deptno, dname, loc
  3    from scott.dept;
4 rows created.
 
ops$tkyte@ORA10G> commit;
Commit complete.


That code re-creates the DEPT table, but with an additional LAST_MOD column that uses the TIMESTAMP WITH TIME ZONE datatype (available in Oracle9i and above). We have defined this column to be NOT NULL so that it must be populated, and its default value is the current system time.

This TIMESTAMP datatype has the highest precision in Oracle, typically going down to the microsecond (millionth of a second). For an application that involves user think time, this level of precision on the TIMESTAMP is more than sufficient, as it is highly unlikely that the process of the database retrieving a row and a human looking at it, modifying it, and issuing the update back to the database could take place within a fraction of a second. The odds of two people reading and modifying the same row in the same fraction of a second are very small indeed.

Next, we need way of maintaining this value. We have two choices: either the application can maintain the LAST_MOD column by setting its value to to SYSTIMESTAMP  when it updates a record or a trigger/stored procedure can maintain it. Having the application maintain LAST_MOD is definitely more performant than a trigger-based approach, since a trigger will add additional processing on part of Oracle to the modification. However, this does mean that you are relying on all of the applications to maintain LAST_MOD consistently in all places that table is modified . So, if each application is responsible for maintaining this field, it needs to consistently verify that the LAST_MOD column was not changed and set the LAST_MOD column to the current SYSTIMESTAMP. For example, if an application queries the row where DEPTNO=10

ops$tkyte@ORA10G> variable deptno   number
ops$tkyte@ORA10G> variable dname    varchar2(14)
ops$tkyte@ORA10G> variable loc      varchar2(13)
ops$tkyte@ORA10G> variable last_mod varchar2(50)

ops$tkyte@ORA10G> begin
  2      :deptno := 10;
  3      select dname, loc, last_mod
  4        into :dname,:loc,:last_mod
  5        from dept
  6       where deptno = :deptno;
  7  end;
  8  /
PL/SQL procedure successfully completed.

which we can see is currently

ops$tkyte@ORA10G> select :deptno dno, :dname dname, :loc loc, :last_mod lm
  2    from dual;
 
       DNO DNAME      LOC      LM
---------- ---------- -------- -----------------------------------
        10 ACCOUNTING NEW YORK 25-APR-05 10.54.00.493380 AM -04:00 

it would use this next update statement to modify the information . The last line does the very important check to make sure the timestamp has not changed and uses the built-in function TO_TIMESTAMP_TZ (tz is short for time zone ) to convert the string we saved in from the select back into the proper datatype. Additionally, line 3 of the update updates the LAST_MOD column to be the current time if the row is found to be updated:

ops$tkyte@ORA10G> update dept
  2     set dname = initcap(:dname),
  3         last_mod = systimestamp
  4   where deptno = :deptno
  5     and last_mod = to_timestamp_tz(:last_mod);
1 row updated.

As you can see, one row was updated—the row of interest. We updated the row by primary key (DEPTNO) and verified that the LAST_MOD column had not been modified by any other session between the time we read it first and the time we did the update. If we were to try to update that same record again, using the same logic, but without retrieving the new LAST_MOD value, we would observe the following:

ops$tkyte@ORA10G> update dept
  2     set dname = upper(:dname),
  3         last_mod = systimestamp
  4   where deptno = :deptno
  5     and last_mod = to_timestamp_tz(:last_mod);
0 rows updated.

Notice how 0 rows updated is reported this time because the predicate on LAST_MOD was not satisfied. While DEPTNO 10 still exists, the value at the moment we wish to update no longer matches the timestamp value at the moment we queried the row. So, the application knows based on the fact that no rows were modified that the data has been changed in the database—and it must now figure out what it wants to do about that.
<b>
You would not rely on each  application to maintain this field for a number of reasons. For one, it adds code to an application, and it is code that must be repeated and correctly implemented anywhere this table is modified. In a large application, that could be in many places. Furthermore, every application developed in the future must also conform to these rules. There are many chances to “miss” a spot in the application code and not have this field properly used. So, if the application code itself is not to be made responsible for maintaining this LAST_MOD field, then I believe that the application should not be made responsible for checking this LAST_MOD field either (if it can do the check, it can certainly do the update!). So, in this case, I suggest encapsulating the update logic in a stored procedure and not allowing the application to update the table directly at all.</b> If it cannot be trusted to maintain the value in this field, then it cannot be trusted to check it properly either. So, the stored procedure would take as inputs the bind variables we used in the previous updates and do exactly the same update. Upon detecting that zero rows were updated, the stored procedure could raise an exception back to the client to let the client know the update had, in effect, failed.

An alternate implementation uses a trigger to maintain this LAST_MOD field, but for something as simple as this, my recommendation is to avoid the trigger and let the DML take care of it. Triggers introduce a measurable amount of overhead, and in this case they would be unnecessary.
</quote> 

Why not use ORA_ROWSCN ?

Jay, January 27, 2006 - 10:29 am UTC

Wonder why Tom did not suggest (or even mention) the use of ORA_ROWSCN (if using 10g) for optimistic locking instead of re-inventing the wheel with version/date column in the previous post.

Tom Kyte
January 27, 2006 - 11:26 am UTC

I do in the book - the book has a long chapter on this very topic covering the approaches to this from many angles.

ora_rowscn to work typically requires the table to be rebuilt with rowdependencies... it is 10g specific.

And - it was not confirming that what the person suggested was valid (which it is, in fact since the rowscn consumes storage and the timestamp consumes storage and the timestamp conveys ADDITIONAL information - the time of last update - it might be preferable in some cases...)

How to lock child Tables

pasko, January 27, 2006 - 1:33 pm UTC

Hi Tom,

i have your Book and read how you clearly outlined the various Locking Techniques, including the new technique in Oracle 10G.

I am using the Last Modified Timestamp technique to lock rows which are being updated from some WEB Frontend GUI.

It's not very clear to me how would i lock Child Tables, using for example the Timestamp Technique.

For Example taking the Dept/Emp Example, suppose i have a DB Procedure which deletes a certain Department Number from the Department Table.Here i have only the Last Timestamp Value from Table: Dept, and i would like to delete or update all Child Tables having a Foreign-Key to the deleted Department Row.
So, what is the best way to Lock these Children Rows by using only the Timestamp Column from the Parent Table(Dept) ?

I was thinking may be i could use queries of this Form:

Example for an Update on Table Dept:

update dept
last_mod = systimestamp
where deptno = :deptno
and last_mod = to_timestamp_tz(:last_mod);


Update or(Delete) All Child Rows for this deptno in Table: emp , using only the Last_Mod Timestamp from table: dept

update emp
set last_mod = systimestamp ,
comm = :new_commission
where deptno in (
select deptno
from dept
where deptno = :deptno
and last_mod = to_timestamp_tz(:last_mod)
) ;

Is this the correct approach to lock the Child Rows or should i use the for update nowait clause for all child Tables before doing the Update/Delete.

Thanks in advance,

Pasko




Tom Kyte
January 28, 2006 - 12:33 pm UTC

why would you update or lock all of the child records??? for an update to the parent?

Your example isn't about the parent - it updates the child?

not sure what you are doing.

Sorry for not being very clear

pasko, January 28, 2006 - 4:56 pm UTC

Hi Tom,

i would like to cascade update or delete to a Child table whenever i update or delete a Parent Record through the Last Modified Timestamp Technique on Parent.

May be a Delete Example is better in this Case.
If i delete One Record from Parent Table: Dept for deptno x , then delete all Employees with this deptno x from Table emp.


Suppose the GUI Tool calls a Delete Dept Stored Procedure with Signature:

procedure
delete_dept( p_deptno in dept.deptno%type,
p_last_mod in varchar2
--last modified timestamp from Table:dept
);

now inside this Procedure i would like to delete the Record from table: dept and also delete cascade all child Records from Table: emp , using only the last modified Timestamp from the Dept table, because i do not have all the Last Modified Timestamps from the emp Table.





Tom Kyte
January 29, 2006 - 8:16 am UTC

You never update primary keys (else you've done something horribly wrong and need to fix that, you obviously picked the wrong thing as a primary key) so ..... update cascade - no problem, it won't happen.

delete cascade is declaritive. you can create the foreign key that way (delete cascade).

Or if you do it yourself, you just

a) select and lock the parent record verifying that no one has modified it
b) delete children
c) delete parent



Bitmaps block inserts

nairs, February 07, 2006 - 5:43 am UTC

I have a table and a bitmap index on one column (oracle 9i)
creat table t (num int, name char(1));
create bitmap index t_idx on t(name);

If I do an insert from two sessions
insert into t values (1,'a') the second session gets blocked by the first session till the first session is committed. And it shows up in v$lock as a blocking/blocked entry.

If I remove the bitmap index or replace it with B*tree index, I have no problem inserting from multiple sessions.

Could you please throw some light on this behaviour with respect to bitmap indexes?

Thanks.


Tom Kyte
February 07, 2006 - 5:59 am UTC

you will NEVER EVER IN A MILLION YEARS use bitmap indexes in a system where you do single row inserts, updates, deletes - they are appropriate soley in a read only/read mostly (data loads) type of systems.

a bitmap index key entry - by its very design - points to MANY rows. One person at a time may lock an index key entry.

bitmaps are NOT appropriate on tables that are modified in an OLTP fashion. Since each key entry points to many rows (many many rows), they necessarily inhibit scalability, lead to deadlocks and so on.

ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.

Reader, February 14, 2006 - 4:34 pm UTC

ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
ORA-06512: at line 3
ORA-06512: at line 54

In my cursor I have an Order by and use analytical function .
Is it true that I cannot use "Select For Update"
Do I have to lock the table ...

Thanks

Tom Kyte
February 14, 2006 - 4:44 pm UTC

what are you trying to do first.

yes, it is "true" - as the message says.

but tell us, what is your goal/ your logic here.

does "order by" affect locking order of a "for update" clause

Michael, March 27, 2006 - 3:20 am UTC

Hi Tom,

i have a small question about the "for update" clause with "order by". Does the "order by" affect the order in which the rows are locked. I'm getting deadlocks sometimes because two sessions are locking a few equal rows and they seem to lock them in different order. At least that's the only thing why i could get that deadlock. If i could force an order to the locking mechanism, the deadlock wouldn't happen.

Tom Kyte
March 27, 2006 - 9:52 am UTC

not necessarily, unlikely actually.


select a,b from t order by a for update;


that could

a) read every row in T via a full scan
b) then sort




does "order by" affect locking order of a "for update" clause reloaded

Michael, March 27, 2006 - 11:29 am UTC

Thanks for your answer, Tom. Is there a way how i can avoid a deadlock here. I have to lock many rows in a few base tables so dependent data doesn't get updated by other processes in the meanwhile. My code is like this:

for i in (complex query with for update)
loop
--complex update logic here
end loop;

All updates belong to the same transaction, so i have to lock them all at once and can't use autonomous transactions. I tried to select the data in the for loop without for update first and then lock each row by performing an additional "select ...into ... for update", but obviously this was aggravating the problem.
In the long run, we probably have to rethink our whole implementation, although i haven't been able to come up with an alternative yet.
Providing all the details would definately go beyond the scope of this discussion, so i'll spare you with that for now. Any help for the above mentioned problem that doesn't say "rethink your implementation" would be appreciated though. ;)

Tom Kyte
March 27, 2006 - 3:14 pm UTC

unless you can rethink your implementation - only thing I can suggest is "retry some number of times upon deadlock".



a question about oracle lock

gaoyafang, March 29, 2006 - 9:31 am UTC

in a proc*c application,I find a oracle session running a longtime,I trace it,find it when run a sql (select ... from ... where ... for update of ...nowait),resource busy(ora-54) happen.it loop infinitude until lock the rows(this sql execute very quickly,for resource busy,sleep 3 seconds and try again.I have not source code).When I check v$ view to find which session block it,their no lock (because of ora-54,release lock ).How to grasp the lock info (ora-54) and find which session block it in a very very short time?

this sql use 9 bind variables,it hard to run it in sqlplus without nowait to find which blocker.

Tom Kyte
March 29, 2006 - 11:10 am UTC

not sure what you mean here.

You have a pro*c program.

it is doing a select for update.
it for whatever reason goes into an infinite loop (bug in program).

It never really gets truly blocked (nowait).

This pro*c program has a *bug*, it needs to be fixed. It could select for update wait 3 instead of sleeping three and then break out of the loop. At least then it would be blocked and you could see what is actually happening.

right now, "nothing is actually happening" in the database, hard to debug in an environment that is not being used.

why do i receive an "ora-60: deadlock"

A reader, April 03, 2006 - 10:40 am UTC

tom,

could you explain why i'm receiving an "ora-60: deadlock" in the following example if i remove the lock table statement? i always thought another session would just wait!?

--
-- TEST_SUM  (Table) 
--
CREATE TABLE TEST.TEST_SUM
(
  COL1  NUMBER(2)
)
TABLESPACE USERS
PCTUSED    40
PCTFREE    10
INITRANS   10
MAXTRANS   255
STORAGE    (
            INITIAL          64K
            MINEXTENTS       1
            MAXEXTENTS       2147483645
            PCTINCREASE      0
            FREELISTS        1
            FREELIST GROUPS  1
            BUFFER_POOL      DEFAULT
           )
LOGGING 
NOCOMPRESS 
NOCACHE
NOPARALLEL
NOMONITORING;



Insert into TEST.TEST_SUM
   (COL1)
 Values
   (10);
Insert into TEST.TEST_SUM
   (COL1)
 Values
   (10);
Insert into TEST.TEST_SUM
   (COL1)
 Values
   (10);
Insert into TEST.TEST_SUM
   (COL1)
 Values
   (10);
Insert into TEST.TEST_SUM
   (COL1)
 Values
   (10);
COMMIT;


TEST @ adm1 SQL>edit
file afiedt.buf wurde geschrieben

  1  create or replace procedure test_sum_proc as
  2     cursor p_sum is
  3       select sum (col1) summary
  4       from   test_sum
  5       ;
  6     procedure AnotherUserIsUpdating is
  7       pragma autonomous_transaction;
  8     begin
  9       lock table test_sum in share row exclusive mode nowait;
 10       update test_sum set col1 = 100;
 11       commit;
 12     exception
 13       when others then
 14         dbms_output.put_line ('Error: ' || SQLERRM);
 15     end;
 16  begin
 17    lock table test_sum in share row exclusive mode;
 18    for p_s in p_sum loop
 19      dbms_output.put_line ('Summe 1: ' || p_s.summary);
 20    end loop;
 21    AnotherUserIsUpdating;
 22    for p_s in p_sum loop
 23      dbms_output.put_line ('Summe 1: ' || p_s.summary);
 24    end loop;
 25    rollback;
 26* end;
TEST @ adm1 SQL>/

Prozedur wurde erstellt.

Abgelaufen: 00:00:00.06
TEST @ adm1 SQL>exec test_sum_proc;
Summe 1: 50
Error: ORA-00054: resource busy and acquire with NOWAIT specified
Summe 1: 50

PL/SQL-Prozedur erfolgreich abgeschlossen.

Abgelaufen: 00:00:00.02

===
BUT WHEN I REMOVE THE LOCK TABLE STATEMENT ===>>>
===

TEST @ adm1 SQL>edit
file afiedt.buf wurde geschrieben

  1  create or replace procedure test_sum_proc as
  2     cursor p_sum is
  3       select sum (col1) summary
  4       from   test_sum
  5       ;
  6     procedure AnotherUserIsUpdating is
  7       pragma autonomous_transaction;
  8     begin
  9       --REMOVE LOCK TABLE
 10       --lock table test_sum in share row exclusive mode nowait;
 11       update test_sum set col1 = 100;
 12       commit;
 13     exception
 14       when others then
 15         dbms_output.put_line ('Error: ' || SQLERRM);
 16     end;
 17  begin
 18    lock table test_sum in share row exclusive mode;
 19    for p_s in p_sum loop
 20      dbms_output.put_line ('Summe 1: ' || p_s.summary);
 21    end loop;
 22    AnotherUserIsUpdating;
 23    for p_s in p_sum loop
 24      dbms_output.put_line ('Summe 1: ' || p_s.summary);
 25    end loop;
 26    rollback;
 27* end;
TEST @ adm1 SQL>/

Prozedur wurde erstellt.

Abgelaufen: 00:00:00.07
TEST @ adm1 SQL>exec test_sum_proc;
Summe 1: 50
Error: ORA-00060: deadlock detected while waiting for resource
Summe 1: 50

PL/SQL-Prozedur erfolgreich abgeschlossen.

Abgelaufen: 00:00:03.17 

Tom Kyte
April 04, 2006 - 9:35 am UTC

it is not clear the ordering of the calls here in the two sessions.

can you be a bit more clear as to the order of keystrokes necessary in each session... (before I look at it)

Re: why do i receive an "ora-60: deadlock"

Michael, April 03, 2006 - 11:24 am UTC

let's see.

1 create or replace procedure test_sum_proc as
2 cursor p_sum is
3 select sum (col1) summary
4 from test_sum
5 ;
6 procedure AnotherUserIsUpdating is
7 pragma autonomous_transaction;
8 begin
9 --REMOVE LOCK TABLE
10 --lock table test_sum in share row exclusive mode nowait;
11 update test_sum set col1 = 100;
12 commit;
13 exception
14 when others then
15 dbms_output.put_line ('Error: ' || SQLERRM);
16 end;
17 begin
18 lock table test_sum in share row exclusive mode;
19 for p_s in p_sum loop
20 dbms_output.put_line ('Summe 1: ' || p_s.summary);
21 end loop;
22 AnotherUserIsUpdating;
23 for p_s in p_sum loop
24 dbms_output.put_line ('Summe 1: ' || p_s.summary);
25 end loop;
26 rollback;
27* end;

you're locking the whole table test_sum in share row exclusive mode on line 18 . If it succeeds, no other session will be able to get a lock. On line 22 you call the procedure AnotherUserIsUpdating as autonomous transaction. There you do the lock...nowait. This will always raise a -54 (resource busy) error, because the other transaction (test_sum_proc) is still holding that lock and you tell oracle not to wait for it to release it. The update statment is never executed, so everything seems fine.

if you remove the lock request in AnotherUserIsUpdating, the update statment will do the row level locking. AnotherUserIsUpdating is nested in test_sum_proc and runs as autonomous transaction. So the problem is, that test_sum_proc already holds the lock on the table and the lock request in AnotherUserIsUpdating can never succeed. The same thing would happen, if you'd remove the nowait in the lock request in AnotherUserIsUpdating instead of removing the lock request altogether.

ora-60 is clear

A reader, April 04, 2006 - 6:59 am UTC

i can tom hear saying: think about it! sorry, i didn't see it yesterday! must have been blind. ~:(

classic deadlock situation! the main transaction holds a lock, requested by the autonomous transaction. if the autonomous transaction would wait for the lock, the main transaction would also wait forever as the autonomous transaction would never come back. classic deadlock situation!

Waits on Inserts

VLS, April 10, 2006 - 2:11 pm UTC

Hi Tom,

I have a 9207 database which is configured as MTS. During the peak hours, I can seen lots of ENQUEUE waits and the queries waiting on INSERT INTO a table with request=4. There are no FK constraint on this table. There is an Unique Index on this table. When I query v$session to check for the row_wait_obj#, row_wait_file#, row_wait_block# and row_wait_row#, I can see that the sessions are waiting for same obj#, file# and block#. The value in obj# is of Index. Does it mean that :

1. The application is using same unique key value and hence causing this lock or
2. row lock waits on an Index. I can seen high value in this statistics (v$segment_statistics). In this forum, I read one of your ressponse that row lock waits are basically for Index Split. If this is the case, then how do I eliminate this ? PCTFREE is set to 30 for this Index.

Would appreciate if you could reply to my queries.

Regards
VLS

Tom Kyte
April 11, 2006 - 11:19 am UTC

a query like this could give you some visibility into what is happening:


ops$tkyte@ORA10GR2> column blocker format a15
ops$tkyte@ORA10GR2> column blockee format a15
ops$tkyte@ORA10GR2> select
  2        (select username||'.'||a.sid
  3               from v$session where sid=a.sid) blocker,
  4        ' is blocking ',
  5         (select username||'.'||b.sid
  6                from v$session where sid=b.sid) blockee,
  7        ' from executing: ',
  8         (select sql_text from v$sqltext
  9               where address = (select sql_address
 10                                      from v$session where sid=b.sid))
 11    from v$lock a, v$lock b
 12   where a.block = 1
 13     and b.request > 0
 14     and a.id1 = b.id1
 15     and a.id2 = b.id2;
 
BLOCKER         'ISBLOCKING'  BLOCKEE         'FROMEXECUTING:'
--------------- ------------- --------------- -----------------
(SELECTSQL_TEXTFROMV$SQLTEXTWHEREADDRESS=(SELECTSQL_ADDRESSFROMV
----------------------------------------------------------------
OPS$TKYTE.150    is blocking  OPS$TKYTE.142    from executing:
insert into t values ( 1,1 )
 

Are the inserts into the unique key based on something like a sequence number?

A reader, April 11, 2006 - 2:01 pm UTC

If so, then you may want to look at reverse key index or global hash partitioned index (10g).
Not sure how you might track the case of duplicate key insert collisions if the app is handing the ORA-1 error itself.

A reader.

A reader, April 21, 2006 - 12:26 pm UTC

Hi Tom.

I need some guidance on this one. A table we have in production was locked and we could not even describe it in sqlplus. We had to bounce the database to recover. Here is a stack from udump and thanks for any suggestions:

lock_state : GRANTED
Open Options : KJUSERNO_XID
Convert options : KJUSERGETVALUE
History : 0x977d7d8d
Msg_Seq : 0x10003
res_seq : 37
valblk : 0x00000000000000000000000000000000 .
*** 2006-04-21 08:06:24.819
KGL recovered in-flux handle for lock 0x14db60168
----------------------------------------
SO: 0x14db60168, type: 53, owner: 0x15fa82c60, flag: INIT/-/-/0x00
LIBRARY OBJECT LOCK: lock=14db60168 handle=15e4fe288 request=S
call pin=(nil) session pin=(nil) hpc=0000 hlc=0000
htl=0x14db601e8[0x14d2f71c8,0x14d2f71c8] htb=0x14d2f71c8 ssga=0x14d2f64c0
user=15fa019e0 session=15fa019e0 count=0 flags=[0000] savepoint=0x761
LIBRARY OBJECT HANDLE: handle=15e4fe288 mutex=0x15e4fe3b8(0)
name=SAA.MESSAGE_STATUS
hash=cf8841c5c105b06a45fe8b78d4d46fc0 timestamp=03-10-2006 20:00:48
namespace=TABL flags=KGHP/TIM/XLR/[00000020]
kkkk-dddd-llll=0000-0000-0000 lock=0 pin=0 latch#=2 hpc=7996 hlc=7986
lwt=0x15e4fe330[0x14df22d88,0x14d2a38c0] ltm=0x15e4fe340[0x15e4fe340,0x15e4fe340]
pwt=0x15e4fe2f8[0x15e4fe2f8,0x15e4fe2f8] ptm=0x15e4fe308[0x15e4fe308,0x15e4fe308]
ref=0x15e4fe360[0x15e4fe360,0x15e4fe360] lnd=0x15e4fe378[0x15e4e36b8,0x15e526eb8]
LOCK INSTANCE LOCK: id=LBcf8841c5c105b06a
PIN INSTANCE LOCK: id=NBcf8841c5c105b06a release=F flags=[00]
INVALIDATION INSTANCE LOCK: id=IV0000e31a0a150131 mode=S
LIBRARY OBJECT: object=14f98fde8
DATA BLOCKS:
data# heap pointer status pins change whr
----- -------- -------- --------- ---- ------ ---
0 15e4fe1c8 14f98ff80 I/-/A/-/- 0 NONE 00
3 14f98f330 0 I/-/-/-/- 0 NONE 04
8 14f990128 0 I/-/-/-/- 0 NONE 04
9 14f98f268 0 I/-/-/-/- 0 NONE 04
10 14f98f1a0 0 I/-/-/-/- 0 NONE 04
11 14f7c1758 0 I/-/-/-/- 0 NONE 04


A reader, April 21, 2006 - 10:38 pm UTC

Hi Tom, any comment on the above question?

Tom Kyte
April 22, 2006 - 3:08 pm UTC

nope, partial trace file, condition that doesn't exist anymore, no "this is what happened right before", not much I can say.

You might file a tar.

Follow-up to my trace file

A reader, April 22, 2006 - 6:14 pm UTC

During a lock situation, what database parameter triggers clients to exit with errors if a library cache lock exceeds, say 10 hours?

Also, is there a parameter that controls how long client connections will wait on a lock before giving up with an error?

What happened here is that my client application was waiting for the lock to be released for 11 hours. Although trace files were written to udump, the client did not receive an error, and he lost connection when the database was bounced to resolve the lock.

Thanks.

Tom Kyte
April 23, 2006 - 4:58 am UTC

no database parameters do that.



Follow-up

A reader, April 23, 2006 - 10:31 am UTC

Tom,

What could cause a libray cache lock?

If the lock is never released, will sessions waiting on the lock hang indefinitely?

Thanks.


Tom Kyte
April 23, 2006 - 2:36 pm UTC

"please use support" - this is a situation that isn't supposed to happen see.

insert a not-yet committed parent value into child table causes child session to hang

A reader, May 11, 2006 - 9:59 am UTC

TEST @ adm1 SQL>create table t_master (tm_id number primary key);
Tabelle wurde erstellt.
Abgelaufen: 00:00:00.04

TEST @ adm1 SQL>create table t_detail (td_tm_id references t_master (tm_id), td_text varchar2(30));
Tabelle wurde erstellt.
Abgelaufen: 00:00:00.03

TEST @ adm1 SQL>insert into t_master values (1);
1 Zeile wurde erstellt.
Abgelaufen: 00:00:00.09

TEST @ adm1 SQL>insert into t_detail values (1, 'Reference First');
1 Zeile wurde erstellt.
Abgelaufen: 00:00:00.01

TEST @ adm1 SQL>commit;
Transaktion mit COMMIT abgeschlossen.
Abgelaufen: 00:00:00.00

TEST @ adm1 SQL>select distinct sid from v$mystat;
       SID
----------
        54
Abgelaufen: 00:00:00.24

TEST @ adm1 SQL>insert into t_master values (2);
1 Zeile wurde erstellt.
Abgelaufen: 00:00:00.00



>>>>>>>>>>>>>>>>>>>>>>>
>> GOTO ANOTHER SESSION
TEST @ adm1 SQL>select distinct sid from v$mystat;

       SID
----------
        51

Abgelaufen: 00:00:00.04
TEST @ adm1 SQL>insert into t_detail values (2, 'Second Reference');

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>> I WOULD EXPECT A NO PARENT KEY FOUND ERROR !?
>> BUT SESSION HANGS !?
>>


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>> LOCK SCENARIO IS AS FOLLOWS
>>
SYSTEM @ adm1 SQL>select * from v$lock where sid in (51, 54) order by sid;

ADDR             KADDR                   SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- --------
000000038DF43450 000000038DF435C8         51 TX     196621     216513          6          0        429          0
000000038DEDB2B0 000000038DEDB2D8         51 TM      54492          0          3          0        429          0
000000038DEDB1F0 000000038DEDB218         51 TM      54490          0          2          0        429          0
000000038D381400 000000038D381420         51 TX     262146     214391          0          4        429          0
000000038DF2EA98 000000038DF2EC10         54 TX     262146     214391          6          0        446          1
000000038DEDB130 000000038DEDB158         54 TM      54492          0          2          0        446          0
000000038DEDB070 000000038DEDB098         54 TM      54490          0          3          0        446          0
7 Zeilen ausgewählt.
Abgelaufen: 00:00:00.04


SYSTEM @ adm1 SQL>select data_object_id, object_name from dba_objects where data_object_id in (54490
, 54492, 196621, 262146);

DATA_OBJECT_ID OBJECT_NAME
-------------- ------------------------------
         54492 T_DETAIL
         54490 T_MASTER

Abgelaufen: 00:00:00.17

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>> I GOT THIS IN 8.1.7, 9.2.0, 10.2.0
>> IS THIS A FEATURE OR A BUG ??? 

Tom Kyte
May 11, 2006 - 7:39 pm UTC

why would it be a bug?
and why did you expect it to just fail?

it is similar to what happens when two sessions insert "1" into a unique key.

insert a not-yet committed parent value into child table causes child session to hang

A reader, May 12, 2006 - 6:10 am UTC

i can't follow you! did you do my example?

1) i inserted 2 - a non-existing value - into the master table but DIDN'T commit it right now!

2) i inserted 2 - a not yet commited master value - into the detail table awaiting an "ora-2291: integrity constraint (%s.%s) violated - parent key not found" as the parent key didn't exist / wasn't committed. but the session HUNG UP until the transaction 1) was finished!

i think it's a BUG! i found some related bug references in metalink, Bug:694655; Bug:650014

Tom Kyte
May 12, 2006 - 9:30 am UTC

I followed it exactly.

If you believe it to be a bug (I don't, databases are optimized to commit, not to rollback), support would be the correct channel.

My comment was about the behaviour of a unique constraint - two sessions insert the number "1" into a unique column - one blocks - the other hasn't committed. It is blocked on data that 'doesn't exist'. Similar situation, definitely not a bug.

insert a not-yet committed parent value into child table causes child session to hang

A reader, May 12, 2006 - 11:40 am UTC

i tried your example and inserted "1" into a master table with an unique constraint using two sessions. one blocked. even as i created and set the unique constraint deferred! is this the expected behavior or just a side effect of the implementation?

anyway. i did an insert into the detail table. the constraint lookup - via internal select ??? - shouldn't see the new parent key as any other "select" would do. shouldn't it?



Tom Kyte
May 12, 2006 - 9:27 pm UTC

this is the expected behaviour.

You are confusing "what you would see with a query" vs "how it works when enforcing constraints"

Look at the unique key example - what would you have happen?




insert a not-yet committed parent value into child table causes child session to hang

A reader, May 15, 2006 - 8:17 am UTC

ad master/master example: but a deferred constraint should be validated at the end of the transaction explicitly. why does this happen anyway?

ad master/detail example: the insert into the detail table shouldn't see the not-yet commited parent key. that's what i would expect.

is this all due to unique index maintenance implementation?

Tom Kyte
May 15, 2006 - 9:38 am UTC

"ad"?

I don't understand what you are trying to say, the point being made. what do you mean by "why does this happen anyway"? What is a "master/master" example?


I'm sorry it works the way it works, not the way we expect it would work had we written it ourselves. That is - the database works the way it works, not the way WE think it should. It is our job to understand how it works and react accordingly.

foreign keys have nothing to do with indexes.

insert a not-yet committed parent value into child table causes child session to hang

A reader, May 16, 2006 - 11:35 am UTC

hi tom,

with "master/master example" i meant two sessions inserting the same value into an unique key constraint at the same time.

with "master/detail example" i meant one session inserting a new parent key into the master table while at the same time another session inserts the new not yet committed parent key into the detail table.

tom, don't be angry with me. i know i'm impertinent. i know that it is meanwhile. i can see it. i can reproduce it. but i also want to know why it is! there must be a reason. i don't think that the developers sat down, said it's monday, sun is shining, let's make fun and implement constraint validation in exactly that way. there must be a reason for this! why is it the way it is? please tom, give me the reason! especially for the "master/detail example".

Tom Kyte
May 16, 2006 - 11:49 am UTC

It "just is", it is the way it works, it makes as much sense as it would to "fail". The row is likely going to be there - things are optimized to COMMIT, not rollback. The odds are the row in fact will exist, therefore we wait for it.

If it worked in reverse, I could make the same argument you are making.

I am sorry it does not work the way you believe it should - the way YOU would have done it. It makes sense to me, much in the same way that inserts block during a unique key violation. Why should a unique key block? The other row doesn't exist yet, how can we block on data we cannot see? This master/detail issue is analogous (to me at least)

Can a session have 2 requests at the same time?

Vadim, May 16, 2006 - 1:35 pm UTC

Tom,

can a single session have 2 requests at the same time? In other words if I query v$lock is it possible to get 2 records with the same sid, both having v$lock.request != 0 and v$lock.lmode = 0?

Thanks in advance


Tom Kyte
May 16, 2006 - 1:49 pm UTC

cannot think of a time, doesn't mean it cannot happen, I just cannot think of one immediately.

lock on sql

nn, May 23, 2006 - 3:07 pm UTC

Hi Tom,

I am havig an issue here based on lock created by a sql statement? Please hel p me to understand.

SID USERNAME OSUSER PROGRAM MODULE MACHINE

---------- ------------- ---------- ---------- ---------- ----------

SQL_TEXT



51 ADAPPL isint JDBC Thin JDBC Thin admin-stg.

Client Client nn.com

SELECT VEHICLE_CONTEXT_ID, VEHICLE_ID, TASK_ID, LOGIN_ID, TIMESTAMP, TIMEOUT, CONTEXT_STATUS_ID, PURCHASE_TYPE_ID FROM VEHICLE_CONTEXTS WHERE VEHICLE_ID = :1 AND PURCHASE_TYPE_ID = :2 AND CONTEXT_STATUS_ID = :3


38 ADAPPL isint JDBC Thin JDBC Thin admin-stg.

Client Client nn.com

INSERT INTO VEHICLE_CONTEXTS (VEHICLE_CONTEXT_ID, VEHICLE_ID, TASK_ID, LOGIN_ID, TIMESTAMP, TIMEOUT, CONTEXT_STATUS_ID, PURCHASE_TYPE_ID) VALUES (:1,:2,:3,:4,:5,:6,:7,:8)



WAITING_SESSION HOLDING_SESSION LOCK_TYPE CTIME OBJECT_NAME F_PROCESS
--------------- --------------- -------------------------- ---------- -------------------------------------------------------------------------------------------------------------------------------- ------------
38 51 Transaction 60604 ORGANIZATIONS

Tom Kyte
May 24, 2006 - 6:52 am UTC

it would look like session 38 is trying to insert a key (unique or primary) into vehicle_contexts that session 51 already has inserted but not yet committed.

Totally guessing given the information provided.

If you do this in session1:

ops$tkyte@ORA10GR2> create table t ( x int primary key );

Table created.

ops$tkyte@ORA10GR2> insert into t values ( 1 );

1 row created.


and then in session2:

ops$tkyte@ORA10GR2> insert into t values ( 1 );




then in session1 (or session3) you can:

ops$tkyte@ORA10GR2> select
  2       (select username from v$session where sid=a.sid) blocker,
  3        a.sid,
  4            (select x.sql_text from v$sql x, v$session y
  5              where y.sid = a.sid
  6                    and y.sql_address = x.address) sql_text1,
  7       ' is blocking ',
  8        (select username from v$session where sid=b.sid) blockee,
  9            b.sid,
 10            (select x.sql_text from v$sql x, v$session y
 11              where y.sid = b.sid
 12                    and y.sql_address = x.address) sql_text2
 13   from v$lock a, v$lock b
 14  where a.block = 1
 15    and b.request > 0
 16    and a.id1 = b.id1
 17    and a.id2 = b.id2;

BLOCKER                               SID
------------------------------ ----------
SQL_TEXT1
-------------------------------------------------------------------------------
'ISBLOCKING'  BLOCKEE                               SID
------------- ------------------------------ ----------
SQL_TEXT2
-------------------------------------------------------------------------------
OPS$TKYTE                             146

 is blocking  OPS$TKYTE                             151
insert into t values ( 1 )




 

not clear

nn, May 24, 2006 - 4:18 pm UTC

BLOCKER SID
------------------------------ ----------
SQL_TEXT1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'ISBLOCKING' BLOCKEE SID
------------- ------------------------------ ----------
SQL_TEXT2
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADAPPL 19
SELECT VEHICLE_CONTEXT_ID, VEHICLE_ID, TASK_ID, LOGIN_ID, TIMESTAMP, TIMEOUT, CONTEXT_STATUS_ID, PURCHASE_TYPE_ID FROM VEHICLE_CONTEXTS WHERE VEHICLE_ID = :1 AND PURCHASE_TYPE_ID = :2 AND CONTEXT_STATUS_ID = :3
is blocking ADAPPL 42
INSERT INTO VEHICLE_CONTEXTS (VEHICLE_CONTEXT_ID, VEHICLE_ID, TASK_ID, LOGIN_ID, TIMESTAMP, TIMEOUT, CONTEXT_STATUS_ID, PURCHASE_TYPE_ID) VALUES (:1,:2,:3,:4,:5,:6,:7,:8)

Tom Kyte
May 25, 2006 - 1:16 pm UTC

what is not clear?

sql locking

nn, May 24, 2006 - 4:39 pm UTC

Tom,

Holding session is a select statement. How can it cause lock?

Tom Kyte
May 25, 2006 - 1:17 pm UTC

it isn't, you are just looking at a single sql statement used by that session, you are not looking at all of the sql statements that came BEFORE it.



to "nn" ...

Gabe, May 24, 2006 - 9:40 pm UTC

<quote>Holding session is a select statement. How can it cause lock?</quote>

That "select ... from vehicle_contexts" is the last statement executed by the session holding the lock. Session 19 obtained the lock prior to executing the select.


Locks

A reader, June 01, 2006 - 11:18 am UTC

Tom,
Going through the entire discussion on locks, would it be fair to say that if my production database has frequent lock condition, I need to check my application code? All the users connect through the application. If they lock each other's sessions, then most likely suspect is application code. Do you agree?

Thanks


Tom Kyte
June 01, 2006 - 11:39 am UTC

What causes locks?

In this case, I'll assume normal "row locks on rows due to updates".

What causes those locks to happen?

Applications lock information.

Yes, you would need to likely go to the "source"



Updating Zero Rows

Vikram Romeo, June 01, 2006 - 5:32 pm UTC

Hi Tom,

This is an excellent thread ...

I have one basic question though (most of mine are .. :-( but I cant help asking this question) ...

Consider
in SESSION-1:
*************
drop table t;
create table t (x int, y int,z int);
update t set x=1 where 1=2;

0 rows updated.

in SESSION-2:
************
truncate table t;
truncate table t
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

Now the question:
*****************

Why is it that even when zero rows are updated - that means there is no lock on the table right? - we are not able to truncate the table from another session?

Why should oracle lock the table even when 0 rows are updated?

Expecting your response as always ... :-)

Regards,
Vikram Romeo

Tom Kyte
June 01, 2006 - 6:21 pm UTC

there is a lock on the table - you have begun a transaction, you "own" that table structure.

update:

step 1) get a lock on the structure of the table to prevent structural modifications and to ensure we can actually *get* such a lock.

step 2) find rows to modify, modify them.

blocking,

A reader, July 20, 2006 - 10:15 am UTC

I keep hearing that some sessions are blocking others (not locking the objects). I don't understand what they mean. Once they killed the session that was blocking and they said the machine is freed up now and the cpu usage has come down.

What exactly it means? How to find out such sessions that are "blocking"? We are on 10g R1 3 node RAC.

Thanks,


Tom Kyte
July 22, 2006 - 4:51 pm UTC

who is saying they are "blocking but not locking objects"

I believe they might be "not correct"

gv$lock might be useful here.

blocking,

A reader, July 25, 2006 - 7:44 pm UTC

On RAC databases, does people call "blocking" if one node blocks the other node?

One of the DBA was mentioning that Oracle 10g grid control can be used to find out all the blocking sessions.

I am still confused what they mean.

Thanks,



Tom Kyte
July 25, 2006 - 7:50 pm UTC

blocking to me has a specific meaning.

I have locked a resource.
You want that resource.
You are now blocked by me.

It can happen in RAC or single instance and gv/v$lock can be used.

thanks,

A reader, July 25, 2006 - 8:03 pm UTC

In that case can a long running SELECT statement cause blocking to others? If so, what kind of lock would that be?


Tom Kyte
July 25, 2006 - 8:07 pm UTC

not unless it was a select for update, you have to lock something. normal selects - they do not lock the data.

A reader, August 09, 2006 - 1:05 pm UTC

Tom,

I was looking at your query mentioned below and i know you mentioned this will take a while on a busy production system, can using subquery factoring "with" be of help?

Thanks.

select
(select username from v$session where sid=a.sid) blocker,
a.sid,
' is blocking ',
(select username from v$session where sid=b.sid) blockee,
b.sid
from v$lock a, v$lock b
where a.block = 1
and b.request > 0
and a.id1 = b.id1
and a.id2 = b.id2
/

Tom Kyte
August 09, 2006 - 4:22 pm UTC

it could be of help, it'll reduce the times we need to access the v$ views which will always help:

with
sessions
as
(select username, sid, rownum r
from v$session),
locks
as
(select sid, block, request, id1, id2, rownum r
from v$lock)
select sess1.username blocker,
lock1.sid,
' is blocking ',
sess2.username blockee,
lock2.sid
from locks lock1, locks lock2, sessions sess1, sessions sess2
where lock1.block = 1
and lock2.request > 0
and lock1.id1 = lock2.id1
and lock1.id2 = lock2.id2
and lock1.sid = sess1.sid
and lock2.sid = sess2.sid
/


A reader, August 09, 2006 - 7:03 pm UTC

Excellent way lot faster than the previous one.

Thanks.

Exclusive lock

Anne, August 24, 2006 - 8:54 am UTC

Hi Tom,

I have the foll. pseudocode in a package.proc :

lock table t in exclusive mode;
...<Do some processing and insert/update into table t>
Commit if successful;

Now, I need to do some more processing from table t and insert into tables t1, t2.

At this point, after the commmit, I am assuming that the lock on table t is released. So if I needed table t locked again in the same session, should I be doing another "lock table t in exclusive mode;" ? I am not sure if this is the way to go...

Appreciate your help.


Tom Kyte
August 27, 2006 - 7:48 pm UTC

all locks (except for special locks allocated manually via dbms_lock) are released with your commit, yes.

If you want to start another transaction AND this transaction shouldhave t locked, that transaction should lock table t.



Exclusive lock

Anne, August 24, 2006 - 12:57 pm UTC

Hi Tom,

I think I may have mis-typed my email id, because I cannot find it in 'My questions'...

I have the foll. pseudocode in a package.proc :

lock table t in exclusive mode;
...<Do some processing and insert/update into table t>
Commit if successful;

Now, I need to do some more processing from table t and insert into tables t1,
t2.

At this point, after the commmit, I am assuming that the lock on table t is
released. So if I needed table t locked again in the same session, should I be
doing another "lock table t in exclusive mode;" ? I am not sure if this is the
way to go...

Appreciate your help.




Database Userid Getting locked

Chandan Singh, August 25, 2006 - 6:00 am UTC

Hi

I am facing a problem of Database account getting locked when connection for that user exceeds 2.

Scenario :- We have 3 siebel servers. When we bring up 2 siebel servers with database user id SADMIN,Its working fine but when we bring up 3rd siebel server. Database account sadmin gets locked.

what could be the possible reason for this? Well, Other servers work fine when try to increase the no. of servers then sadmin gets locked.

One could be due to FAILED_LOGIN_ATTEMPTS. what could be the other reason?

Please help.

Profile Setting for user SADMIN

RESOURCE_NAME LIMIT

COMPOSITE_LIMIT DEFAULT
SESSIONS_PER_USER UNLIMITED
CPU_PER_SESSION DEFAULT
CPU_PER_CALL DEFAULT
LOGICAL_READS_PER_SESSION DEFAULT
LOGICAL_READS_PER_CALL DEFAULT
IDLE_TIME UNLIMITED
CONNECT_TIME DEFAULT
PRIVATE_SGA DEFAULT
FAILED_LOGIN_ATTEMPTS 100
PASSWORD_LIFE_TIME UNLIMITED
PASSWORD_REUSE_TIME 365
PASSWORD_REUSE_MAX UNLIMITED
PASSWORD_VERIFY_FUNCTION XM_PASSWORD_VERIFY_FUNCTION
PASSWORD_LOCK_TIME 0.0104
PASSWORD_GRACE_TIME 14

Thanks
Chandan Singh

Tom Kyte
August 27, 2006 - 8:19 pm UTC

that is a resource profile, what about other security implementations you might have?

ora-60

MHP, August 25, 2006 - 5:23 pm UTC

Tom,
what are the types of locks would Not hit Ora-60 and Not generating a trace file in the udump?

Tom Kyte
August 27, 2006 - 8:53 pm UTC

all locks might not hit a deadlock.
most all locks could hit a deadlock.

not sure entirely what you mean?

deadlock

MHP, August 28, 2006 - 12:52 am UTC

how can we tell from v$lock if there is the deadlock out there in database without looking for ora-60 in the dump?

Tom Kyte
August 28, 2006 - 8:57 am UTC

you cannot, not unless you are really really really lucky and see it right before the trace is generated.

the raising of the ora-60 RESOLVES the deadlock, once it is raised, you won't SEE it anywhere since the situation no longer exists.

I set up a simulation - two row table, x=1, x=2.  

session 1: update x=1
session 2: update x=2
session 2: udpate x=1 -- blocks
session 1: get READY to update x=2, don't do it yet.
session 3: get READY to run the query below

now, in session 1, hit enter and immediately goto session 3 and hit enter and you might see:

ops$tkyte%ORA10GR2> select
  2        (select username from v$session where sid=a.sid) blocker,
  3         a.sid,
  4        ' is blocking ',
  5         (select username from v$session where sid=b.sid) blockee,
  6             b.sid
  7    from v$lock a, v$lock b
  8   where a.block = 1
  9     and b.request > 0
 10     and a.id1 = b.id1
 11     and a.id2 = b.id2;
 
BLOCKER                               SID 'ISBLOCKING'
------------------------------ ---------- -------------
BLOCKEE                               SID
------------------------------ ----------
OPS$TKYTE                             151  is blocking
OPS$TKYTE                             142
 
OPS$TKYTE                             142  is blocking
OPS$TKYTE                             151
 


but within a very very short period of time (3 seconds or less), you will see:

       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource

in one of the sessions and re-running that query will show:

ops$tkyte%ORA10GR2> select
  2        (select username from v$session where sid=a.sid) blocker,
  3         a.sid,
  4        ' is blocking ',
  5         (select username from v$session where sid=b.sid) blockee,
  6             b.sid
  7    from v$lock a, v$lock b
  8   where a.block = 1
  9     and b.request > 0
 10     and a.id1 = b.id1
 11     and a.id2 = b.id2;
 
BLOCKER                               SID 'ISBLOCKING'
------------------------------ ---------- -------------
BLOCKEE                               SID
------------------------------ ----------
OPS$TKYTE                             142  is blocking
OPS$TKYTE                             151
 


that only one session is blocked now, the deadlock is resolved.  


You could code a 'server error' event trigger to capture ora-60's somewhere for your review. 

To MHP

Michel Cadot, August 28, 2006 - 2:19 am UTC


You can't never see a deadlock case in v$lock (unless an Oracle bug) as if there can be a deadlock condition, Oracle detects it during the process of getting the lock and kill one of the transactions to immediatly resolve it and so the deadlock can't be in v$lock.

Michel


Tom Kyte
August 28, 2006 - 9:06 am UTC

immediately is "within 3 seconds" though, so it will be there "transiently" - but in practice you will NOT see them, they come and go too fast.

security implementations

Chandan, August 28, 2006 - 5:05 am UTC

Hi Tom,

Can you please throw some light on other security implementations that can lead to schema lock.

Thanks
Chandan Singh

Tom Kyte
August 28, 2006 - 10:50 am UTC

password complexity/verfication routines.

in short, something is obviously "different" here - what else have you implemented on this database you did not on some other database.

problem with siebel server manager

Chandan Singh, August 29, 2006 - 3:26 am UTC

Hi Tom,

Thanks for your reply and for all your help that you are providing to the oracle community.

Well, This is just to update you.

Problem seems to be with siebel server manager. When it tries to connect to database using sadmin user, siebel logs shows "SBL-ADM-01042: Login failed for specified username, password, and ODBC datasource combination." message. and after 100 Failed Login Attempts account gets locked.

This same password is working when we are connecting thru sqlplus without any problem.

For this ticket has been raised with Siebel Web Support & waiting for reply.

Thanks again for your reply.
Chandan Singh

Rollback in autonomous transaction

A reader, September 11, 2006 - 10:22 am UTC

Hi Tom,

I have the following situation

Proc1(p_ide, p_error_code)
autnomous transaction
e_stop exception
begin
update table T
set error_code = 'Text of Error'
where ide = p_ide; -- ide is a primary key;

commit;
exception
when others then
dbms_output.put_line('Raise a user defined exception');
raise e_stop;
-- there is no Rollback;
end;

Then I have Proc2 as follows

begin
.../..
proc1(ide, 'Text of Error'); -- call autonomous transaction
.../..
exception
when e_stop
proc1(ide, 'Text of Error'); -- call autonomous transaction
when others then
raise;
end;


I am in a situation where in proc1(autonmous transaction an exception occurs and there is no rollback there).
Then we raise e_stop and go back to the parent transaction. In the parent transaction we will try again to
call proc1 (autonmous transaction) for the same ide.

Do this produces an ORA-0600 Deadlock detected? In other words, if the autonomous transaction do not rollback update of a given
ide,then it goes back to its parent transaction and again the parent transaction call the autonomous transaction in order to update
the same ide, do this is a candidate to ORA-06000

I have been reading Chapter 3 and Chapter 15 of your book and need to validate the above assumption

Thanks a lot


Tom Kyte
September 11, 2006 - 10:45 am UTC

when you test it, what happens


when you exit the autonomous transaction (evil horrible things that they are - something you probably shouldn't be using, 99.999999% of the time they are used wrong), the transaction is "over", dead, kaput, finished.

You cannot leave a block of autonomous code without finishing the transaction (and hence releasing any locks gained therein).

Dead Lock when using autonomous transaction

A reader, September 22, 2006 - 11:03 am UTC

Dear Tom,

I hope you can help me.

I am runing in parrallel (three process) to do an initial load. Each process are doing the same logic but for different ranges of ide.

In each process when an error occurs I am updating the main table via autonomous transaction for the current ide. If an error occurs also in the autonomous transaction a rollback is issued and then a raise to an exception is done and again a call to this autonomous transaction for the same ide is done. This is summarised below

BEGIN
.../..
IF error
-- call autonomous procedure(ide_1, error_1)
Exception
when exception from autonomous procedure then
-- call autonomous procedure (ide_1, error_1)
end;

where autonomous procedure is like
Pragma autonomous transaction
update table T set
error_code = error
where ide = ide11

Commit;

Exception
when others then
rollback;
raise autonomous transaction;
end;

Unfortunatley for one process I have got a ORA-00060 DeadLock detected.

The two remaining processes went very well

Have you any idea why this deadlock happens?

Thanks in advance for your help





Tom Kyte
September 22, 2006 - 3:56 pm UTC

oh my, ouch - this hurts, this hurts so very very bad to read.

so, what is the goal of the autonomous transaction - why do you feel compelled to use it?

there is at least a 99.9999999999999999999999999999999999999999999999% chance your logic is entirely flawed.

enq: TM - contention

A reader, November 07, 2006 - 3:08 pm UTC

Hi Tom,
I am using database 10G.
when i created a statspack report , i found my top wait was "enq: TM - contention"

all notes i found talk about unindexes forgin key , but it all mentioned that this is only applied before 9iR2

but in 10G , could you please help me to know the cause of this wait ?

Thanks

Many users locking one table

kungbengan, November 13, 2006 - 6:55 am UTC

Hi Tom!

I've read a lot in this thread, but there is one thing I don't understand (maybe because I am not an Oracle expert).

The application I am supporting hangs occassionaly because several users are locking one table in exclusive mode. The supplier is telling us that this is a "bottle neck". The only way to solve the issue that the application hangs is to kill user sessions trying to access the table or restart the database. Is there something else I can do to prevent this from happening?

Thanks for your help!

/kungbengan

Tom Kyte
November 14, 2006 - 3:56 am UTC

several users are NOT locking the table in exclusive mode.

They might have row locks, but not full table locks - at the same time.

The vendor of your application has a bug. They sort of need to look into that. They are permitting people to lock rows for long periods of time - and when someone else wants that row, they get blocked. It is a very "basic" sort of thing.

ORA-00054: resource busy and acquire with NOWAIT

Dorothea Nenova, December 12, 2006 - 10:00 am UTC

Dear Tom,

when our users get this message, they would like to know who exactly is using their record, actually they expect that the application is producing the message "User X is locking your information", so that they can ask him to hurry up. It is the basic table of the application, so at table level there are a few users, who lock it and it takes time to check what everybody from this list is doing, not to say that there is no way to guess who exactly is using the record.

It is clear to me that without "NOWAIT" the session will remain blocked and the user could not even be informed about this, which is worse, of course.

Is there any way to cope with such a situation?
Thanks a lot!


which sql hold the lock?

Harry Zhang, December 27, 2006 - 4:42 am UTC

Hi tom,

If session do the below:
update t ..
select * from t
select * from dual

Then in v$session only the last sql is recorded.
How do I find the sql that really hold the lock?

Thank you!
Tom Kyte
December 28, 2006 - 8:40 am UTC

you do not, it is not really "relevant" in the grand scheme of things and in fact there might be MANY "sql" that "hold" the lock (sql doesn't hold a lock, the session does)

INACTIVE Session holding resource

Sanji, December 29, 2006 - 1:19 pm UTC

Tom,

I'm trying to investigate a frequent database issue of "ENQUEUES".
Oracle 9.2.0.4.0 on HP-UX 11i.

Following is a log of the queries that i executed.

select username,v$lock.sid,trunc(id1/power(2,16)) rbs,bitand(id1,to_number('ffff','xxxx'))+0 slot,id2 seq,lmode,request
from v$lock, v$session
where v$lock.type = 'TX'
and v$lock.sid = v$session.sid
/

USERNAME SID RBS SLOT SEQ LMODE REQUEST
---------- ---- ---------- ---------- ---------- ---------- ----------
UNITEDRENTAL 21 1 61 969453 6 0

select XIDUSN, XIDSLOT, XIDSQN, status
from v$transaction;

XIDUSN XIDSLOT XIDSQN STATUS
---------- ---------- ---------- ----------------
1 61 969453 ACTIVE

select sid,serial#, machine, status,
to_char(logon_time,'dd-mm-yy hh:mi:ss') "LOGON",
floor(last_call_et/3600)||':'||
floor(mod(last_call_et,3600)/60)||':'||
mod(mod(last_call_et,3600),60) "IDLE"
,prev_hash_value,prev_sql_addr
from v$session
where username is not null
and sid=21
/

SID SERIAL# MACHINE STATUS LOGON IDLE PREV_HASH_VALUE PREV_SQL_ADDR
---- ------- --------------- -------- ----------------- ---------- --------------- ----------------
21 60128 URNT\TREC INACTIVE 29-12-06 12:02:17 0:30:45 2856600553 C00000002ABA4588

select sid,address, hash_value,sql_text
from v$open_cursor
where sid=21;

SID ADDRESS HASH_VALUE SQL_TEXT
---------- ---------------- ---------- ------------------------------------------------------------
21 C00000002ABA4588 2856600553 INSERT INTO "CORRESPONDENCE" ( "EVENTID", "CORRFROM", "CORRT


select sid,event,p1,p2,p3,wait_time,seconds_in_wait,state
from v$session_wait
where sid=21

SID EVENT P1 P2 P3 WAIT_TIME SECONDS_IN_WAIT STATE
---- ------------------------------ ---------- ---------- ------ ---------- --------------- ----------
21 SQL*Net message from client 1413697536 1 0 0 2244 WAITING

Question:
The session is inactive (v$session), but is Active otherwise (v$transaction, v$open_cursor). From v$session_wait, it's waiting for a response from the client.
From v$open_cursor, the query being executed is an INSERT.

The particular session needs to be killed whenever there is a lock event, involving this session and there are frequent such events.

I'm not able to understand the reason behind this behaviour.

Regards
Sanji
Tom Kyte
December 30, 2006 - 9:01 am UTC

TX just means "i have a transaction open", not sure why you are running the query you are running to investigate enqueue issues?


what are you not able to understand?

you have a client session (sid = 21)

It is currently sitting there (like a sqlplus session would be if you did not hit the enter key)

At some point, that session had performed an insert (doesn't mean that the TX you are seeing it even related to that insert, that just means in your case that application has a cursor open and it happened to be an insert - it really isn't shown here that the insert is the reason for the TX).

Why would you kill this session if there is a "lock" event. Why would you kill a session in response to a blocking/blockee event EVER???

this doesn't make sense, if the blocker should not be blocking - you have an application ISSUE TO CORRECT.

A reader, January 01, 2007 - 9:03 am UTC

Tom,

For a transaction that uses large amounts of rollback, say it takes a while to rollback,is
it correct that it will use lots of rollback slots.

In that case

1) Does the row in v$transaction's XIDUSN XIDSLOT XIDSQN values keep flipping
and flopping as the transaction rolls back or just stay fixed on the first rollback
segment slot used.

2) Same question with V$lock, but presumably, it will Always be pointing to an arbitary
or the first rollback segment slow on the ID1 and ID2 parameters no matter how many the rollback
segment slots are? Its like a token system, once it records a value of an RBS, it needs
to keep it on ID1 and ID2, so that any other sessions being blocked, have the same
value of ID1 and ID2, but with a Request > 0

Thanks

Ravi
Tom Kyte
January 01, 2007 - 9:18 am UTC

the XID... columns are the Transaction ID - they are fixed for the transaction.


A reader, January 01, 2007 - 11:48 am UTC

Tom,
What I wanted to know was whether the column values of v$transaction XIDUSN XIDSLOT XIDSQN or the ID1 and ID2 of v$lock, do they point to an "actual" rollback segment slot?

If yes, for a large transaction would not multiple slots be used, say I update a million rows but do not commit and if they do, as there are only one row for v$transaction and v$lock, do they actually point to the first RBS slot used?

Thanks
Tom Kyte
January 01, 2007 - 7:47 pm UTC

the xid--- columns are the transaction id, they are a given during the transaction (you get one transaction id)



A session blocks itself

Ivan Virag, January 05, 2007 - 9:58 am UTC

Hi Tom.

How is generally possible that a session can block itself in case of the dedicated server. This select:

select (select username
from v$session
where sid=a.sid
) blocker
,a.sid
,' is blocking '
,(select username
from v$session
where sid=b.sid
) blockee
,b.sid
from v$lock a, v$lock b
where a.block = 1
and b.request > 0
and a.id1 = b.id1
and a.id2 = b.id2;

returns:

BLOCKER SID 'ISBLOCKING' BLOCKEE SID_1
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
...

I have no access to the database, I'm trying to solve their problem via emails with total hang and got this.

Thank you

Ivan

Tom Kyte
January 05, 2007 - 10:49 am UTC

 ops$tkyte%ORA10GR2> select (select username
from v$session
  2    3  where sid=a.sid
  4  ) blocker
  5  ,a.sid
  6  ,' is blocking '
  7  ,(select username
  8  from v$session
  9  where sid=b.sid
 10  ) blockee
 11  ,b.sid
 12  from v$lock a, v$lock b
 13  where a.block = 1
 14  and b.request > 0
 15  and a.id1 = b.id1
 16  and a.id2 = b.id2;

no rows selected

ops$tkyte%ORA10GR2> /

BLOCKER                               SID 'ISBLOCKING'  BLOCKEE                               SID
------------------------------ ---------- ------------- ------------------------------ ----------
OPS$TKYTE                             148  is blocking  OPS$TKYTE                             148


this was the result of running this bit of code for example

ops$tkyte%ORA10GR2> create table t ( x int primary key );

Table created.

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

1 row created.

ops$tkyte%ORA10GR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          insert into t values ( 1);
  5          commit;
  6  end;
  7  /

great but

Sokrates, January 05, 2007 - 3:32 pm UTC

a.

when I copy / paste your example (10GR2) I get

SQL> create table t ( x int primary key );

Table created.

Elapsed: 00:00:00.02
SQL> insert into t values ( 1 );

1 row created.

Elapsed: 00:00:00.00
SQL> get afiedt.buf
1 declare
2 pragma autonomous_transaction;
3 begin
4 insert into t values ( 1);
5 commit;
6* end;
SQL> /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4


Elapsed: 00:00:03.06

quite soon ( after 3 seconds )
I don't understand that.
I expected the session to hang forever.
did you get the same behaviour and can you explain it ?

did you run the query to detect the self-blocking session
within these 3 seconds ?




b.

when I understood Ivan right, he got more than one entry
of a self-blocking-session which seems quite impossible to me.

(
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
...
)

am I right or do you know of an example which could give
Ivan's result ?
Tom Kyte
January 06, 2007 - 8:49 am UTC

I know you did, I did too. I ran that block, went to another session - ran the "is blocking" query.

I don't understand Ivans output either - it does not look like the output of that query. I'd want more context - like what these sessions actually do.

self-blocking-session

Ivan Virag, January 08, 2007 - 9:56 am UTC

Hallo.

The process does this:

They have a schema INFOSVRLDR1 with a table say T1. Then we have the same table T1 which is placed on a remote database with synonym say T1_LINKED. T1 is filled from T1_LINKED via dblink. They use "INSERT /*+APPEND */ INTO T1 (<column_list>) SELECT <column_list> FROM T1_LINKED. The process goes like this:

1. Procedure which truncates T1 table (runs as an autonomous transaction)
2. Procedure which set indexes unusable on T1 table
3. Procedure which drops primary key constraint on T1 table
4. Procedure which sets skip_unusable_indexes to TRUE
5. INSERT /*+APPEND */ INTO T1 (<column_list>) SELECT <column_list> FROM T1_LINKED;
6. commit;
7. Procedure which rebuilds unusable indexes on T1 table
8. Procedure which recreates the primary key on T1 table
9. Procedure which rebuilds the T1 table statistics using DBMS_STATS package.

Then the process goes to do the same with table T2 and T2_LINKED and goes further sequentially to the next tables - T3, T4 ... Tn. One time it totaly hangs on T8, the next time on T54, then on T6, ... There is no other activity on this schema during the process, there are no foreign key constraints (just indexes) on this schema (don't ask me why, please. I am not the author). And moreover inside processing of one table it can hang once on the INSERT command once on recreating the indexes once on the computing the statistics. When it hangs, the above mentioned lock select returns hudreds of entries with self blocking session on INFOSVRLDR1.

BLOCKER SID 'ISBLOCKING' BLOCKEE SID_1
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
INFOSVRLDR1 21 is blocking INFOSVRLDR1 21
and more
and more
and more...


I am desperate :-)

If you have any clue or recomendation for me I would be very thankfull.

Thank you very much.

Ivan
Tom Kyte
January 08, 2007 - 1:13 pm UTC

please utilize support, does not sound "normal"

block=2

Harry Zhang, January 10, 2007 - 2:20 am UTC

Hi Tom,

In your script:
tkyte@TKYTE816> select
(select username from v$session where sid=a.sid) blocker,
2 a.sid,
3 ' is blocking ',
4 (select username from v$session where sid=b.sid) blockee,
5 b.sid
6 from v$lock a, v$lock b
7 where a.block = 1
8 and b.request > 0
9 and a.id1 = b.id1
10 and a.id2 = b.id2
11 /


Why you use block=1, sometimes I saw block=2.

Hanging Session

Tariq Zia lakho, January 17, 2007 - 6:07 am UTC

I need you help regarding the hanging session in oracle9i
I am facing this type of problem since 2 months when

1. Alter table add column
2. Alter table add constraint
3. Drop table
4. Even truncate table in which just 2000 records

There is no error in Alert Log.
I have already checking through tracing....no result

today i am facing problem in Trucate table.....when I run this query (trncate table <table_name>); session hanged after 15 mints prompt return and display a message in which locked_objects.....but there is no object locked.
this table is standalong......There is no constraint on it. There is no relation.

Please help me how could i find the problem. What is the cause. even checked the UNDO Tablespace its free 75%.

For emergency basis I have run delete command and commit.

Regards,
Tariq

Hanging Session

Tariq Zia lakho, January 17, 2007 - 6:10 am UTC

I need your help regarding the hanging session in oracle9i
I am facing this type of problem since 2 months when I perform the following things

1. Alter table add column
2. Alter table add constraint
3. Drop table
4. Even truncate table in which just 2000 records

There is no error in Alert Log.
I have already checking through tracing....no result

today i am facing problem in Trucate table.....when I run this command (trncate table <table_name>); session hanged after 15 mints prompt return and display a message in which locked_objects.....but there is no object locked.
this table is standalone......There is no constraint on it. There is no relation.

Please help me how could i find the problem. What is the cause. even checked the UNDO Tablespace its free 75%.

For emergency basis I have run delete command and commit.

Regards,
Tariq

row select

Michael, January 19, 2007 - 1:25 am UTC

hi tom,
could you tell me what this statemetS are doing exactlly?

LOCK TABLE saving IN ROW SHARE MODE;
select bal into a
from saving
where customerID='John';
does it mean that we are going to lock (customerID='John') by share?, because one friend told me that"LOCK TABLE saving IN ROW SHARE MODE;" makes a share lock on the entire table (Saving) not on a row , like intention lock mode in Multiple Granularity .

thanks alot for help

To: Michael

Michel Cadot, January 24, 2007 - 7:34 am UTC

locks and buffer cache,

A reader, February 02, 2007 - 12:00 pm UTC

I think there can be hundereds and thousands of row level locks and even table level locks in the datafile level. This can happen when a DML statement is issued. this will be released when a commit or rollback happens.

When I issue an update statment (to update 10% of the rows), what is the process that takes a message to the datafile and locks it?

I understand Oracle requests the OS to get the block out of physical disks (PIO), does the OS goes and locks the row which we are trying to update while it fetches?

Another question:

I have pl/sql procedure that has a cursor statment that selects data from emp table. In the body of my procedure, I open the cursor and perform an update statement on the emp table within the loop of the cursor.

When the procedure is executed, the cursor first parse the statement and execute it. I have all my data from emp in the buffer cache. Will the latch on these buffers exists until the pl/sql procedure is completed?

Now in the body of the procedure, if I perform the update statement, will the same server process use the latch on the buffers (all my data is in buffer cache and the update may not do a PIO this time) and try to update the data OR will it wait for the cursor to release the latch and then the Update statement tries to get its own latch?

thanks,

Tom Kyte
February 02, 2007 - 1:43 pm UTC

there can be as many row locks as there are rows.


I'll refer you to either

a) the Concepts guide
b) my book Expert Oracle Database Architecture, if you want to hear it in my voice

as this takes many pages to do justice.

Locks are an attribute of the data, they are part of the block structure itself. A row lock is an attribute, we do it, the OS can do nothing.


.... I have all my data from emp in the buffer cache. ....

maybe you do, maybe you don't, you cannot say that. Latches are serialization devices that enable access to shared data structures, they are held for incredibly short periods of time to mediate this access. They would never be held that long - no.

Locks as "Process Manager" ?

Edward, February 05, 2007 - 5:37 pm UTC

hi Tom,

I'm thinking of using the lock mechanism as a sort of "Process Manager/Signal":

Sequence of events:

Process_P = "Producer"
Process_C (J2EE program) = "Consumer"

1) Process_P locks Row_1
2) Process_P then get busy processing data that Process_Y will consume.
3) Process_C, will at some point, come by & attempt a "Select for Update" on Row_1 -- so it will wait.
4) Process_P is done (for now) and releases Row_1....proceed to lock Row_2 & do more stuff...etc
5) Process_C - Row_1 lock gone - proceeds to consume Process_P's results, when done, try to lock Row_2

This is because Process_C can not "sleep" or loop around doing nothing waiting for Process_P

do you see any issue with this design ?

Thanks
Tom Kyte
February 05, 2007 - 6:41 pm UTC

yes, it is was too complex - you have advanced queues that do this all for you already.

Alexander the ok, May 07, 2007 - 11:53 am UTC

Hi Tom,

Do you monitor locks and idle sessions on your databases? I was looking for a reliable script, but I'm wondering if it's even necessary in Oracle. Thank you.
Tom Kyte
May 08, 2007 - 11:08 am UTC

idle sessions - no, why ?

locks - only when there is a problem, and the GUI tools have lots of "monitors"

mm, May 16, 2007 - 5:25 pm UTC

hi tom,
i have two questions ....
First:-
i read the explain of the following functions in your book 'Expert one-on-one Oracle' ,but i still confused

* trunc(id1/power(2,16)) rbs
* bitand(id1,to_number('ffff','xxxx'))+0 slot


Second:-
you write in Expert one-on-one Oracle in version 8.1.6

======================================================

We can artificially demonstrate how this works by creating a table with a constrained
MAXTRANS. For example:
tkyte@TKYTE816> create table t ( x int ) maxtrans 1;
Table created.
tkyte@TKYTE816> insert into t values ( 1 );
1 row created.
tkyte@TKYTE816> insert into t values ( 2 );
1 row created.
tkyte@TKYTE816> commit;
Commit complete.
Now, in one session we issue:
tkyte@TKYTE816> update t set x = 3 where x = 1;
1 row updated.
and in another:
tkyte@TKYTE816> update t set x = 4 where x = 2;

Now, since those two rows are undoubtedly on the same database block and we set
MAXTRANS (the maximum degree of concurrency for that block) to one, the second
session will be blocked. This demonstrates what happens when more than MAXTRANS
transactions attempt to access the same block simultaneously. Similarly, blocking may also
occur if the INITRANS is set low and there is not enough space on a block to dynamically
expand the transaction. In most cases the defaults of 1 and 2 for INITRANS is sufficient as
the transaction table will dynamically grow (space permitting), but in some environments
you may need to increase this setting to increase concurrency and decrease waits. An
example of when you might need to do this would be a table, or even more frequently, on
an index (since index blocks can get many more rows on them than a table can typically
hold) that is frequently modified. We may need to increase INITRANS to set aside ahead
of time sufficient space on the block for the number of expected concurrent transactions.
This is especially true if the blocks are expected to be nearly full to begin with, meaning
there is no room for the dynamic expansion of the transaction structure on the block.


=======================================================


i have 10.2.0.1

i try out creating t table with maxtrans 1 attribute,

in session 1> update t set x = 3 where x = 1;
1 rows updated.

in session 2> update t set x = 4 where x = 2;
1 rows updated.

in session 2, there is no any lock occurred ,

thanks in advance,

Tom Kyte
May 17, 2007 - 11:10 am UTC

what are you confused out? they stored two bits of data in that attribute (bummer), and that is the bit shifting we do to get them back out.


in 10g, maxtrans is deprecated, ignored. it is always maxed out.

dba_ddl_locks performance difference between 2 DBs

A reader, May 21, 2007 - 8:51 am UTC

Hi, Tom,
We see a significant difference when querying dba_ddl_locks between 2 databases that are running 8.1.7.4 (HP-UX 11.0) - pretty much similar environments.
The shared_pool_size in the database with the worse performance is actually higher than the other database.

I looked in metalink, ran 8.2 catblock.sql as the note mentioned that 8.2 catblock's dba_waiters is not as slow as 8.1's dba_waiters and that I could run 8.2 catblock.sql for 8i.

That didn't help, either.

Any suggestions? Am I missing something that I'm not looking at (other than concurrent user activity)?
Thanks!
Ravi.

One Clarification

Muhammad Riaz Shahid, June 21, 2007 - 9:56 am UTC

Hello Tom,

Session 1
=========
UPDATE emp
SET depton = 20
WHERE empno = 6399

Session 2
=========
SELECT empno, sal,...
FROM emp
WHERE empno=6399
FOR UPDATE NOWAIT;

Is there an (efficient) way the session 2 can find which user has locked the row he/she is trying to lock?

Best regards,
Tom Kyte
June 21, 2007 - 11:05 am UTC

session 2 cannot since in order to find out who is blocking session 2 - session 2 needs to be blocked, but if session 2 is blocked - session 2 cannot possibly "look" to see who is blocking them (it is after all "blocked")

session 2 can see a list of possible blockers either right before or right after (if they use NOWAIT), but they cannot see precisely "who"

ORA_ROWSCN max value?

Nathan Wray, August 10, 2007 - 10:24 am UTC

Hi Tom, first thanks for the column, it's been a great resource.

We're using ora_rowscn from Java and got into trouble storing it as an Integer. We've switched to Long (2^63-1) and seem to be out of the woods. I've been trying to find the maximum value for ora_rowscn to confirm that we'll be OK in a Long.

I haven't been able to find anything definitive, but the text of ORA-29322 implies that the value is 2^48. Can you confirm the maximum value we can expect from a ORA_ROWSCN?

ORA-29322: SCN string size too long -- maximum size 58 bytes/characters
Cause: Too many characters in specifying the SCN string
Action: Remove all unnecessary characters. Only 15 characters are required for both the hex and decimal representation of the 48-bit SCN.


Thanks again
Nathan

Tom Kyte
August 14, 2007 - 3:05 pm UTC

I would presume a 38 digit number to be the max for all numbers.

an Oracle.sql.number type would work well for you

Thanks!

Edw, August 15, 2007 - 10:02 am UTC


Locks on insert statements

Vinay, August 24, 2007 - 12:34 pm UTC

Hi Tom,
I went through the posts above. I'd like to know if the understanding I got about locks pertaining to insert statements is right:

"If I issue an insert statement on a table that has a unique constraint defined on it, and *simultaneously*, in parallel, issue another insert statement on the same table, the second statement will wait for the first one to complete since the second statement 'does not know' whether the first statement will add records into the unique key columns which the second statement would possibly violate"

Have I understood it right? In that case, the second statement would wait forever till the first statement is committed or rolled-back..

Thanks,
Vinay

Tom Kyte
August 27, 2007 - 3:28 pm UTC

You need not same *simultaneously* or in parallel - both mislead.


If I issue an insert statement in some transaction A on a table that has a unique constraint defined
on it, and in some other transaction B, issue another insert statement on the
same table, the second transaction B will wait for the first one to complete since
the second transaction B 'does not know' whether the first statement will add
records into the unique key columns which the second statement would possibly
violate. The blocked transaction will block and wait until the first transaction A completes (one way or the other - commit or rollback)

Slight modification to my 'understanding' ;-)

A reader, August 27, 2007 - 4:12 am UTC

Hi Tom,
I performed a few tests on my database here and I think I'll need to revisit my 'understanding' of this lock business! What I observed was:

"If an insert statement in session A inserts into a table which has a unique constraint defined on it and session B attempts to insert into the same table, *before* session A commits its transaction, then: session B will wait/block *only* if the values inserted by B violate unique constraints (A has inserted values, but not yet committed. However, if session B is inserting values which do not violate the constraint, then the insert just goes through immediately without any waiting."

Not sure if I'm right this time either - but if I am, then another question comes to mind.. Session A has not yet committed its records - how does session B 'know' what values session A just inserted (but not committed yet)? If I issue a 'select * from ..' statement in session B, the new records inserted by A are invisible to me (since they are uncommitted) but Oracle does seem to know, even for data inserted by a different session.

I'm rather confused as to what exactly is going on here behind the scenes.. please let me know if the information I've given you is insufficient..

Thanks,
Vinay
Tom Kyte
August 27, 2007 - 4:29 pm UTC

the system knows and sees everything

you insert the value "1" into a primary key field. do not commit.

I try to insert the value "1" into a primary key field - well, I cannot put the necessary value into the index Oracle is using under the covers -because you are there, I have to wait right now to find out if you will commit (and I fail, dup val on index) or succeed.


Thanks

Vinay, August 28, 2007 - 7:49 am UTC

Oh ok.. the index that Oracle automatically creates to enforce uniqueness! Thanks a lot!

--Vinay

Single resource deadlock: blocking enqueue which blocks itself

sgcagg, August 28, 2007 - 11:24 am UTC

I am working at a client where they are getting a deadlock. The operation that causes the deadlock deletes from parent and child tables, and the FK is not indexed. I am 99.99% sure that the missing index is the issue, but I was wondering if there is a way to prove it.

The trace file we are getting is different from the ones I have seen in this and other threads.
(include below).
Is there a way to get the more detailed traces which includes the SQl that caused the lock?
I this "single resource deadlock" some how not related to a missing index?
[trace]
Dump file /opt/oracle/product/admin/raca3/udump/raca3_ora_12758.trc
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning and Real Application Clusters options
JServer Release 9.2.0.8.0 - Production
ORACLE_HOME = /opt/oracle/product/9.2
System name: Linux
Node name: fastlane8
Release: 2.4.21-20.ELsmp
Version: #1 SMP Wed Aug 18 20:46:40 EDT 2004
Machine: i686
Instance name: raca3
Redo thread mounted by this instance: 3
Oracle process number: 80
Unix process pid: 12758, image: oracle@fastlane8 (TNS V1-V3)

*** 2007-08-21 18:01:50.028
*** SESSION ID:(31.44953) 2007-08-21 18:01:50.027
Single resource deadlock: blocking enqueue which blocks itself, f 0
----------enqueue------------------------
lock version : 1
Owner node : 0
grant_level : KJUSERCW
req_level : KJUSERPW
bast_level : KJUSERNL
notify_func : 0x87384a6
resp : 0x987a1cb8
procp : 0x93ca8fa8
pid : 0
proc version : 0
oprocp : (nil)
opid : 0
gid : 0
xid : 0 0
dd_time : 0.0 secs
dd_count : 0
timeout : 0.0 secs
On_timer_q? : N
On_dd_q? : N
lock_state : GRANTED
Open Options :
Convert options : KJUSERGETVALUE
History : 0xa7d8d7da
Msg_Seq : 0x99b099d
res_seq : 1340
----------enqueue------------------------
lock version : 1771
Owner node : 2
grant_level : KJUSERCW
req_level : KJUSERPW
bast_level : KJUSERNL
notify_func : (nil)
resp : 0x987a1cb8
procp : 0x93c9d9f8
pid : 12758
proc version : 170
oprocp : (nil)
opid : 0
gid : 1
xid : 5242883 152
dd_time : 0.0 secs
dd_count : 0
timeout : 0.0 secs
On_timer_q? : N
On_dd_q? : N
lock_state : CONVERTING
Open Options : KJUSERDEADLOCK
Convert options :
History : 0x14351435
Msg_Seq : 0x0
res_seq : 0


Mark Bobak's fantastic Hotsos Presentation on Deadlocks

Mark Brady, August 30, 2007 - 9:25 am UTC

I believe what you want to look at is the Deadlock Graph:

Mark Bobak presented a rather simple decision tree which relies on this information. It looks like this:


Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-00040019-000039d0 17 149 X 18 150 S
TX-00050015-000000a2 18 150 X 17 149 S


Based on what type of lock is held and waited on and the enqueue, you can narrow down your possibilities 99% of the time. If it is an unindexed foreign key the Enqueue -- where you see TX here would be TM and the held and waited would be SSX/SX.

Maybe someone like Tom would be able to read the information provided and unearth the same information.

backup controlfile

sudhakar pawar, August 31, 2007 - 3:37 am UTC

when to use backup controlfile clause ?
Tom Kyte
September 04, 2007 - 6:02 pm UTC

when backing up the controlfile of course - which you might want to do

a) after a structural change (added/removed/moved files for example)
b) as part of your overall backup strategy.


Deadlock Graph?

sgcagg, August 31, 2007 - 10:37 am UTC

Pardon my ignorance, but where can I find the Deadlock Graph. Should it also be in the dump file. Is there something I need to turn on so that it is created?
Tom Kyte
September 05, 2007 - 9:07 am UTC

it should be in the trace file, by default.

how to give the username and password,host string in sqlplus

A reader, September 04, 2007 - 1:55 am UTC

hi Tom,
i want to know how to give uname,pwd and host string when am opening the sqlplus in oracle10g client.iam the client here and i have to connect the database with server.
iam waiting for quick reply
thank you
regards
sandhya
Tom Kyte
September 05, 2007 - 1:41 pm UTC

$ sqlplus u/p@db

you just pass them on the command line, or

$ sqlplus /nolog
SQL> connect u/p@db


you use the connect command once in sqlplus.

Lots of 'Row Lock Waits" on the indexes, but no on the based table

Qihua, October 01, 2007 - 6:45 pm UTC

Hi, Tom,

Thanks for distribute your knowledge around. :)
After I run the AWR report in 10G, I found there are lots of "Row Lock Waits" on the index of one table. But the strange thing is that there is no such wait on the base table.

(the stats shown in the section of "Segments by Row Lock Waits" in AWR report)

My questions are:
1: How can it be like that? Under what condition will the "Row Lock Waits" happens to index but not on the base table?

2: Why the value of stats "row lock waits" increase by 2 instead of by 1 each time?
I did a simple test
create table test1 as select * from dba_objects
create index idx_test1 on test1(owner)

first
session 1:
select * from test1 where owner='test' for update
(I check the plan, it first accesses index and then access the table)
then
session 2:
update test1 set owner='test'


I found the incearsed value of "row lock waits" is 2 instead of 1.
That meant the following query result jump from x to x+2 instead to x+1.
select value from v$segment_statistics where statistic_name='row lock waits' and object_name='TEST1'
And even thought it first access index and then table, the "row lock waits" is on the table instead of the index.

Delete hangs

Reader, October 05, 2007 - 11:36 am UTC

Hello Tom,
I am executing the following stmnt in sqlplus:
delete from user where username = 'test';

user table has 4700 records. The above delete is hanging. If I do Cntrl + C, I get the below message:
ERROR at line 1:
ORA-01013: user requested cancel of current operation

and nothing is deleted from the table;

If I run the below select statement, I get the data without any issues:
select username from user where username = 'test';

Can you please advise what I need to check? Please let me know if I am missing some information.

Single resource deadlock: blocking enqueue which blocks itself

Vinu, November 12, 2007 - 8:02 am UTC

I am also having the same issue of "Single resource deadlock: blocking enqueue which blocks itself" as mentioned by "sgcagg from PA". We are using Oracle9i Enterprise Edition Release 9.2.0.7.0 - Production with RAC with 2 nodes and we are getting deadlock for all sorts of statements whether its INSERT,UPDATE,DELETE or SELECT. I understand that the global enqueue is done for inter-instance co-ordination in RAC by ORACLE and not sure what needs to be done at application level. Read about having seperate free lists/groups for each instance, is that the way to go ? Our tables are not partitions and data volume is no that high at this point of time. Can somebody throw some light...

A Sample trace file is below.

/vendor/oracle/product/9.2.0/admin/npgdb/udump/db1_ora_29898.trc
Oracle9i Enterprise Edition Release 9.2.0.7.0 - Production
With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining options
JServer Release 9.2.0.7.0 - Production
ORACLE_HOME = /vendor/oracle/product/9.2.0
System name: Linux
Node name: db-01
Release: 2.4.21-32.ELsmp
Version: #1 SMP Fri Apr 15 21:17:59 EDT 2005
Machine: i686
Instance name: db1
Redo thread mounted by this instance: 1
Oracle process number: 27
Unix process pid: 29898, image: oracle@db-01 (TNS V1-V3)

*** 2007-11-12 11:26:55.689
*** SESSION ID:(32.39041) 2007-11-12 11:26:55.689
Single resource deadlock: blocking enqueue which blocks itself, f 0
----------enqueue------------------------
lock version : 63979
Owner node : 0
grant_level : KJUSERCW
req_level : KJUSERPW
bast_level : KJUSERNL
notify_func : (nil)
resp : 0x8adc83d0
procp : 0x8acbff84
pid : 30154
proc version : 8232
oprocp : (nil)
opid : 0
gid : 0
xid : 1900545 10549
dd_time : 61.0 secs
dd_count : 0
timeout : 0.0 secs
On_timer_q? : N
On_dd_q? : Y
lock_state : CONVERTING
Open Options : KJUSERDEADLOCK
Convert options :
History : 0x1435555a
Msg_Seq : 0x0
res_seq : 0
----------enqueue------------------------
lock version : 62349
Owner node : 0
grant_level : KJUSERCW
req_level : KJUSERPW
bast_level : KJUSERNL
notify_func : (nil)
resp : 0x8adc83d0
procp : 0x8acbc2b0
pid : 29898
proc version : 7090
oprocp : (nil)
opid : 0
gid : 0
xid : 1769473 2416
dd_time : 0.0 secs
dd_count : 0
timeout : 0.0 secs
On_timer_q? : N
On_dd_q? : N
lock_state : CONVERTING
Open Options : KJUSERDEADLOCK
Convert options :
History : 0x51435555
Msg_Seq : 0x0
res_seq : 0

"insert...NOWAIT"

Sokrates, January 03, 2008 - 2:50 am UTC

in regards to
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:839412906735#16075577326436
and
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:839412906735#28098733150600
:

1. do you have the ID of the enhancement request Robert filed ?
2. what do you think of the following solution to solve the here-called "insert nowait" problem ? (which can occur in any multi-user-environment - think of two operators editing the same table manually - and therefore is not only related to not using sequences):

Setup.
create table test(id integer primary key, name varchar2(30));
create unique index tun on test(name);

Problem.
declare
procedure t is
pragma autonomous_transaction;
begin
insert into test(id, name) values(2, 'Sokrates');
commit;
end t;
begin
insert into test(id, name) values(1, 'Sokrates');
t;
end;
/

:
declare
*
FEHLER in Zeile 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 5
ORA-06512: at line 10


Suggested solution other than using dbms_lock mentioned in http://asktom.oracle.com/pls/asktom/f?p=100:11:1276506991017790::::P11_QUESTION_ID:340617419132
:

REM create a loopback link to myself

create database link loopback connect to ... ;

show parameter distributed_lock_timeout
NAME TYPE VALUE
------------------------------------ ----------- ---------------
distributed_lock_timeout integer 1


REM for inserts ONLY use loopback link
declare
procedure t is
pragma autonomous_transaction;
begin
insert into test@loopback(id, name) values(2, 'Sokrates');
commit;
end t;
begin
insert into test@loopback(id, name) values(1, 'Sokrates');
t;
end;
/

declare
*
FEHLER in Zeile 1:
ORA-02049: timeout: distributed transaction waiting for lock
ORA-02063: preceding line from LOOPBACK
ORA-06512: at line 9


Abgelaufen: 00:00:01.04

REM unfortunately we cannot set distributed_lock_timeout to 0, so we have to wait at least 1 second - but better than writing a trigger for each unique index !

Tom Kyte
January 03, 2008 - 11:15 am UTC

I would not want to double the number of inbound connections for this, no.

I do not have his ID either, anything we had would be here on this page... (if he were to have given it to me, it would have appeared here)

Frankly, in the year 2007, with a stateless environment and short transactions - it seems to me that this would not be an issue anymore. In client server with the potential for long running ones - sure, but in a web environment - I don't see it anymore.

thanks

Sokrates, January 03, 2008 - 11:47 am UTC

for answer

ora-00069

Reader, January 19, 2008 - 10:23 pm UTC

Tom,
I did some test but fall into trouble -- could not drop constraint or table. Please see below:
drop table T;

Table dropped.

create table T ( x number ) ;

Table created.

alter table T add constraint CK1 check ( 1=1) disable validate;

Table altered.

alter table T disable table lock;

Table altered.

insert into t values(1);

I got ORA-25128 error which is reasonable. But from now on
I can't drop constraint or drop table t.

alter table T drop constraint CK1;
alter table T drop constraint CK1
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for T

lock table t in row share mode;

alter table t drop constraint CK1;
alter table t drop constraint CK1
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for T
Table(s) Locked.

lock table t in row exclusive mode;

Table(s) Locked.

drop table t;
drop table t
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for T

How can I deal with ORA-00069 and drop constraint or table
at this moment?

Thanks.
Tom Kyte
January 19, 2008 - 11:04 pm UTC

ummm, why not enable table lock for table T?

ops$tkyte%ORA10GR2> create table T ( x number ) ;

Table created.

ops$tkyte%ORA10GR2> alter table T add constraint CK1 check ( 1=1) disable validate;

Table altered.

ops$tkyte%ORA10GR2> alter table T disable table lock;

Table altered.

ops$tkyte%ORA10GR2> alter table t drop constraint CK1;
alter table t drop constraint CK1
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for T


ops$tkyte%ORA10GR2> alter table T enable table lock;

Table altered.

ops$tkyte%ORA10GR2> alter table t drop constraint CK1;

Table altered.

ora-00069

Reader, January 19, 2008 - 10:42 pm UTC

Tom,
For the question above, I also tried:

alter table T enable table lock;

But it just hung there unitl I got

ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

Your help will be greatly appreciated.
Tom Kyte
January 19, 2008 - 11:05 pm UTC

type "commit" in the other session- the one that did the insert, so that you can actually do DDL on the table like that.

Reader, January 20, 2008 - 12:23 pm UTC

Tom,
unfortunately,before I reading you second answer for "commit", I close the session which I did inserting.
So now I still can't do inserting or dropping constraing on this table. Even tried drop table or user, nothing could be done.

I feel fruastrate about it.

Thanks again for you help.

Reader, January 20, 2008 - 1:17 pm UTC

Tom,
For above qusetion, I fall into the very bad loop -- when I do:

alter table T enable table lock;

I get:
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

When I do other alter or drop, I always get

ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for T

I can't get original session to issue "commit" now. It seems
entering into the DEAD END and no way can be OUT.

Please help!

Thanks very much for your time and help.


Tom Kyte
January 20, 2008 - 1:42 pm UTC

kill the original session, find what sessions have locks on it (v$lock)
and then kill them if they are orphaned.

Reader, January 20, 2008 - 2:16 pm UTC

Tom,
Checked the database, there is no original session left and
no other sessions have lock on table t. Also tried to flashback table but can't alter table enable row movement--still got ORA-00069: cannot acquire lock -- table locks disabled for T.

I am wondering if bounce database will get rid of lock on
table t?

Thanks very much.


Tom Kyte
January 20, 2008 - 7:55 pm UTC

and how did you check the database.

Reader, January 20, 2008 - 9:51 pm UTC

Tom,
Basically,checking database by:

select a.sid sid,
a.serial#,
c.spid,
a.machine,
a.username,
a.module,
a.status,
a.logon_time,
b.name command_running,
a.lockwait lock_waiting_for
from v$session a,
v$process c,
sys.audit_actions b
where a.command = b.action
and a.paddr = c.addr
and a.type <> 'BACKGROUND'
order by sid,logon_time;

Do not see any session /username / machine which related to the user who created table t. Also don't see any lockwait from the query result.

Also check it by TOAD and query which join v$session s, v$lock l, sys.obj$ o, sys.user$ u.

My guess is something massed up from user itself internally,
not other user.

Please help.

Thanks again.

Tom Kyte
January 20, 2008 - 10:03 pm UTC

just query v$lock, nothing else.

A reader, January 21, 2008 - 12:14 pm UTC

Tom,
Yes, checked by vSlock as:
SELECT * FROM V$LOCK WHERE request > 0;

SELECT * FROM V$LOCK WHERE request > 0;

SELECT DECODE(request,0,'Holder: ','Waiter: ') ||
sid sess, id1, id2, lmode, request, type
FROM V$LOCK
WHERE (id1, id2, type) IN (SELECT id1, id2, type FROM V$LOCK WHERE request > 0)
ORDER BY id1, request;

Do not find sessions for holder and waiter on it.

What else I can do? Please help.

Thanks.




Tom Kyte
January 21, 2008 - 9:16 pm UTC

please utilize support, I cannot reproduce in any way shape or form and you haven't cut and pasted anything (so I don't really know what you've done)

just query v$lock, no predicates, just see whats in there. nothing else.

dbms_lock.request lock identifier limitation

jc, January 23, 2008 - 6:31 pm UTC

Hi Tom,

In this thread, your followup on "March 4, 2005 - 7am US/Eastern:":

create or replace procedure run_serial( p in varchar2 )
as
l_status number;
begin
l_status := dbms_lock.request
( id => 123, -- use whatever you like,
-- but use the same in both places
lockmode => dbms_lock.x_mode,
release_on_commit => FALSE );

For the lock id you said "use whatever you like..". Is there any *reserved* lock identifiers used by Oracle internal that we should not use? Please confirm.

Thanks!!


Tom Kyte
January 23, 2008 - 8:29 pm UTC

http://docs.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_lock.htm#i1002556

... User assigned lock identifier, from 0 to 1073741823, ...

Thanks!!

jc, January 25, 2008 - 3:09 pm UTC


Trickey question regarding Update Statement!!

shakeel, January 30, 2008 - 11:30 am UTC

Please explain why these two cases's are different, Ideally they should be same ??
case:1
CREATE TABLE SKL_TEST1( COL1 NUMBER, COL2 NUMBER, COL3 NUMBER);

INSERT INTO SKL_TEST1 VALUES (1,2, 3);
UPDATE SKL_TEST1 SET COL3=COL3+10,COL1=COL2*COL3;
COMMIT;


case:2
drop table skl_test1;
CREATE TABLE SKL_TEST1( COL1 NUMBER, COL2 NUMBER, COL3 NUMBER);
INSERT INTO SKL_TEST1 VALUES (1,2, 3);
UPDATE SKL_TEST1 SET COL3=COL3+10;
UPDATE SKL_TEST1 SET COL1=COL2*COL3;

commit;

Please explain why the COL1 output is different is both the case's

Thanks in Advance!!

Shakeel G
IT Consultant
Warsaw, Poland.






Tom Kyte
January 30, 2008 - 1:47 pm UTC

think about it...

sql is not a procedural language, it is a functional language.


update has a READ component.
update has a WRITE component.

the read component happens... then the write.

UPDATE SKL_TEST1 SET COL3=COL3+10,COL1=COL2*COL3;

col3, col10, col2 are READ OUT (because they are on the right hand side, an RVALUE)

then, col3 is set to a new value at the same time col1 is set to a new value - using the RVALUES read above.


a "swap" in sql is easy to write and needs no temporaries:

update t set a = b, b = a;

A and B are read
then A and B are simultaneously modified - using the previously read values.

confusion on locking situation

A reader, January 31, 2008 - 9:39 am UTC

hi tom,

i'm confused about the following locking situation in one of my databases. 

could you imagine what's going on there?

SQL> select * from dba_blockers;

HOLDING_SESSION
---------------
            276

Elapsed: 00:00:00.01
SQL> select * from dba_waiters;

WAITING_SESSION HOLDING_SESSION LOCK_TYPE                  MODE_HELD  MODE_REQUE   LOCK_ID1   LOCK_ID2
--------------- --------------- -------------------------- ---------- ---------- ---------- --------
            276             276 Distributed Xaction        Exclusive  Exclusive         577          0

Elapsed: 00:00:00.01
SQL> select * from v$lock where sid = 276;

ADDR             KADDR                   SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- --------
070000000EA4B2A8 070000000EA4B2C8        276 DX        577          0          0          6     502985          0
070000000EA4B110 070000000EA4B130        276 DX        577          0          6          0     504026          1

Elapsed: 00:00:00.01
SQL> select * from v$locked_object where session_id = 276;

no rows selected

Elapsed: 00:00:00.00
SQL> select * from v$transaction where ses_addr in (
  2  select saddr from v$session where sid = 276)
  3  /

no rows selected

Elapsed: 00:00:00.00
SQL> select sid, row_wait_obj#, row_wait_file#, row_wait_block#, row_wait_row#
  2  from v$session where sid = 276;

       SID ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW#
---------- ------------- -------------- --------------- -------------
       276         13528              5               0             0

Elapsed: 00:00:00.00
SQL> column object_name format A20
SQL> select owner, object_name, object_type
  2  from   dba_objects
  3  where  object_id = 13528;

OWNER                          OBJECT_NAME          OBJECT_TYPE
------------------------------ -------------------- ------------------
ADAT                           T_ANBAHNUNGEN        TABLE

Elapsed: 00:00:00.00
SQL> 

Cannot ALTER TABLE ... ENABLE TABLE LOCK

Tony Killen, February 07, 2008 - 10:41 am UTC

Hi Tom,
I was just putting together a test case to see if a single column foreign key index on a table could be converted to a composite (2 column) foreign key index (with the original index column as the leading edge). I suspected it would but wanted to test this. (I'm a big fan and your advice is starting to stick!)

I tried your "trick" on p475 of Expert Oracle Database Architecture to disable the table locks on the child table, then update the parent table and see what happened with both types of index and with no index.

I issued ALTER TABLE <child table name> DISABLE TABLE LOCK, ran my first test, then ended up in the same situation as a couple of your previous reviewers on this thread.

When I issued ALTER TABLE <child table name> ENABLE TABLE LOCK, I got a "ORA-00054: resource busy and acquire with NOWAIT specified". I tried looking for locks on the child table in V$LOCK - nothing there. I couldn't drop the table as it was under a foreign key constraint and I needed a table lock to drop the constraint. Then I deleted (and committed) all the rows in the table. Again I got ORA-54 on the empty table trying to re-enable the table lock. Scary!

Then I saw this in Note:341124.1 on metalink:
"If you use the DISABLE TABLE LOCKS feature, then you stop oracle taking out any TM locks when a table is updated. If the user tries to ENABLE table locking again, we have no way of knowing if anyone is actually updating the table at this time (because there are no TM locks). The only solution is to wait for all active transactions to complete."

Which does make complete sense.

In Bug# 2899179 it says that there is now a note in the ALTER TABLE section of the SQL Reference:
"Caution: Oracle waits until active DML transactions in the database have completed before locking the table. Sometimes the resulting delay is considerable." But I couldn't see it online.

This is supposedly fixed in 10 but I'm on 9.2.0.6. The DB I'm using is multi-user and I currently have five rows in v$transaction and have batch updates running in the background. I'll have to wait for no activity this evening to fix this.

I think you should put a health warning on this "trick". It would have been disastrous for me on a real table. (And I know you will say "This is why we test!").

I guess you may not have seen this before on your single user DB as you probably didn't have any outstanding transactions when disabling/enabling table locks.

I've had a frustrating (but educating!) day.

This is my first post here so I should thank you for all your help in the past and no doubt long into the future!

Tony.
Tom Kyte
February 07, 2008 - 11:43 am UTC

thank you very much - appreciate the followup

Cannot ALTER TABLE ... ENABLE TABLE LOCK

Tony Killen, February 07, 2008 - 11:42 am UTC

And here is the test case (it's not fixed in 10.2!):
-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> create table t1 (x int);

Table created.

SQL> alter table t1 disable table lock;

Table altered.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0
-->>>>>>>>>>>In separate session:>>>>>>>>>>>>>
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> create table t2 (x int);

Table created.

SQL> insert into t2 values (99);

1 row created.
-- And leave this uncommitted

-->>>>>>>>>>>In original session:>>>>>>>>>>>>

SQL> l
  1* select count(*) from v$transaction
SQL> /

  COUNT(*)
----------
         1

SQL> alter table t1 enable table lock;
alter table t1 enable table lock
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

-->>>>>>>>>>>In the other session:>>>>>>>>>>>
SQL> commit;

Commit complete.
-->>>>>>>>>>>And back in the original session:>>>

SQL> select count(*) from v$transaction;

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

SQL> alter table t1 enable table lock;

Table altered.

SQL>

-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Xinmin, March 02, 2008 - 1:11 am UTC

Hi Tom,
ORA-02049 raises in the following case that I don't understand. Here is the script. please note
1) add index on foreign key, the problem goes away. But why, I don't update primary key.
2) fk not on leading column of composite index can solve this issue, why? Thank you for your time in advance. -Xinmin
--
1. in first database
create table mytab1(id number primary key, name varchar2(32)) tablespace idm_dim_ts
insert into mytab1(id, name) values(1, 'name1');
insert into mytab1(id, name) values(2, 'name2');
grant select on mytab1 to ida_dbl_user;
--
2. create two tables in second database
create table mytab1(id number primary key, name varchar2(32)) tablespace icm_ts
insert into mytab1(id, name) values(1, 'name1');
insert into mytab1(id, name) values(2, 'name2');
insert into mytab1(id, name) values(3, 'name3');
commit;
--
create table mytab2(id number primary key, mytab1_id number, name varchar2(32)) tablespace icm_ts
alter table mytab2
add constraint mytab2_c foreign key (mytab1_id)
references mytab1 (id);
insert into mytab2(id, mytab1_id, name) values(1, 1, 'name11');
insert into mytab2(id, mytab1_id, name) values(2, 1, 'name12');
insert into mytab2(id, mytab1_id, name) values(3, 2, 'name21');
commit;
--
3. open new session to update
update mytab2 t1 set t1.mytab1_id = 1 where t1.mytab1_id = 3
--
4. opne another session
merge into mytab1 t1
using ( select id, name
from idm_owner.mytab1@idm
) t2
on ( t1.id = t2.id )
when matched then
update set t1.name = t2.name
when not matched then
insert (id, name )
values (t2.id, t2.name);

Tom Kyte
March 02, 2008 - 11:18 am UTC

Looks like I need to update my "when you need an index on a foreign key"

The merge is demanding it - no need for a database link or anything.


ops$tkyte%ORA9IR2> update mytab2 t1 set t1.mytab1_id = 1 where t1.mytab1_id = 3;

0 rows updated.

ops$tkyte%ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4    merge into mytab1 t1
  5    using ( select id, name from remote_mytab1) t2
  6    on ( t1.id = t2.id )
  7    when matched then update set t1.name = t2.name
  8    when not matched then insert (id, name ) values (t2.id, t2.name);
  9
 10    commit;
 11  end;
 12  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4


ops$tkyte%ORA9IR2> rollback;

Rollback complete.

ops$tkyte%ORA9IR2> create index mytab2_idx on mytab2(mytab1_id);

Index created.

ops$tkyte%ORA9IR2> update mytab2 t1 set t1.mytab1_id = 1 where t1.mytab1_id = 3;

0 rows updated.

ops$tkyte%ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4    merge into mytab1 t1
  5    using ( select id, name from remote_mytab1) t2
  6    on ( t1.id = t2.id )
  7    when matched then update set t1.name = t2.name
  8    when not matched then insert (id, name ) values (t2.id, t2.name);
  9
 10    commit;
 11  end;
 12  /

PL/SQL procedure successfully completed.


the merge apparently has a larger locking issue - you need not even reference the primary key at all

ops$tkyte%ORA9IR2> alter table mytab1 add idcopy number;

Table altered.

ops$tkyte%ORA9IR2> update mytab1 set idcopy = id;

3 rows updated.

ops$tkyte%ORA9IR2> commit;

Commit complete.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> update mytab2 t1 set t1.mytab1_id = 1 where t1.mytab1_id = 3;

0 rows updated.

ops$tkyte%ORA9IR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4    merge into mytab1 t1
  5    using ( select id, name from remote_mytab1) t2
  6    on ( t1.idcopy = t2.id )
  7    when matched then update set t1.name = t2.name
  8    when not matched then insert (id, name ) values (t2.id, t2.name);
  9    commit;
 10  end;
 11  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4


So, the list is now:

o update the parent primary key
o delete from parent
o merge into parent

A reader, March 04, 2008 - 12:40 am UTC

Hi Tom,
Thanks for replies.
There was a typo -
2)foreign key that is not a leading column of a composite index can _not_ solve this issue, why?

Tom Kyte
March 04, 2008 - 7:20 am UTC

because it needs to be on the leading edge so we can find it without having to search the ENTIRE structure;


create index t_idx on (a,b,c,d) - we can find (a), (a,b), (a,b,c) - but not (b), not (c), not (d) without looking at the entire thing (in general, yes I know about skip scans but for locking and concurrency purposes they do not count)

Strange SQL Performance

A reader, April 12, 2008 - 9:27 am UTC

Tom,
Thanks for your help to the oracle community. We have a verys strange situation at our work. We have an insert select which runs in 20 seconds. But when you run it as
begin
insert select
commit
end it runs forever...If you can atleast point as to where to look for that would be great
Thanks

Tom Kyte
April 13, 2008 - 8:35 am UTC

probably when you do it one way - you are doing it differently (eg: binds in one case, no binds in another).

you would start by comparing the row source operation found in the tkprof after tracing both of them.

but I will guess that the two queries are in fact entirely different syntax wise... not the same at all. But you'd have to share them with us

Lock not getting released

Deepak, April 17, 2008 - 5:20 am UTC

Hi Tom,

I have done the following ...

SQL> create table verybigtab as select * from all_objects;

SQL> insert into verybigtab 
select * from verybigtab;

SQL> commit;

-- repeated the above insert/commit statements many times to have a table with 80M rows...

Then I tried to create an index on the OBJECT_ID column. I got the resource busy exception. 

I was the only user accessing the DB (Only a single session for the user in question).

Now after getting the exception I tried to queried V$LOCK and found that the table has a TM lock with LMODE 3.

Now the question is after COMMITing the transaction why was there a lock on that table?

Then I killed the session and the V$LOCK entry persisted for sometime.

Please help me in understanding the concept behind this. 


 

Tom Kyte
April 17, 2008 - 7:50 am UTC

I believe you made a mistake somewhere

eg: you used one session to do the inserts. You committed, but forgot to commit the last time. then, in another session, you tried to create the index.

That is the only thing I can see happening here.

Mutex

Suraj Sharma, April 17, 2008 - 10:27 pm UTC

Hi Tom,

What are Mutex and how those are different from latches or other Oracle Locks?
Tom Kyte
April 17, 2008 - 10:48 pm UTC

mutex - MUTual EXclusion

it is a way to implement a lock or latch. Now we use them for latching only.

they are a way to implement a lock or latch. Like a semaphore is, or a test and set instruction is.

doubt on Toad Locking

Ravi Tej, April 21, 2008 - 11:35 pm UTC

Hi Tom ,

We are using TOAD ver 9.0.1.8 in our Production system and recently we had an unusual scenario of a select query creating lock.The scenario is we ran a select query and later tried to monitor the progress of SID (by navigating to Schema browser and later clicked on Lock Tab present over there instead of current statement ).Later a developer came up saying "when we navigate to Locks Tab in schema browser ORACLE creates a Lock ". But i suspect that readers shouldn't block writers irrespective of the Program Type(TOAD/SQLPLUS).so thought of raising a concern in your forum .

Thanks
Ravi Tej

Tom Kyte
April 23, 2008 - 5:42 pm UTC

ummm, I've never used toad. Unless toad was doing a "select for update", table would not be "locked"

if you have a problem with the way toad works, I'd suggest a quest forum?

Toad Locking

Ravi Tej, April 24, 2008 - 1:25 am UTC

Thnks Tom for the reply.
we were running just a select Query .we are trying to replicate the same scenario on our Dev Database if problem persists we would use Quest forum as suggested by You .

Regards
Ravi Tej

an expiration functionality

Vipin, April 24, 2008 - 10:31 am UTC

Tom,

SELECT FOR UPDATE is one of the coolest features of Oracle (ofcourse like any other feature, only if it is used in the right way, in right place..)

Do we have an expiration functionality for this type of locking. What I mean here is, if a user locks a record using SELECT FOR UPDATE NOWAIT, is there any "clause" which will expire this lock after a specific time -say 10 minutes- just so that there are no ever lasting locks in the system.

Thanks for this site which is a quick resort for any oracle lover.
Tom Kyte
April 28, 2008 - 12:12 pm UTC

locks are owned by the session. as long as that session is alive, it is the only thing that can release them.

if you want, you can use a resource profile to kill idle sessions, thus releasing any locks they might have had.

SELECT Blocking Inserts

MK, June 26, 2008 - 1:39 pm UTC

Hi Tom,
I am trying to identify some blocking sessions in the database and run the following query

 select s.blocking_session, s.sid, s.serial#, s.wait_class, s.seconds_in_wait, p.spid, p.pid
 From gv$session s,
      gv$process p 
 where s.paddr = p.addr
 and blocking_session is not NULL
 order by blocking_session;


I keep noticing that the Blocking Session's SQL ID maps to a Select statement that needs to be fixed and is doing hard parses due to the lack of bind variables. But the sessions that it blocks are insert statements into completely unrelated tables. These insert statements come in from a web application cluster which makes the connections in the database to grow out of hand! I am wondering how long running select statements can cause "Application Waits" to take place for subsequent Insert statements? Can you please explain this odd behavior?

Your help would be most appreciated.

Thanks in advance,
MK

Tom Kyte
June 26, 2008 - 4:28 pm UTC

you are seeing the SQL the session is CURRENTLY execution.

do this

create table t ( x int primary key );
insert into t values ( 1 );
select * from t, all_objects, all_objects, all_objects;



(and do that in your OWN TEST DATABASE - think before you type! :) )


now, in another session - issue:

insert into t values ( 1 );


it'll block, but it isn't blocking on the select, it is blocking on the insert we did BEFORE we selected.

v$lock will show you what objects that session that is running a long running query has locks on - those locks were obtained via insert, update, delete, merge and/or select for update or lock table commands.

blocking query

MK, June 27, 2008 - 5:19 am UTC

Thanks for that explanation. Is there a query that can give me exactly which session is blocking the sessions in wait? I will try and get a better understanding of the v$lock table in the meanwhile but I am sure you can give me a better more reliable way of finding these sessions, processes that are causing locking and hence blocking other sessions. I see a lot of "Row Lock Contention" in the ADDM reports that I run and a lot of gc enqueue waits in the RAC logs. The logs list the particular update statement that is responsible but when I look at the statement being run after some Log Mining I see nothing wrong with the updates .. they seem to be updating different rows. So I am at a loss at understanding why there is the row lock contention issues when different rows get modified. Could it be that these rows are placed on the same physical block and hence contention?

Two questions then.
1. How do I find out exactly what session is blocking others and the sessions that are waiting on this block due to locking to end or commit?

2. Why do updates from concurrent sessions to the DB to the same table but different rows (different rowids) complain about "Row Lock Contention" between these updates?

Thanks for the previous answer. Oracle's Multiversioning model has no concept of read locks etc so I don't think we should ever have the situation where queries block or get blocked by locking DML. Am I right?

Tom Kyte
June 27, 2008 - 9:18 am UTC

you have that query, you know exactly what session is blocking the other session, and you know that right now they are running a long running query.


You have the query you need already. Not sure why you don't think this is so??




1) you have it

2) not sure what you mean



last paragraph: correct

blocking query

MK, June 27, 2008 - 11:23 am UTC

Nope not satisfied ... sorry! :)

About 1, You mentioned that it could be a DML that occurred prior to the select statement that shows up in the SQL I sent you as the "blocking session" that is truly blocking sessions. Hence I would expect that to find the "true" blocker we would have to join the v$lock table into the query somehow to see which DML actually blocks other DMLs. Is this a correct assumption?

In part 2, I explained that there are concurrent sessions that update a single table but different rows. So why do the ADDM and AWR reports point out a problem with the update statements on this table mentioning that a majority of these updates were waiting because of "row lock contention" (wait class)? I just want you to help me understand what could be happening behind the scenes with this situation I am noticing.

Cheers,
MK
Tom Kyte
June 27, 2008 - 11:33 am UTC

above I stated factually that it would be a modification (select is dml) that the session executed before starting their current SQL statement.

The true blocker IS THE TRANSACTION. The transaction belongs to a session. A session executes many sql statements.

do this:

create table t ( x int primary key );
insert into t values ( 1 );
select count(*) from all_objects, all_objects, all_objects;


whilst that is running, in another session:

insert into t values ( 1 );


Now, that will block, it will be be blocked by the session running a query, it will be blocked by a session running a query right after it ran an insert which is blocking you.


DML doesn't block other DML. Locks acquired by a transaction block other DML. transactions belong to sessions, your session block another session.



In part 2 - I do not "believe" that they are updating different rows. I based that on the fact that you have blocking and locking issues!!!!! You are modifying the same stuff at the same time - you have to be, everything you describe points that way. I think you need to go back to the application and look deeper into it.

Locking + Auditing

MK, July 03, 2008 - 4:58 am UTC

You were right about the application trying to modify the same row from concurrent sessions and from different application servers. I found this out by turning on FGA on the table that was getting the most row locks and deadlocking exceptions.

--- Setting the policy
exec dbms_fga.add_policy('xxx','customer_store','customer_store_access',statement_types => 'update');

--- In the dba_fga_audit_trail table
update CUSTOMER_STORE set DATA_CLASSIFICATION=:1, CREATED=:2, INSERTED=:3, MODIFIED=:4, OBJECT_CREATED_DATE=:5, OBJECT_MODIFIED_DATE=:6, OBJECT_LAST_USED_DATE=:7, OBJECT_GUID=:8 where CUSTOMER_CLIENT_ID=:9 and OBJECT_ID=:10 and OBJECT_KIND=:11 and MODIFIED=:12

--- SQL Bind values I see 
SQL_BIND
----------
 #1(6):400000 #2(32):75ade628c0a801220180a552d346521e #3(6):233618 #4(6):188600 #5(2):62



I was wondering why I am seeing the sql_bind column in "dba_fga_audit_trail" as the above when I clearly have 12 values that should be bound in. Of special interest would be the date parameters? Is there something I have to do to make this policy better to capture the exact bind values?
I notice that the values that are being shown in the bind variables are shown in the incorrect order as well but I do understand which column values they are trying to pass values to.

Thanks.
Tom Kyte
July 07, 2008 - 9:54 am UTC

I don't know your datatypes - the formats should be "nice" in general. You might need to query fga_log$ directly for really long bind strings

consider:

ops$tkyte%ORA11GR1> create table t ( a int, b date, c timestamp, d varchar2(4000) );

Table created.

ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> insert into t values ( 1, sysdate, systimestamp, 'a' );

1 row created.

ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> begin
  2  DBMS_FGA.ADD_POLICY(
  3  object_schema => user,
  4  object_name   => 'T',
  5  policy_name   => 'chk_hr_emp',
  6  audit_condition => 'a>0',
  7  enable               =>  TRUE);
  8  end;
  9  /

PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> declare
  2          l_a int := 1;
  3          l_b date := sysdate;
  4          l_c timestamp := systimestamp;
  5          l_d varchar2(4000) := rpad('d',3999,'d')||'X';
  6  begin
  7          for x in (select * from t where a = l_a and b <= l_b and c <= l_c and d < l_d )
  8          loop
  9                  null;
 10          end loop;
 11  end;
 12  /

PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR1> select sql_bind from dba_fga_audit_trail;

SQL_BIND
-------------------------------------------------------------------------------
 #1(1):1 #2(15):7/7/2008 9:41:2 #3(28):07-JUL-08 09.41.02.300895 AM #4(4000):dd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddd


ops$tkyte%ORA11GR1> set long 10000
ops$tkyte%ORA11GR1> select LSQLBIND from sys.fga_log$;

LSQLBIND
-------------------------------------------------------------------------------
 #1(1):1 #2(15):7/7/2008 9:41:2 #3(28):07-JUL-08 09.41.02.300895 AM #4(4000):dd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddddddddddddddddddX



DISABLE TABLE LOCK

ArchitK, July 22, 2008 - 12:22 am UTC

Hi Tom,

I have a query on DISABLE TABLE LOCK stuff mentioned in your book "Expert one-on-one Oracle". I was trying to figure out what operations are permitted/not permitted with DISABLE TABLE LOCK. Following is my test script and output from SQL.
SQL> !cat test.sql
 drop table dump_table;
 create table dump_table (a number);
 ALTER TABLE dump_table disable TABLE LOCK;
 alter table dump_table add(b varchar2(10));
 create index dump_i on dump_table(a);
 alter table dump_table modify (a not null);
 drop index dump_i;
 ALTER TABLE dump_table enable TABLE LOCK;
 drop index dump_i;

SQL> @test.sql

Table dropped.


Table created.


Table altered.

 alter table dump_table add(b varchar2(10))
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for DUMP_TABLE



Index created.

 alter table dump_table modify (a not null)
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for DUMP_TABLE


 drop index dump_i
            *
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for DUMP_TABLE



Table altered.


Index dropped.


From above test I could conclude, with DISABLE TABLE LOCK in place:-
1) New columns can not be added.
2) Existing columns can not be modified
But I could not understand following,
3) Index creation is possible but index could not be dorpped. Does it mean that DDL type lock is required on table to drop the index but not to create index.

Could you please explain this behavior? Thanks for great book and support to oracle community.

Thanks,
ArchitK
Tom Kyte
July 22, 2008 - 11:20 am UTC

you can conclude in the release you were using the above... yes.

We attempt to use as few locks as possible for each operation - adding the index just didn't need that one.

Locks in Oracle 10g Release 2 (10.2.0.3.0)

Rajagopal, August 07, 2008 - 4:49 am UTC

Hi Tom,

I have a table with more than 50 million rows which has partitions and subpartitions. There are multiple inserts into this table every day and data is deleted once in a week.
I used to get the error 'ORA-00054: resource busy and acquire with NOWAIT specified' frequently and my DBA asked me to be patient since this problem will be solved in 10g Release 2.In my DBA's opinion.although I am trying to make the indexes unusable in a specific partition and data is being inserted into some other partition, Oracle loks the entire table.
We now upgraded to Oracle 10g Release 2(10.2.3.0)
but I still get the error. I realised that the SQL Plus version is 10.1.0.5.0. Could this be causing the problem?.
By the way, my procedure is failing when trying to make the bit map indexes unusable.

I would like to get your opinion on this issue.

Tom Kyte
August 07, 2008 - 1:25 pm UTC

and you tell us nothing about the operation you are actually trying to do

or why the dba thinks it is happening now and "is fixed"

a delete will not result in an ora-54 under any normal conditions, a delete would block.

so, you must not be using delete but rather drop or truncate.

but we really have no idea.

is it correct?

Andrea, September 01, 2008 - 5:51 am UTC

Hi, Mr Kyte.

If I would know who are blocker and blockee, then I have to write this your statement.

tkyte@TKYTE816> select 
           (select username from v$session where sid=a.sid) blocker,
  2         a.sid,
  3        ' is blocking ',
  4         (select username from v$session where sid=b.sid) blockee,
  5             b.sid
  6    from v$lock a, v$lock b
  7   where a.block = 1
  8     and b.request > 0
  9     and a.id1 = b.id1
 10     and a.id2 = b.id2
 11  /

BLOCKER         SID 'ISBLOCKING'  BLOCKEE         SID
-------- ---------- ------------- -------- ----------
TKYTE             8  is blocking  TKYTE             9


If I understood, correctly how to read v$lock, then I can write this query and the result is the same but in other format. This is correct? Have this statement any performance problems?

SELECT SID, TYPE, lmode, request, BLOCK, id1, id2, 
 CURSOR (SELECT SID, TYPE, lmode, request BLOCK, id1, id2
            FROM v$lock waiter
            WHERE waiter.id1 = blocker.id1
            AND waiter.id2 = blocker.id2
            AND BLOCK = 0) STATEMENT
  FROM V$LOCK blocker
  WHERE BLOCK > 0


       SID TY      LMODE    REQUEST      BLOCK        ID1        ID2 STATEMENT
---------- -- ---------- ---------- ---------- ---------- ---------- --------------------
       315 TX          6          0          1    1638424    1691973 CURSOR STATEMENT : 8

CURSOR STATEMENT : 8

       SID TY      LMODE      BLOCK        ID1        ID2
---------- -- ---------- ---------- ---------- ----------
       140 TX          0          6    1638424    1691973
       185 TX          0          6    1638424    1691973
       306 TX          0          6    1638424    1691973
       318 TX          0          6    1638424    1691973
       450 TX          0          6    1638424    1691973
       490 TX          0          6    1638424    1691973
       728 TX          0          6    1638424    1691973

7 rows selected.

       222 TX          6          0          1    1835037    1596972

       SID TY      LMODE    REQUEST      BLOCK        ID1        ID2 STATEMENT
---------- -- ---------- ---------- ---------- ---------- ---------- --------------------
       489 TX          6          0          1    1441818    1591207 CURSOR STATEMENT : 8

CURSOR STATEMENT : 8

       SID TY      LMODE      BLOCK        ID1        ID2
---------- -- ---------- ---------- ---------- ----------
        44 TX          0          6    1441818    1591207
       189 TX          0          6    1441818    1591207


P.S.
I apologize for my English

Tom Kyte
September 01, 2008 - 1:10 pm UTC

Your query and my query are not the same (different predicates), but if you like yours and it provides you what you want...


"Side effect" of not storing row-level locks

John Stegeman, September 02, 2008 - 8:09 am UTC

Hi Tom,

For some reason, the brain started grinding today when I read this post. As you have said, Oracle doesn't store a master list of row locks anywhere. This is indeed efficient, but can lead to a situation where a session is blocked, even though it doesn't really need to be. For example:

session 1:

SQL> create table x(a number);              
                                            
Table created.                              
                                            
SQL> insert into x values(1);               
                                            
1 row created.                              
                                            
SQL> insert into x values(2);               
                                            
1 row created.                              
                                            
SQL> commit;                                
                                            
Commit complete.                            
                                            
SQL> update x set a =3 where a=2;           
                                            
1 row updated.                              
                                            
SQL> savepoint foo;                         
                                            
Savepoint created.                          
                                            
SQL> update x set a=5 where a=1;            
                                            
1 row updated.  


session 2:

update x set a=6 where a=1; 

(blocks)

session 1:

SQL> rollback to savepoint foo;  
                                 
Rollback complete.               


technically, session 2 *could* unblock at this time, but doesn't...

Thanks for all you do on this site.


Tom Kyte
September 02, 2008 - 11:56 am UTC

yes, that is documented. When we block, we block on a session.

Given that this is a fairly rare edge case, I'm happy to infrequently have this happen given the benefits of not storing those locks in a lock manager.

workaround

Sokrates, September 03, 2008 - 5:36 am UTC

and there is an easy (undocumented) workaround:
Session 1 could just
rollbac to savepoint foo;
instead of
rollback to savepoint foo;

which would unblock Session 2
compare
http://laurentschneider.com/wordpress/2008/08/difference-between-rollbac-and-rollback.html

Haha !
Only joking

Exclusive loack by update

Mayank, November 17, 2008 - 1:56 am UTC

Hi Tom,

It was a too good article to understand the locking.
I have got a weired problem rather. Let me explain you.

I have a table called xyz. From Session A I issue an update command that updates 1 row of id=1. Now from Session B I issue another command that also updates row of id=2, but this transaction hangs and also locks the table in Exclusive mode untill I issues a rollback in Session A.

Usually update should put a lock on the effected row only and other rows should be free to use by other sessions.

I am using read commit mode in my both the sessions but the application for the poc. But in actual environment the application will be using serializable mode and problem could be worse. Even now the table is used by an application that changes the mode to serilazibale.

Any help on this will be much appreciated.


Tom Kyte
November 18, 2008 - 7:19 pm UTC

you will have to provide an example because what you say flies in the face of what should happen. So, you must either

a) be doing something other than what you say
b) observing something 'incorrectly'


Strange Behaviour

A reader, November 17, 2008 - 12:06 pm UTC

Hi Tom,

Its been really surprising to see this, with a session locking both Parent and children table and trying to disable the foreign key constraint gets ORA-00054 error.

Application is still writing to these tables but when I have taken those exclusive locks then disabling constraint should have been succeeded without any errors.

Can you please explain this behaviour.

SQL> Lock table OLTP.N_EVENT,OLTP.N_Runs in exclusive mode;
Table(s) Locked.

SQL> alter table OLTP.N_EVENT disable constraint NEVENT_FKEY_NRUN;
alter table OLTP.N_EVENT disable constraint NEVENT_FKEY_NRUN
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified
 
Which resource is busy as both of the tables have been taken for an excl. lock. It doesn't make any sense to me that after 5 secs the same statements succeeded.

Appreciate your thoughts!

Tom Kyte
November 18, 2008 - 7:26 pm UTC

the lock table is meaningless in this context

the first thing, the very first thing the alter to disable the constraint does is.....

commit;

which releases the locks. We just discussed this exact question elsewhere on this site, please refer to my complete answer there. (you asked it there)

A reader, November 18, 2008 - 9:16 am UTC

The ADDM report gives following results:

FINDING 1: 64% impact (61090 seconds)
-------------------------------------
SQL statements consuming significant database time were found.

RECOMMENDATION 3: SQL Tuning, 12% benefit (11675 seconds)
ACTION: Run SQL Tuning Advisor on the SQL statement with SQL_ID
"d3dkahxp1p0j0". RELEVANT OBJECT: SQL statement with SQL_ID d3dkahxp1p0j0 and PLAN_HASH 484748492

FINDING 3: 25% impact (23733 seconds)
-------------------------------------
SQL statements were found waiting for row lock waits.

RECOMMENDATION 1: Application Analysis, 25% benefit (23733 seconds)
ACTION: Trace the cause of row contention in the application logic. Use
given blocked SQL to identify the database objects involved.
Investigate application logic involving DML on these objects.
RATIONALE: The SQL statement with SQL_ID "d3dkahxp1p0j0" was blocked on
row locks.

The statements in both the finding are same and it is simple update statment which is updating in a tables based on it primary key. Based on this please reply following questions
1. We are thinking to kill the blocking session by execute a job after ever five minutes so that row lock waits status should be resolved. Is this right?
2. In ADDM report we find row locks on 5 tables and some queries with high CPU but application response is very slow. If we restart the application server then application behaving normal.Is this all happens due to locks on five tables?
3. There are 10 tables with 8 millions records in each, one query which joine these 10 tables takes high CPU cost. Is this right to apply partitioning on these tables?



Tom Kyte
November 18, 2008 - 7:46 pm UTC

1) why not figure out why the HECK you have something holding the lock for a really long period?

Killing a session is rather like using an atom bomb to crack open a walnut, it'll work but has a couple of obvious downsides to it.

why not actually analyze the logic and determine WHY you are in the situation you are in????

block or row attribute

gajanan, November 19, 2008 - 2:04 am UTC

Dear tom,
Seems little late on this thread to ask this question,
You have mentioned that lock is stored as an attribute in the block header in the transaction slot, but is row header also used to store row lock status?
Tom Kyte
November 21, 2008 - 5:47 pm UTC

the transaction list in the header of the block tells us which things are locked by what transactions on the block. That is all.

When you go to a block, you see the block header. You know what transactions are a) active, b) done. So, you can quickly tell which transactions have information locked on that block and the transaction list points to the bits of the block that are owned by that transaction.

Blocking session count

A reader, February 04, 2009 - 1:10 pm UTC

Tom,

We are going to monitor "Blocking session count" for set of oracle databases starting with 8i (yes, we still have some of them).

I found following script on the Metalink

SELECT SUM(num_blocked)
FROM (SELECT id1, id2, MAX(DECODE(block, 1, sid, 0)) blocking_sid,
SUM(DECODE(request, 0, 0, 1)) num_blocked
FROM v$lock
WHERE block = 1 OR request > 0
GROUP BY id1, id2)
GROUP BY blocking_SID

This script will count all session blocked currently. How I can find only the session waiting for e.g. more then 180 seconds? Again 90 % of our databases are 10g, but we still have some 8i and 9i.
Tom Kyte
February 04, 2009 - 1:31 pm UTC

this is the query I use:

tkyte@TKYTE816> select 
           (select username from v$session where sid=a.sid) blocker,
  2         a.sid,
  3        ' is blocking ',
  4         (select username from v$session where sid=b.sid) blockee,
  5             b.sid
  6    from v$lock a, v$lock b
  7   where a.block = 1
  8     and b.request > 0
  9     and a.id1 = b.id1
 10     and a.id2 = b.id2
 11  /



you can pull last_call_et from v$session, that shows how long the session has been in the state it is current in (active but blocked in your case...)

DB Blocker

A reader, February 06, 2009 - 8:25 am UTC

Just one question:

What is the difference between ctime (number?) in v$lock and last_call_et in v$session?

SQL> select sid, ctime from v$lock where block=1;

       SID      CTIME
---------- ----------
       615        296
SQL> select last_call_et from v$session where sid=615;

LAST_CALL_ET
------------
         297

If I am only interested to find the number of db users blocking at least one other user for more than three minutes, is it not enough to query v$lock for all sid with block=1 (blocker) and ctime>180 like:

SQL> select count(sid) from v$lock where block=1 and ctime>180 ;

COUNT(SID)
----------
         1

Again, I am interested only in number not in sids of blockee and blocker (I will run the query every 5 minutes - so it should be as simple as possible...).

By the way, why ctime has type of number?

Tom Kyte
February 06, 2009 - 3:50 pm UTC

ctime for the blockee - in this case - might be close to last_call_et.

In fact, it would likely be more correct even. If you were in a long running procedure - last_call_et would be going up and up - ctime would be set as of the time of the request.

You are correct, you should use ctime.


ctime is the number of seconds.

what is v$lock.type='HV' lock

Sam, February 14, 2009 - 9:32 pm UTC

Tom:

Database version : 10.2.0.3

I have a session which is doing insert into partition table 
(parallel hint enabled in the select query) holding a lock with v$lock.type='HV' and blocking all other session.
There is no BITMAP index on the table in question.

What is causing 'HV' lock and how to resolve this locking situation. We have parallel_max_servers set to 50.

SQL> select * from v$lock where sid=545 ;

ADDR             KADDR                   SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
00000004B742B6A0 00000004B742B6C0        545 HV     341572      65536          1          0        687          0
00000004B742B738 00000004B742B758        545 HV     341573      65536          1          0        687          0
.....
00000004B7438F08 00000004B7438F28        545 HV     341671      65536          1          0        687          0
00000004B7438FB8 00000004B7438FD8        545 PS          1          7          4          0        687          0
00000004B74390E8 00000004B7439108        545 PS          1          9          4          0        685          0
00000004B7439640 00000004B7439660        545 PS          1         11          4          0        685          0
...
00000004B743F890 00000004B743F8B0        545 HV     341671      65536          1          0        685          0
00000004B9A95180 00000004B9A951A8        545 TM     341551          0          6          0        688          1
00000004B5E998F0 00000004B5E99928        545 TX    2031674      70287          6          0        688          0


Holding session ids:

  1* select * from v$lock where block=1
SQL> 

ADDR             KADDR                   SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
00000004B9A94B80 00000004B9A94BA8        550 TM     341551          0          1          0       1101          1
00000004B9A94D80 00000004B9A94DA8        571 TM     341551          0          1          0       1101          1
00000004B9A94F80 00000004B9A94FA8        510 TM     341551          0          1          0       1101          1
00000004B9A95180 00000004B9A951A8        545 TM     341551          0          6          0       1104          1
00000004B9A95298 00000004B9A952C0        640 TM     341551          0          1          0       1101          1

Blocked session ids:

SQL> select * from v$lock where sid in (512,572,579,591,595) ;

ADDR             KADDR                   SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
00000004B9A94A80 00000004B9A94AA8        579 TM     341551          0          0          6        290          0
00000004B9A95398 00000004B9A953C0        512 TM     341551          0          0          6       2982          0
00000004B9A95498 00000004B9A954C0        595 TM     341551          0          0          6       4856          0
00000004B9A95798 00000004B9A957C0        572 TM     341551          0          0          3       4510          0
00000004B9A95AB0 00000004B9A95AD8        591 TM     341551          0          0          6       3097          0

INSERT query from holding/blocking session is :

INSERT 
INTO ETL.ENDG_RSRVS_MCH 
SELECT /*+ parallel (a,4) (d,4) (c,4) */
   a.gl_effective_dt,
   MIN(a.acctng_perd_beg_dt),
   MAX(a.acctng_perd_end_dt),
   a.document_status_cd,
   a.document_type_cd,
   'H' ORPH_RJCT_IND,
   'R' rndrd_unrd_ind,
   a.premium_loss_cd,
   a.NM_CONTRACT_NO,
   'H' orphan_status_cd,
   a.incomplt_treaty_in,
   a.mach_nm_orig_cd,
   a.MIS013_COUNTRY_CD,
   a.kind_cd,
   a.HOLD_IN,
   a.rein_proc_ctgry_cd,
   a.rein_direction_cd,
   a.rein_rndrg_freq_cd,
   a.rein_no,
   a.rein_uw_yr_no,
   a.rein_efctv_dt,
   a.rein_key_cd,
   a.fac_certificate_no,
   a.xtrnl_rein_ref_no,
   a.captive_in,
   a.asco_mis012_cur_cd,
   a.nm_adjustment_cd,
   a.source_system_id,
   a.mis780_asco_code,
   a.POLICY_XPIRTN_DT,
   a.INSURED_NM,
   a.policy_no,
   a.policy_efctv_dt,
   a.mis780_comp_code,
   a.mach_nm,
   a.rein_no_layer_no,
   a.rein_no_section_no,
   a.rein_no_foreign_dom_cd,
   ' ' reltnshp_typ_cd,
   ' ' src_rein_no,
   '01-jan-1800' src_rein_efctvdt,
   '0' src_rein_uw_yrno,
   ' ' src_rein_key_cd,
   ' ' src_rein_no_layer_no,
   ' ' src_rein_no_section_no,
   ' ' src_rein_no_foreign_dom_cd,
   a.puc_dsp_div,
   a.puc_dsp_puc,
   a.puc_dsp_sec,
   a.LOSS_DT,
   a.DEP_DDSP_DEPT,
   a.term_condition_cd,
   a.matrix_cd,
   a.mis404_tax_st_cd,
   a.credited_branch_no,
   a.working_branch_no,
   a.mis020_catas_cd,
   a.mis020_catas_yr_no,
   a.claim_branch_no,
   a.claim_case_no,
   a.key_branch_no,
   a.key_case_no,
   a.cla_id,
   NVL(c.rdps_maj_class_no, d.rdps_maj_class_no) mis028_maj_class,
   c.MIS028_STMT_LINE,
   NVL(d.transaction_typ_cd, c.transaction_typ_cd) transaction_typ_cd,
   NVL(d.trans_sub_typ_cd, c.trans_sub_typ_cd) trans_sub_typ_cd,
   c.gen_ledger_acct_no,
   NVL(d.reinsurer_no, a.reinsurer_no) reinsurer_no,
   NVL(d.reinsurer_brnch_cd, a.reinsurer_brnch_cd) reinsurer_brnch_cd,
   NVL(d.intermediary_no, a.intermediary_no) intermediary_no,
   NVL(d.intmdry_brnch_cd, a.intmdry_brnch_cd) intmdry_brnch_cd,
   CASE 
   WHEN a.incomplt_treaty_in IN ('Y') 
   THEN
   ' ' 
   ELSE
   NVL(d.participant_typ_cd, ' ') 
   END participant_typ_cd,
   c.BALSHT_GL_ACCT_NO,
   MAX(a.mach_nm_orig_ts),
   COUNT(*) count_keys,
   SUM(NVL(d.asco_financial_am, c.asco_financial_am)) asco_financial_am
FROM (
   SELECT /*+ parallel (a,4) (d,4)*/
      d.sub_header_no,
      DECODE(a.mach_nm_orig_cd, 'M', DECODE(document_type_cd, 'MCH', 'MN', 'MO'
      ), 'N', DECODE(document_type_cd, 'NMC', 'NN', 'NO')) mach_nm,
      a.document_no,
      a.mach_nm_orig_cd,
      a.gl_effective_dt,
      a.acctng_perd_beg_dt,
      a.acctng_perd_end_dt,
      a.document_status_cd,
      a.document_type_cd,
      a.premium_loss_cd,
      a.NM_CONTRACT_NO,
      'H' orphan_status_cd,
      a.incomplt_treaty_in,
      a.MIS013_COUNTRY_CD,
      a.kind_cd,
      a.HOLD_IN,
      a.rein_proc_ctgry_cd,
      a.rein_direction_cd,
      a.rein_rndrg_freq_cd,
      a.rein_no,
      a.POLICY_XPIRTN_DT,
      a.INSURED_NM,
      a.rein_uw_yr_no,
      a.rein_efctv_dt,
      a.rein_key_cd,
      a.fac_certificate_no,
      a.xtrnl_rein_ref_no,
      a.captive_in,
      a.asco_mis012_cur_cd,
      a.NM_ADJUSTMENT_CD,
      a.source_system_id,
      a.mis780_asco_code,
      a.policy_no,
      a.policy_efctv_dt,
      a.mis780_comp_code,
      a.mach_nm_orig_ts,
      a.rein_no_layer_no,
      a.rein_no_section_no,
      a.rein_no_foreign_dom_cd,
      a.reinsurer_no,
      a.reinsurer_brnch_cd,
      a.intmdry_brnch_cd,
      a.intermediary_no,
      d.puc_dsp_div,
      d.puc_dsp_puc,
      d.puc_dsp_sec,
      d.LOSS_DT,
      d.DEP_DDSP_DEPT,
      d.term_condition_cd,
      d.matrix_cd,
      d.mis404_tax_st_cd,
      d.credited_branch_no,
      d.working_branch_no,
      d.mis020_catas_cd,
      d.mis020_catas_yr_no,
      CASE 
      WHEN a.mach_nm_orig_cd = 'M' 
      THEN
      d.claim_branch_no 
      WHEN a.mach_nm_orig_cd = 'N' 
      THEN
      a.nm_claim_branch_no 
      ELSE
      0 
      END claim_branch_no,
      CASE 
      WHEN a.mach_nm_orig_cd = 'M' 
      THEN
      d.claim_case_no 
      WHEN a.mach_nm_orig_cd = 'N' 
      THEN
      a.nm_claim_case_no 
      ELSE
      0 
      END claim_case_no,
      CASE 
      WHEN a.mach_nm_orig_cd = 'M' 
      THEN
      d.key_branch_no 
      WHEN a.mach_nm_orig_cd = 'N' 
      THEN
      a.nm_key_branch_no 
      ELSE
      ' ' 
      END key_branch_no,
      CASE 
      WHEN a.mach_nm_orig_cd = 'M' 
      THEN
      d.key_case_no 
      WHEN a.mach_nm_orig_cd = 'N' 
      THEN
      a.nm_key_case_no 
      ELSE
      ' ' 
      END key_case_no,
      d.cla_id
   FROM (
      SELECT /*+ parallel (a,4)*/
      * 
      FROM src.theader a 
      WHERE gl_effective_dt = TO_DATE('01-APR-08', 'dd-mon-yy') 
      AND document_status_cd = 'A' 
      AND mach_nm_orig_cd = 'M' 
      AND document_no NOT IN (
      SELECT document_no
      FROM etl.theader_reject) 
      AND rein_direction_cd = SUBSTR('CED4', 1, 3) 
      AND rein_direction_cd = SUBSTR('CED4', 1, 3) 
      AND ((SUBSTR('CED4', 4, 1) IS NULL) 
      OR (source_system_id IN (
      SELECT source_system_id
      FROM etl.proc_ref 
      WHERE rein_direction_cd = 'CED4')))) a, src.tsub_header d 
   WHERE a.document_no = d.document_no) a, (
   SELECT /*+ parallel (y,4)*/
      document_no,
      sub_header_no,
      rdps_maj_class_no,
      transaction_typ_cd,
      trans_sub_typ_cd,
      reinsurer_no,
      reinsurer_brnch_cd,
      intermediary_no,
      intmdry_brnch_cd,
      NVL(TRIM(participant_typ_cd), 'XXX') participant_typ_cd,
      rdps_bus_type_cd,
      asco_financial_am
   FROM src.tpartcpnt_explsn y 
   WHERE transaction_typ_cd IN (1, 4, 5, 6, 8, 9, 10, 13, 18, 22, 29, 30, 36, 
   37, 44, 45) 
   AND trans_sub_typ_cd IN (11, 41, 51, 61, 81, 91, 101, 131, 181, 221, 291, 
   301, 302, 361, 371, 441, 451)) d, (
   SELECT /*+ parallel (b,4)*/
   * 
   FROM src.tsub_header_fncl b 
   WHERE transaction_typ_cd IN (1, 4, 5, 6, 8, 9, 10, 13, 18, 22, 29, 30, 36, 
   37, 44, 45) 
   AND trans_sub_typ_cd IN (11, 41, 51, 61, 81, 91, 101, 131, 181, 221, 291, 
   301, 302, 361, 371, 441, 451)) c 
WHERE a.document_no = c.document_no 
AND a.sub_header_no = c.sub_header_no 
AND c.document_no = d.document_no(+) 
AND c.sub_header_no = d.sub_header_no(+) 
AND c.rdps_maj_class_no = d.rdps_maj_class_no(+) 
AND c.rdps_bus_type_cd = d.rdps_bus_type_cd(+) 
AND c.transaction_typ_cd = d.transaction_typ_cd(+) 
AND c.trans_sub_typ_cd = d.trans_sub_typ_cd(+) 
GROUP BY a.gl_effective_dt, a.document_status_cd, a.document_type_cd, a.premium_loss_cd
, a.NM_CONTRACT_NO, a.incomplt_treaty_in, a.mach_nm_orig_cd, a.MIS013_COUNTRY_CD
, a.kind_cd, a.HOLD_IN, a.rein_proc_ctgry_cd, a.rein_direction_cd, a.rein_rndrg_freq_cd
, a.rein_no, a.rein_uw_yr_no, a.rein_efctv_dt, a.rein_key_cd, a.fac_certificate_no
, a.xtrnl_rein_ref_no, a.captive_in, a.asco_mis012_cur_cd, a.nm_adjustment_cd, 
a.source_system_id, a.mis780_asco_code, a.POLICY_XPIRTN_DT, a.INSURED_NM, a.policy_no
, a.policy_efctv_dt, a.mis780_comp_code, a.mach_nm, a.rein_no_layer_no, a.rein_no_section_no
, a.rein_no_foreign_dom_cd, a.puc_dsp_div, a.puc_dsp_puc, a.puc_dsp_sec, a.LOSS_DT
, a.DEP_DDSP_DEPT, a.term_condition_cd, a.matrix_cd, a.mis404_tax_st_cd, a.credited_branch_no
, a.working_branch_no, a.mis020_catas_cd, a.mis020_catas_yr_no, a.claim_branch_no
, a.claim_case_no, a.key_branch_no, a.key_case_no, a.cla_id, NVL(c.rdps_maj_class_no
, d.rdps_maj_class_no), c.MIS028_STMT_LINE, NVL(d.transaction_typ_cd, c.transaction_typ_cd
), NVL(d.trans_sub_typ_cd, c.trans_sub_typ_cd), c.gen_ledger_acct_no, NVL(d.reinsurer_no
, a.reinsurer_no), NVL(d.reinsurer_brnch_cd, a.reinsurer_brnch_cd), NVL(d.intermediary_no
, a.intermediary_no), NVL(d.intmdry_brnch_cd, a.intmdry_brnch_cd), CASE 
WHEN a.incomplt_treaty_in IN ('Y') 
THEN
' ' 
ELSE
NVL(d.participant_typ_cd, ' ') 
END, c.BALSHT_GL_ACCT_NO

Tom Kyte
February 16, 2009 - 12:23 pm UTC

direct loader high watermark enqueue


whenever you direct load into a table, the table is locked - no other session can modify it.



ops$tkyte%ORA10GR2> create table t ( x int );

Table created.

ops$tkyte%ORA10GR2> insert /*+ append */ into t select 1 from dual;

1 row created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          insert into t values ( 1 );
  5          commit;
  6  end;
  7  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4


High water mark enqueue

Sam, February 16, 2009 - 10:18 pm UTC

Thanks Tom.

In this case, Holding session and Waiting session does not have /*+ append */ hint enabled in the INSERT. So not sure why we have "direct loader high watermark enqueue" lock waits.
Any other thing can cause this lock ?

We have parallel hint in the SELECT part.


Tom Kyte
February 17, 2009 - 8:22 am UTC

parallel = direct path

parallel is all it took, you are doing a parallel load, that is always direct path.

PARALLEL HINT in INSERT

Sam, February 17, 2009 - 1:55 pm UTC

>> parallel = direct path
>> parallel is all it took, you are doing a parallel load, that is always direct path.

Thanks for clarifying this Tom.

Are the following INSERT statements performing DIRECT PATH INSERT, correct ?

INSERT /*+ PARALLEL */ into T select * from TEMP ;

INSERT into T select /*+ PARALLEL */ * from TEMP ;



I thought that INSERT will be sequential and queries are run parallelly. this is something i wanted to get clarified.

Thanks for your time.
Tom Kyte
February 17, 2009 - 2:56 pm UTC

what is the table you are loading into set to be? and was there an alter session to enable parallel dml operations?

parallel hint

Sam, February 19, 2009 - 2:46 pm UTC

<< what is the table you are loading into set to be? and was there an alter session to enable parallel dml operations?

No parallelism enabled at the table level or session level.
Tom Kyte
February 19, 2009 - 4:56 pm UTC

ok, one thing I want you do to for me

after doing the insert, before you commit, select count(*) from table_inserted_into where rownum =1 - in the session that does the insert.

tell me if that succeeds or fails.

PARALLEL hint

Sam, February 21, 2009 - 12:54 am UTC

Tom,

here is the test result with PARALLE hint.
I am not using *APPEND* hint in the INSERT.


00:42:15 SQL> insert into t1 select /*+ PARALLEL */ * from temp ;

44 rows created.

Elapsed: 00:00:00.00
00:42:34 SQL> select count(*) from t1 ;

  COUNT(*)
----------
        44

Elapsed: 00:00:00.01
00:42:40 SQL> insert /*+ PARALLEL */ into t2 select * from temp ;

44 rows created.

Elapsed: 00:00:00.01
00:43:17 SQL> select count(*) from t2 ;

  COUNT(*)
----------
        44

Elapsed: 00:00:00.01

Tom Kyte
February 21, 2009 - 9:13 pm UTC

no, I mean the process we were talking about above - not that I don't believe you - but I'm not sure what else is happening - I just want you to put that count where rownum=1 into THAT PROCESS and show us what you see. the entire process. change nothing else.

A reader, February 21, 2009 - 9:14 am UTC

Tom-
I have a fundamental question on locking and query processing. Say I have a complex query with some joins and a bunch of where clauses and I execute the query and fetch some rows (not the entire result but say the first 1000 out of a million) - most SQL query tools have the ability to limit to a certain number and then when you scroll down they fetch the next block of rows.

Now if I wait for 10 minutes and then fetch the next 1000 rows how does Oracle know where to start? If the resultset is stored in a temp segment I can see how it can bring back the next results. But if the results are not first written to a temp segment (i.e. Oracle is reading directly from the table with no sorting etc.) does Oracle reexecute the query? If not how does it know which rows were retuned earlier and where to start? I know it has something to do with cursor locations but I don't quite understand it.

Thank you.
Tom Kyte
February 21, 2009 - 9:22 pm UTC

when you open a query, we remember "what time is it"

so, say you open a query at 12 oclock noon. And you fetch NOTHING from it (no IO is performed, we just opened the query, nothing in temp, no IO's, nothing)

As we fetch data from the query, we will make sure every block is "as of that point in time". Now say you come back 3 hours later, it is 3 oclock in the afternoon (15:00 hours). You issue your very first fetch call.

For the first time, we do some IO, lets say this was just a simple "select * from t" where t is a regular normal table with some rows. In order to process this query, we know we need the first block of T, so we go to the buffer cache and request it. But the version in the cache right now is seen to have been modified at 14:00 hours. Well, 14:00 is AFTER 12:00 and everything this query sees has to be AS OF 12:00. So, we roll back the change to that block - and we keep rolling it back until we get the version of the block that was committed as of 12:00. That is the version we use.

We do this for every block we encounter. Even if you do not fetch again for 3 more hours (it is now 18:00 hours). You ask us finally for the second row. The second row is on block 1 as well - we go to the buffer cache and get block 1 for that table, and discover it was modified at 17:45. We rollback...... until it is as of 12:00 noon and we use that.


If you want a more detailed answer in my words, "Expert Oracle Database Architecture" has pages and pages on it.

Documentation has a lot to say on it as well

http://docs.oracle.com/docs/cd/B19306_01/server.102/b14220/intro.htm#sthref135


Update on bitmap index column

A reader, March 06, 2009 - 6:58 pm UTC

Hi Tom,

As update on bitmap indexes can be very CPU intensive and will result into whole table lock, can you suggest whta will be the best way to handle this scenario:
We have couple of SCD dimensions tables, and most of the time users will query on current_flag ='Y' column. The volume of dimensions tables will vary from few hundred to thousands. For query performance we plan to create bitmap index on current_flag (having 'Y','N' values only). But when we need to implement SCD, the old row will be updated with 'N' and new row will be inserted with 'Y', thus updating a bitmap index column.

Thanks,
Tom Kyte
March 07, 2009 - 12:19 pm UTC

... As update on bitmap indexes can be very CPU intensive and will result into whole table lock, ...

neither of those statements are true.


And it seems you believe a myth that "if you have low distinct cardinality columns - only bitmap indexes make sense"


how about this


create index t_idx on t( case when flag = 'Y' then flag end );

and then you query:

where (case when flag='Y' then flag end) = 'Y;


you will index..... only the Y values. (if you have effective Oracle by Design, I actually use this exact example "processed flag = Y" to discuss this topic...)

Bitmap Indexes

A reader, March 07, 2009 - 6:44 pm UTC

Hi Tom,

Regarding updates (Locking and CPU resources)...

How this is different than what is mentioned in your book
'Expert Oracle Database Architecture from Apress" Page 452 last paragraph

However, there are times when bitmaps are not appropriate...

... If a session modifies the indexed data, then all of the rows that index index entry points to are effectively locked in most cases....Oracle locks the entire bitmap index entry....locking potentially hundreds of rows..

Thanks



Tom Kyte
March 08, 2009 - 7:09 am UTC

do you see the difference between "locking potentially hundreds of rows" versus "locks the entire table"????

And "are effectively locked in most cases" versus "locks the entire table"?


Keep reading the book, I mention that a bitmap index on say the JOB column of EMP does not mean that the JOB=CLERK value will appear once in the bitmap, but will likely appear many many times. And that each key value in the bitmap will cover a range of rows, NOT the entire table (once the table gets to be sizable in any case)...

There are examples in there.

It is not true that bitmaps lock the entire table.

locking

A reader, March 12, 2009 - 5:37 am UTC

Greetings Thomas,

and thanks like always,

My Case as follow:
select
(select username from v$session where sid=a.sid) blocker,
a.sid,
' is blocking ',
(select username from v$session where sid=b.sid) blockee,
b.sid
from v$lock a, v$lock b
where a.block = 1
and b.request > 0
and a.id1 (+) = b.id1
and a.id2 (+) = b.id2;

Blocker SID 'ISBLOCKING' BLOCKEE SID_1
C 91 is blocking C 91

the session is truncating a table.
The session is blocking him self?????
And when i use other GUI tools they tell me you have "session blocked" but there is no blocker.

Thnaks in advanced

Too Many Unindexed Foreign Keys?

Ramchandra Joshi, May 22, 2009 - 5:30 am UTC

Hi Tom,

http://asktom.oracle.com/~tkyte/unindex/index.html

I understand the point of having the child table indexed for the foreign key columns.

But the point here is if my child table is having references to 6-7 parent tables ,Then is it really a good idea to have indexes on all those 6-7 columns in the table ?

Just consider if the child table is a regular *TRANSACTION* table and all the parent tables are Master tables.So Does it not provide extra overhead on our child table with those *TOO MANY* indexes ?

Thanks in Advance,
Ram.


Tom Kyte
May 23, 2009 - 10:21 pm UTC

if you update the parent table primary key
or
if you delete from the parent table
or
if you merge into the parent table

you absolutely want that foreign key index.


Think about it - if you leave it unindexed you will:

a) get a full table lock on the child table every time you do any of the three above operations
b) full scan the table table for each and every parent row you perform the operation on. Delete 10 rows from the parent table, 10 full scans of child table (whilst child table is, well, LOCKED)



Think about the *overhead* of that and get back to us whether you think having the indexes would be

a) good
b) bad

I think (a) applies if you do those operations (update/delete/merge into parent)

Blocking deletes

Bozzer, June 01, 2009 - 1:01 pm UTC

Hi Tom,

I have a question for you regarding blocking deletes and concurrency. If we have a single delete statement called from a package that deletes a large number of records (e.g. 800k to 1000k) from table x

e.g. Process A

delete from x
where exists
(select null
from y
where x.a = y.a
and x.b = y.b)

then another concurrent process Process B (that runs the same delete statement above) but deletes a smaller number of records. Process B will wait until the large delete completes. Process A may take between 10-20 mins. And Process B normally takes 30 seconds (if run on its own). Potentially process B may have to wait 10-20 mins for process A to complete.

Would it be feasible under these circumstances to do the delete in a loop and commit (every 100k records). We would like to do the delete as a single set operation ... but how can we prevent blocking ...

Tom Kyte
June 01, 2009 - 8:20 pm UTC

... Would it be feasible under these circumstances to do the delete in a loop and
commit (every 100k records). ...

what happens if it fails and stops running after the first 100k but before the second? are you OK with that

what happens to every other transaction out there that until now has either see ALL OF THE ROWS to be deleted or NONE OF THE ROWS that were deleted - what will happen to them when them when they start seeing 100k of them gone, then 200k of them gone and so on?

In short - only you - you and ONLY YOU - can answer this question, the ramifications of commiting in the loop are very very clear. What will happen to your transactional integrity if you make this change????

committing in a loop

Bozzer, June 02, 2009 - 5:13 am UTC

I agree with you totally. But when it comes to performance - a large delete will hold up the smaller delete if we do it as a single set operation. Can we make changes in the storage parameters (e.g. initrans, pctused, pctfree) so that a single delete set operation can be speeded up?
Tom Kyte
June 02, 2009 - 7:45 am UTC

initrans, pctused, pctfree would have negligible impact (if any - initrans - perhaps IF AND ONLY IF you were experiencing ini waits in the session doing the delete).

when it comes to performance VERSUS CORRECT PROGRAM EXECUTION - one must choose the latter.


In short, you need to address these questions:

what happens if it fails and stops running after the first 100k but before the second? are you OK with that

what happens to every other transaction out there that until now has either see ALL OF THE ROWS to be deleted or NONE OF THE ROWS that were deleted - what will happen to them when them when they start seeing 100k of them gone, then 200k of them gone and so on?



if either of those represents "a bad thing", you cannot commit partially (as you'll experience those bad things).


You tune a delete in the same fashion you tune any sql statement. Remember a delete will typically have the maximum impact of all of the DML - every index on the table will be affected (fewer indexes = better delete performance IN GENERAL - big exception would be if you drop the index the delete uses to find the records to delete!). The entire row goes into the rollback segment.

ways to speed things up:

don't do the thing (that is by far the fastest) - Can you find a way to use partitioning instead of delete, then you can truncate or drop.

review the execution plan of the delete - ensure that it uses an index IF THAT MAKES SENSE. ensure that it uses a full scan IF THAT MAKES SENSE. If the delete is horribly complex with a billion subqueries - look at the logic and see if it can be simplified


committing in a loop

bozzer, June 03, 2009 - 5:23 am UTC

This is some of the most useful advice I have come across! Thank you. As it happens (in this particular case) - it doesn't matter if it fails midway through. We can restart the job and it will continue to delete. The table has about eight to ten indexes so I guess this wouls slow down deletes. We have normal B-tree indexes on columns with low cardinality e.g. active_indicator (which has two values Y or N) ...which I guess is a bad thing - as the indexes are unselective.
Tom Kyte
June 04, 2009 - 9:11 am UTC


Santanu, June 29, 2009 - 6:07 am UTC

A package (invoked by daily job) inserting bulk data into a table failed with out any error msg. Both package and the table in inaccessible with ORA-00054: resource busy and acquire with NOWAIT specified. Can¿t drop or recompile the package and can¿t truncate or drop the table.
But following query not returning no info.
Select SESSION_ID from v$locked_object where OBJECT_ID=(select object_id from dba_objects where object_name='xyz'). There is no inactive session in the v$session to be killed for this username either.
Pls help.

Tom Kyte
July 06, 2009 - 6:16 pm UTC

.. failed with
out any error msg. ...

umm, no, it did not. YOU might have failed to log the error, you might have used a when others to HIDE the error, YOU did something to make the error disappear, but rest assured, we raised an error to you. It is up to YOU to do something about it.

Or, after reading your probably description, it is likely it hasn't failed - it is just still running.


query v$access to see who is currently using it.

enq: TX - row lock contention

Rama Subramanian G, July 06, 2009 - 11:08 am UTC

Tom,

In an AWR Report, in Top 5 Timed Events, I see the following line as the first one.

Event Waits Time Avg % Total Wait
Wait Call Time Class
-------------------------------------------------------
CPU time 6,545 42.9

enq: TX - 1,167 3,385 2,901 22.2 Application
row lock
contention
-------------------------------------------------------

Now, TX locks - Are they locks blocking something ? Why is this a Top 5 Wait event?

Thanks
Tom Kyte
July 06, 2009 - 8:36 pm UTC

in reverse...

why is this a top 5 wait event? Because the rest of the waits consume less total time (that one was easy). Think about it... It was in the top five because... well, it was in the top 5.

Why is Michael Phelps in the top 5 swimmers in the world?


You have wait locking issues - you have session 1 that has a lock on a row in a table and session 2 would like to have that same row locked. session 2 will wait for session one to finish.

row level locking???

a reader, October 27, 2009 - 5:55 am UTC

Hi Tom,

I must be missing something here, i though oracle implemented row level locking by default, but:

----as scott:
SQL> grant update on emp to hr;
SQL> update emp set sal=1000 where ename='SMITH'

---in another sqlplus window as hr:
SQL> update emp set sal=1000 where ename='JAMES'
...and it blocks until scott makes a commit!

Hr is trying to update a different row, and gets blocked because scott is modifying another row. I'm using 10.2.0 so it's not a matter of maxtrans.

I'm using the default example database.
Can you please tell me what's going on?
Thanks in advance.

Tom Kyte
October 27, 2009 - 11:46 am UTC

no it doesn't

not unless you modified the schema by adding a bitmap index or something.


you just update emp in the "hr" window, why not scott.emp?

but - no, what you say isn't true. If you believe it is, then create a FULL TEST CASE including all create statements so we can reproduce it.

Then we can tell you what you did wrong.

row level locking???

A reader, October 27, 2009 - 1:19 pm UTC

Sorry about the typo.

Yes as user hr the sql is:
SQL> update SCOTT.EMP ....

By your anwser I understand that oracle doesn't implement row level locking UNLESS you have a bitmap index, otherwise, it just lock the entire table?

Can you please point me to the documentation regarding this point? ( i have been checking the concepts guide and found nothing like that).

Tom Kyte
October 27, 2009 - 5:03 pm UTC

you cannot have a typo in a CUT AND PASTE and that is what you should be using, everything else is 'fake'


...
By your anwser I understand that oracle doesn't implement row level locking
UNLESS you have a bitmap index, otherwise, it just lock the entire table?
....
NO NO NO NO NO NO NO NO

if you have a bitmap index, you decrease concurrency and probably lose row level locking.

you have row level locking always by default.


Here is my CUT AND PASTE showing this:



scott%ORA10GR2> connect scott/tiger
Connected.
scott%ORA10GR2>
scott%ORA10GR2> update emp set sal = 1000 where ename = 'SMITH';

1 row updated.

scott%ORA10GR2>
scott%ORA10GR2> !sqlplus / @update_james

SQL*Plus: Release 10.2.0.4.0 - Production on Tue Oct 27 17:02:05 2009

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> update emp set sal = 1000 where ename = 'JAMES';

1 row updated.

ops$tkyte%ORA10GR2> commit;

Commit complete.

ops$tkyte%ORA10GR2> exit;
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

scott%ORA10GR2>
scott%ORA10GR2>




there you go, no one gets blocked.

If you do that, and you get blocked - then you NEED TO GIVE US A REPRODUCIBLE TEST CASE - because it means you did something, you created a bitmap index for example (that DECREASES concurrency, not the other way around).


By default - what you claim to have seen WILL NOT HAPPEN.


So, you are doing something else and you need to share that with us. Full test case please.


A reader, October 28, 2009 - 2:32 am UTC

Sorry Tom

After checking dba_indexes I found someone created a bitmap index on the sal column of emp.

Thanks a lot and sorry for the loss of time.
Tom Kyte
October 28, 2009 - 7:57 am UTC

this is exactly why I want test cases.

99.999999999% of the time, when I build my test case to reproduce an issue....


I find my own mistake, it hits me in the face hard, and I fix it and we are done.

Table locked and session was invalidated

Tarek, November 04, 2009 - 5:50 am UTC

Dear tom,

I would like to thank you for all of your answers on the previous questions. I find your website the most useful on the internet regarding oracle database issues.

I have a simple question (maybe very easy for you, but i just became a profesional developer 10 months ago). I developed a java application, which runs on Oracle application server and Oracle database. This application depends on multiple JSPs on which multiple users can access a single JSP in the same time, some problems occurs due to the excessive usage of this application and I have some questions about them:

1. Is there any danger or disadvantages in connecting to the database using the jdbc directly from the JSP ?!!

2. An error occurs almost once a week (most probably at the point of time when an excessive usage happens). This error stops the users from submitting or accessing the some JSPs. I ran the following query on the DB to find any locked items:
SELECT o.owner, o.object_name, o.object_type, o.last_ddl_time, o.status,l.session_id, l.oracle_username, l.locked_mode
FROM dba_objects o, gv$locked_object l
WHERE o.object_id = l.object_id; 


I found that the table I use to select from in the halted JSPs is a result from this query.

In order to solve this problem temporarily, i use the sql developer to add a record to this table and commit, i find that the problem is solved and the halted jsps involved are running.

These are the exceptions that appears in the log files of the application server right after I press commit:

a.java.lang.IllegalStateException: Session was invalidated (all the time)
b.java.sql.SQLException: Closed Connection (some times)

I do not know exactly where to start debugging, since i use synchronization in all of my code. Also I made sure that each user accessing the same JSP has a separate connection.

Thanks in advance

Tom Kyte
November 09, 2009 - 3:53 pm UTC

1) as long as you code properly (use bind variables, do things in as few sql statements as possible - good coding practices) it would be no different than jdbc from "anything" or odbc or odp.net or pro*c or whatever.

2) you do not mention what the database error is?????

the IllegalStateException is a java issue, your code, outside of the database. that is not a database error.

SQLException - you don't give me the ora-xxxxx error code, but it sounds like someone bounced your database (shutdown, started it up again) or killed your session.

Table locked and session was invalidated

Tarek Mostafa, November 10, 2009 - 4:25 am UTC

Dear Tom,


First of all, thanks for your help, i really appreciate it.

I actually don't use binding variables, nor my code has few sql statements (I reduced them as much as i can), but i will consider using the binding variables approach.

Actually there is no ora-xxxx error code resulting, but i am really concerned with the table locking issue.


What actions by users can lock a table in oracle?!!
Can u please help me with that, because what i read is that an oracle table can not be locked by any means.

Thanks again
Tom Kyte
November 11, 2009 - 3:11 pm UTC

"U" isn't available, "U" is dead as far as I know. Look it up, it is true.

http://en.wikipedia.org/wiki/U_of_Goryeo



... because what i read is that an oracle table can
not be locked by any means.
...

where did you read that (totally 100% incorrect) thing?

And where did locking tables all of a sudden come up? Not a shred of background on that - what you think it is causing,what is happening.


... but i will consider using the binding variables
approach.
...

do not consider it, do it - your code is wrong, and almost certainly "not very secure" because of this.




if there is no ora-xxxx error, not sure what I can do to help you. SQLException sure *sounds* like it would have the ora-xxxx with it (else, how could sql throw an exception into your code) and the illegal state situation has nothing to do with the database at all.

Tarek Mostafa, November 12, 2009 - 2:54 am UTC

Dear Tom,

In my first post i wrote that an Oracle table gets locked, I even wrote the query that i used to get the locked items.

What i read was that an Oracle table can be locked only for an instance of time while updating, inserting or deleting and that even if multiple operations on a table is requested, a synchronized way of handling them is done (correct me if i am wrong).

Regarding the security issue of not using Binding variables, i am not really concerned with security since my application does not require any users login or passwords and security is handeled by another application, by which if a user is not allowed to use my application, he will not see it in the first place. However, i will use your advice and consider using them (as i said before), since i am looking to learn for my next application.

Actually there is no ora-xxxx resulting from the sqlexception and here is the full stacktrace of the error:
09/11/02 18:00:27 java.sql.SQLException: Closed Connection
09/11/02 18:00:27 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:138)
09/11/02 18:00:27 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:175)
09/11/02 18:00:27 at oracle.jdbc.driver.DatabaseError.check_error(DatabaseError.java:874)
09/11/02 18:00:27 at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:184)
09/11/02 18:00:27 at com.orionserver.http.OrionHttpJspPage.service(OrionHttpJspPage.java:59)
09/11/02 18:00:27 at oracle.jsp.runtimev2.JspPageTable.service(JspPageTable.java:453)
09/11/02 18:00:27 at oracle.jsp.runtimev2.JspServlet.internalService(JspServlet.java:591)
09/11/02 18:00:27 at oracle.jsp.runtimev2.JspServlet.service(JspServlet.java:515)
09/11/02 18:00:27 at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
09/11/02 18:00:27 at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:711)
09/11/02 18:00:27 at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:368)
09/11/02 18:00:27 at com.evermind.server.http.HttpRequestHandler.doProcessRequest(HttpRequestHandler.java:866)
09/11/02 18:00:27 at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:448)
09/11/02 18:00:27 at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:302)
09/11/02 18:00:27 at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:190)
09/11/02 18:00:27 at oracle.oc4j.network.ServerSocketReadHandler$SafeRunnable.run(ServerSocketReadHandler.java:260)
09/11/02 18:00:27 at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:303)
09/11/02 18:00:27 at java.lang.Thread.run(Thread.java:595)

I think this error occurs when an excessive use of the application happens, and as i said before the whole jsp halts and not a single request for this jsp responds or any other jsp which has operations with the locked table, even with any other user. In order to solve this issue temporarily i use the sql developer to add dummy record to this table and commit (this action unlocks the table) and then rollback.

I would like to add that if this issue is out of your scope, just point that out.

Thanks for your time and assistance


Tom Kyte
November 15, 2009 - 1:29 pm UTC

... What i read was that an Oracle table can be locked only for an instance of time
while updating, inserting or deleting and that even if multiple operations on a
table is requested, a synchronized way of handling them is done (correct me if
i am wrong).
...

you are entirely wrong.


A table can be locked for any duration of time. Look up the LOCK TABLE command.

A table is NOT locked to serialize modifications - it does not work that way. You can have thousands of users SIMULTANEOUSLY modifying a table - they will not serialize their modifications.



... i am not really
concerned with security since my application does not require any users login
or passwords and security is handeled by another application, ....

that is exactly WHY you need to be concerned, you have missed the point entirely. Since the application is doing security (and if it is being done by people that don't get sql injection, don't know what it is and when it is bad - then I know it is DONE WRONG) - you have to be concerned about sql injection.


If you log into the database using the actual end users credentials - you don't need to worry about sql injection, that user can only do what they've been granted the ability to do.

It is precisely when you use this single user account and "do security yourself in the application" that sql injection should KEEP YOU AWAKE WITH COLD SWEATS AT NIGHT. That is doesn't... Hmmmmmm - think about that.










A java stack strace does nothing for me, there is an oracle error happening, your code is hiding it in one of your exception handlers.

if there is no oracle error message, then - I would guess "someone in your application stack, closed the connection"


go to your databaseerror class and see what it does, it is hiding this from you.

Locks during XA transactions

Nevin, November 17, 2009 - 10:42 am UTC

Hi Tom,
Is there any difference to the locking mechanism or the v$lock table view if I execute my DML (insert/update) within a distributed/XA transaction? A test program (using Oracle JDBC Thin XA driver 10.2.0.4) to verify this gave the following behavior
1. Table inserts in JDBC local transaction (non XA) showed up in v$lock table
USERNAME        SID       RBS       SLOT      SEQ          LMODE      REQUEST     
--------------- --------- --------- --------- ------------ ---------- ---------- 
IRES_BACKUP     515       25        11        893165       6          0           

1 rows selected 

XIDUSN                 XIDSLOT                XIDSQN                 
---------------------- ---------------------- ---------------------- 
25                     11                     893165                 

1 rows selected


2. Table inserts in XA transaction does not show up in v$lock table. Transaction is visible in v$transaction.
USERNAME        SID       RBS       SLOT      SEQ          LMODE      REQUEST     
--------------- --------- --------- --------- ------------ ---------- ---------- 

0 rows selected 

XIDUSN                 XIDSLOT                XIDSQN                 
---------------------- ---------------------- ---------------------- 
9                      3                      1933433                 

1 rows selected


3. I first insert a row with a particular PK via SQLPlus and then (without committing in SQLPlus) try to reinsert the same row in a distributed transaction. Here I get to see locks held by SQLPlus and lock requested by the session in distributed transaction in v$lock
USERNAME        SID       RBS       SLOT      SEQ          LMODE      REQUEST     
--------------- --------- --------- --------- ------------ ---------- ---------- 
IRES_BACKUP     515       28        41        397069       0          4           
IRES_BACKUP     401       28        41        397069       6          0           

2 rows selected 

XIDUSN                 XIDSLOT                XIDSQN                 
---------------------- ---------------------- ---------------------- 
4                      29                     1328335                 
28                     41                     397069                 

2 rows selected


4. I first insert a row with a particular PK in a distributed transaction and then (before XA transaction commits) try to reinsert the same row via SQLPlus. Here I get to see the 2 rows by SQLPlus session in v$lock. But there is no row for the XA transaction that holds the lock.
USERNAME        SID       RBS       SLOT      SEQ          LMODE      REQUEST     
--------------- --------- --------- --------- ------------ ---------- ---------- 
IRES_BACKUP     401       45        27        214399       0          4           
IRES_BACKUP     401       80        4         114748       6          0           

2 rows selected 

XIDUSN                 XIDSLOT                XIDSQN                 
---------------------- ---------------------- ---------------------- 
45                     27                     214399                 
80                     4                      114748                 

2 rows selected


Is it lock escalation ?

Max, January 22, 2010 - 4:44 am UTC

Dear Tom,
I read your book, as well as your answers in this post, and you always say : no such thing as lock escalation in Oracle
So my question is: in Oracle (before 10g) if I set MAXTRANS=2, and I have many sessions which lock rows in the same block, why this example is not a lock escalation from row-lock to block-lock?

Sincerely

Tom Kyte
January 25, 2010 - 1:46 am UTC

maxtrans is obsolete for many releases - it doesn't 'exist' anymore, it is always set to the max.

but yes, you could make it so that only N transactions could have hit a block in older releases (concurrently). It would have been, in those older releases, an artificial limit you imposed for some reason.

Relation between DBMS_LOCK handle and V$LOCK.ID1

Matt, February 01, 2010 - 12:38 pm UTC

Tom,

We have a need to detect when a commit or rollback has happened. Without going into details (which I'll happily provide), we have a off-the-shelf tool that uploads data in batches, calling a custom API (that we provide) once for each record. After the last record it commits. Our custom API needs to know when it is processing the FIRST record in a batch, so we can perform special logic at that time.

I figured this could be done by using a shared DBMS_LOCK lock as a marker. After a commit, the lock will go away and, on the next call, the missing lock will tell us that a commit/rollback has happened.

But I have a concern about the query I use to check for the lock's existence:


-- Check for lock
SELECT COUNT (*)
INTO   l_count
FROM   v$lock
WHERE  SID = (SELECT SID
              FROM   v$mystat
              WHERE  ROWNUM = 1)
AND    TYPE = 'UL'
AND    id1 = SUBSTR (l_lock_handle, 1, 10);


Specifically, I do not understand why V$LOCK only seems to show the first 10 digits of the DBMS_LOCK lock handle. Can you explain that? (Also, I'll welcome any criticisms of the overall concept).

Thanks,
Matt

Tom Kyte
February 01, 2010 - 12:44 pm UTC

but how would that tell you a new batch started???

say batches are 1,000 records.

batch1 goes up - you start. when you are on record 521 - the second batch completes. You will NOT be in batch 2 until record 1,000 was processed. It has nothing to do with the timing of the commits?

and what if your process dies but the batch upload continues, you cannot tell where a batch started/ended?

give more details please, sounds more like the records need to be tagged during the insert - which could be done with a trigger placing the transaction id in every record inserted (you can always use a separate table if you cannot modify the table or rename table to table_ and create a view table as select ... and add the column you need to table_)

The custom API *is* the insert

Matt McPeak, February 01, 2010 - 2:19 pm UTC

Tom,

Sorry I wasn't clear. The process flow is this:

1) User enters data into Microsoft Excel (1000 rows)
2) User presses "Oracle / Upload" menu in Excel
3) 3rd Party (OK, it's Oracle) VB code in Excel sends each Excel row to Oracle. For each row, it calls our custom PL/SQL AP, passing as parameters the data from Excel. The custom API validates and inserts the data into a table.
4) After the custom API has been called for all 1000 rows, it commits.
5) User optionally starts over with step 1.

I'm trying to add logic to that custom API in step 3 so that it knows which rows are uploaded in the same batch. Your suggestion about tagging the rows on insert is exactly what I am trying to accomplish.

Thanks,
Matt

Tom Kyte
February 01, 2010 - 4:11 pm UTC

read about dbms_transaction.local_transaction_id

Transaction ID

Matt McPeak, February 01, 2010 - 2:24 pm UTC

By the way, my first attempt WAS to try to use a change in TADDR to note a change in transaction, but I found it did not change on commit/rollback. Are you saying there is something else I could check that *would* change reliably? Like V$TRANSACTION.XIDUSN or something? That would be easier, if it would work.

Thanks again!

- Matt
Tom Kyte
February 01, 2010 - 4:11 pm UTC

see above

Thanks

A reader, February 01, 2010 - 4:31 pm UTC

This is just what I needed. Thanks!

question of lock

alan, February 04, 2010 - 8:06 pm UTC

Hello Tom:
Here is my test:

SQL> create table t(x int primary key,y int);    
table created

SQL>  insert into t values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> update t set x=2;
                                
1 row updated.            


--open another session:

SQL> update t set y=2 where x=1;
 
      
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid in (159,152) order by 1;                                                                    
                                                                                
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK            
---------- -- ---------- ---------- ---------- ---------- ----------            
       152 TM      64626          0          3          0          0            
       152 TX     131078       5346          0          6          0            
       159 TX     131078       5346          6          0          1            
       159 TM      64626          0          3          0          0            
                                                                           

--I can understand this ,but

SQL> drop table t purge;

Table dropped.

SQL> create table t (x int primary key,y int);

Table created.



SQL> insert into t values(1,1);

1 row created.

---open another session:

SQL>SQL> insert into t values(1,1);
                
 SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid in (159,152) order by 1;                                                                                                 
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK            
---------- -- ---------- ---------- ---------- ---------- ----------            
       152 TX     131097       5339          0          4          0            
       152 TM      64626          0          3          0          0            
       152 TX     524291       5327          6          0          0            
       159 TX     131097       5339          6          0          1            
       159 TM      64626          0          3          0          0             
SQL>          


My question is:
1.I want there is a 6 tx request of sid 152 but is 4,why?
2.Why sid 152 hold a 6 mode tx lock,I think it was blocked by sid 159,what it is?
3.What the diffent of this 2 cases(insert and update on a table with pk)


Regards alan

Tom Kyte
February 07, 2010 - 11:47 pm UTC

It would be more illustrative and easier to understand if you printed out what session was what and what objects where represented...

we get locks at the lowest level and escalate them up as needed. Before we can insert "1", we need to make sure there isn't a "1" in there first - we want do that in a way that uses the lowest lock possible - in this case a share. It would become exclusive when we actually insert the row - which we are blocked from doing right now.

still not clear of the diffrence of update and insert on table with PK

A reader, February 08, 2010 - 5:58 pm UTC

Hello,Tom

you said:
we get locks at the lowest level and escalate them up as needed. Before we can insert "1", we need to make sure there isn't a "1" in there first - we want do that in a way that uses the lowest lock possible - in this case a share. It would become exclusive when we actually insert the row - which we are blocked from doing right now.

1.From the above,I still not find the diffrence of update and insert on table with PK.
When update blocking,the bocked session aslo
NEED TO MAKE SURE THERE ISN'T A "1" IN THERE FIST.
Why we can't see a 4 lmode lock request?
2.Sorry Tom,I still want to know what the tx lmode=6 was of sid=152,it has been blocked ,how can it hold a tx 6 lock?

I past the tests here again:

SQL> create table t(x int primary key,y int);    
table created

SQL>  insert into t values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> update t set x=2;
                                
1 row updated.            

 
         
--open another session:
         

SQL> update t set y=2 where x=1;
 
      
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid in (159,152) order by 1;     
                                                               
                                                                                
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK            
---------- -- ---------- ---------- ---------- ---------- ----------            
       152 TM      64626          0          3          0          0            
       152 TX     131078       5346          0          6          0            
       159 TX     131078       5346          6          0          1            
       159 TM      64626          0          3          0          0            
                                                                           


--I can understand this ,but

SQL> drop table t purge;

Table dropped.

SQL> create table t (x int primary key,y int);

Table created.



SQL> insert into t values(1,1);

1 row created.

---open another session:

SQL>SQL> insert into t values(1,1);
                
 SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid in (159,152) order by 1;    
                                                                                             
       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK            
---------- -- ---------- ---------- ---------- ---------- ----------            
       152 TX     131097       5339          0          4          0            
       152 TM      64626          0          3          0          0            
       152 TX     524291       5327          6          0          0            
       159 TX     131097       5339          6          0          1            
       159 TM      64626          0          3          0          0             
SQL>          


the sid=159 the the blocking session ,sid=152 is the blocked session. the object with TM lock is the table T.

I am so comfused with it,want your a more detail explain.

Regards
Alan




Tom Kyte
February 15, 2010 - 11:06 am UTC

the update is trying to update an existing row, the insert is trying to insert a row that does not yet technically 'exist', these cannot even be compared, they are doing two entirely different things, entirely different.


the second case you have working with data against data that technically doesn't exist yet. They are different.

still not clear of the diffrence of update and insert on table with PK

Oleksandr Alesinskyy, February 15, 2010 - 12:56 pm UTC

Hm, if update changes the value of the primary key to one that does not exist yet - where is so big difference from insert (yes, such update is a bad practice, but let us forget it for a moment).
Tom Kyte
February 16, 2010 - 5:11 pm UTC

the update is trying to update a row that it can see (consistent read says "x=1" is there, trying to get the exclusive lock on that row to update it blocks).

the insert is trying to insert a row that does not yet "exist"


they are entirely different transactions. In the update case - two sessions are trying to modify the same exact row at the same exact time. In the insert case - there is this magic "I don't exist, you cannot see me" row that is blocking the second session. They are totally different cases, not even similar in nature (to me)

foreign key locking

A reader, February 16, 2010 - 6:21 pm UTC

Hi Tom,

Could you please explain the locking behaviour on below site

http://jonathanlewis.wordpress.com/2010/02/15/lock-horror/



Tom Kyte
February 17, 2010 - 8:52 am UTC

I read that before - Jonathan seems to have covered what is happening in painstaking detail. It doesn't look like it should be that way (which was sort of mentioned). What more could I possibly add to that?????

Oleksandr Alesinskyy, February 19, 2010 - 9:37 am UTC

In the update case - two sessions are trying to modify the same exact row at the same exact time. In the insert case - there is this magic "I don't exist, you cannot see me" row that is blocking the second session. They are totally different cases, not even similar in nature (to me)
Not exactly - imagine the following situation - 2 updates strive to update primary keys of 2 different rows in the table to the same value that does not yet exist in the table - is it so much different from the insert?

E.g.
create table MUMU (x number(1) primary key);
insert into MUMU values(1);
insert into MUMU values(2);
commit;
update MUMU set x=3 where x=1;

from another session
update MUMU set x=3 where x=2;

Where is a huge difference from
insert into MUMU values(4);

from another session
insert into MUMU values(4);

In both cases 2 sessions try in parallel to add the same new non-existing value to the primary key.



Thank you!

A reader, February 19, 2010 - 7:15 pm UTC


Your test case of March 16, 2004

Viveka, February 22, 2010 - 3:07 am UTC

I tried to reproduce the test case given by you on "

What about regular UPDATE   March 16, 2004 - 6pm Central time zone" above. I could not.

Is there a difference in Oracle 10g? Please help.


SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE    10.2.0.1.0      Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

SQL> create table emp as select * from scott.emp_classic;

Table created.

SQL> lock table emp in share mode;

Table(s) Locked.

SQL> declare
  2          pragma autonomous_transaction;
  3  begin
  4          for x in ( select ename from emp where rownum = 1 for update )
  5          loop
  6                  dbms_output.put_line( 'locked ' || x.ename );
  7          end loop;
  8          commit;
  9  end;
 10  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4

Tom Kyte
March 01, 2010 - 6:37 am UTC

Yes, there is - in fact, it was some release of 9ir2 - select for update takes a slighter higher version of the lock now (in response to a necessary change in behavior to correct a "product issue")

enq ST - contention,

A reader, March 02, 2010 - 12:43 pm UTC

Hello,

The AWR report on my 15 TB 3-node RAC database is constantly showing enq: ST - contention as top most wait event. The avg wait (ms) is 480.

In my database (10.2.0.4) on RHEL 4.0, system tablespace is dictionary managed and almost all other tablespaces are locally managed. Datafiles are managed by ASM. My database is growing at 150 GB per day that may indicate lot of transactions.


How to identify what is causing enq: ST- contention? Can this contention cause slowness in our application? Finally, how to fix it?

Thanks,

Tom Kyte
March 02, 2010 - 12:55 pm UTC

there will always be a topmost timed event - no matter what you do.

is this an identified performance issue? If I told you my average wait at a stop light was 50 seconds - is that a performance issue?

answer 1: yes, because my entire drive was 5 minutes and I waited 4 times.

answer 2: no, because my entire drive was 10 hours and I waited once.


so, give us more information to help us understand if this is a real problem that needs to be looked at.


enq - follow up,

A reader, March 02, 2010 - 1:42 pm UTC

Hello,

Traffic light example was the good one.

Ok, let me give you some other information: We have a production single instance database on Sun OS which is of the same size and exact same number of data loads. This Sun box is eventually going to be retired once our 3-node database is caught up from data point of view. On Sun box, I don't see enq: ST wait event in the top 5 list. Comparing these two databases is not apples to apples comparison, but from the data load point of view they almost are.

I agree there will always be wait events and one of them will always be top, but why enq: ST contention? Is there a way to push it down from top to somewhere at the bottom?

Top 5 wait events:

enq: ST - contention 161,389 77,627 481 63.5 Configuration
CPU time 22,396 18.3
db file sequential read 7,407,211 11,759 2 9.6 User I/O
row cache lock 4,965,331 3,995 1 3.3 Concurrency
PX Deq Credit: send blkd 692,048 3,358 5 2.7 Other



Tom Kyte
March 02, 2010 - 2:08 pm UTC

can you format that so we all can read it, headings would be nice, columns that line up.

... Is there a way to push it down from top to
somewhere at the bottom?
...

we could introduce some heavy IO waits, that would probably do it. Or run every query with "for update", that would almost surely do it.

All kidding aside, let's see if you have a problem first.

How long of a report was this for?
Can you include headings for all to see?
Can you make the columns line up so we can read it?
Can you describe what in general was taking place when you ran this?
Do you have access to ASH?

enq - follow up,

A reader, March 02, 2010 - 5:21 pm UTC

Hello,

How long of a report was this for?
This report is for the 12 hours starting from 7:00am - 7:00pm CST

Can you include headings for all to see?
Sure. Here is the information with formatting.. (sorry for not formating it earlier)
Event Waits Time(s) Avg Wait(ms) % Total Call Time Wait Class
-------------------------------------------------------------------------------------
enq: ST - contention 161,389 77,627 481 63.5 Configuration
CPU time 22,396 18.3
db file sequential read 7,407,211 11,759 2 9.6 User I/O
row cache lock 4,965,331 3,995 1 3.3 Concurrency
PX Deq Credit: send 692,048 3,358 5 2.7 Other
blkd


Can you make the columns line up so we can read it?
Did that.
Can you describe what in general was taking place when you ran this?
In our database, 90% of the time it is data loading. The data is loaded using MERGE statement. Besides data loading, we create indexes within the pl/sql packages and drop them at the end.

Do you have access to ASH?
I have. I will look into it in detail.

Thanks for your time.


Tom Kyte
March 02, 2010 - 7:59 pm UTC

can you verify that all tablespaces except system are locally managed.

and verify that system is not being used for stuff - anything other then dictionary data (and that system is not growing rapidly)


enq - follow up,

A reader, March 03, 2010 - 10:27 am UTC

Good catch. I have couple of my own tables which I use for capturing database information (from v$sqlarea) which was put in SYSTEM tablespace. I insert into these tables every 3 hours. Now I moved it to USERS tablespace.

Apart from that there are 4 other tablespaces which are DICTIONARY managed but the objects in that tablespace hardly has any activity.

One other thing I noticed is, SYSTEM tablespace has lots of recycle bin objects. We have turned on RECYCLEBIN parameter which I think we need to turn it off.

If I have recycle bin objects like NESTED TABLE, LOBSEGMENT, LOGINDEX, how can I purge them?

Thanks for the great question you asked.


Tom Kyte
March 03, 2010 - 11:08 am UTC

... One other thing I noticed is, SYSTEM tablespace has lots of recycle bin
objects. We have turned on RECYCLEBIN parameter which I think we need to turn
it off.
...

how so? you have things in the recyclebin in the SYSTEM tablespace? Stop using system!!! therein lies part of your problem, you are creating and dropping lots of stuff in system.

STOP USING SYSTEM - that is a big mistake. Your load process must create and drop lots of stuff. It is creating the tables in some tablespace other than system - but the 'sub-objects' like nested tablespace and lobs are going into system - fix that, right now.


lock released too early

Michal Pravda, March 23, 2010 - 10:27 am UTC

Hello Tom,

I've got a system to maintain which has a queue table (I think it is a bookexample for dbms_aq, but that is another topic :(). Long story short I wanted to truncate the table to get rid of bad records and reset HWM but it failed (on ORA-00054: Resource busy and acquire with NOWAIT specified) because another session wanted to write into it.

How can I prevent that fail? I know that DDLs do "commit, ddl, commit", does truncate do the same? If so why it doesn't get some sort of lock or priority to do the stuff I want here?

Here's cut to the bone example which resembles with the same output what i was doing.
session 1:
create table tt (i int);
lock table tt in exclusive mode;
session 2:
insert into tt values (1); --waits for session 1 as expected
session 1:
truncate table tt;
=> ora 0054 resource busy. --why?? wasn't the exclusive lock supposed to prevent this?


Tom Kyte
March 23, 2010 - 12:49 pm UTC

truncate is ddl, and just like any ddl - commits before and after it starts/completes.

truncate also needs exclusive access to the table.

the exclusive lock in your above timeline - it was given up the nanosecond you issued truncate, because truncate operates like this (as does DDL in general)

begin
   COMMIT;
   do the truncate;
   commit;
exception
   when others
   then
         ROLLBACK;
         raise;
end;



In 11g (no version :( ) you can:

alter session set ddl_lock_timeout = N;

where N is the number of seconds you would like the truncate to block (and to block new transactions from starting) and wait to try to truncate. That is, you can make DDL wait.





truncating table safely

Michal Pravda, March 24, 2010 - 1:09 am UTC

Ok, better than nothing i guess, but it doesn't solve the problem, it just delays it. And in the meantime the table can get other records, which will get truncated but wasn't backed up for example.

What would you suggest in a scenario: I've got a table with a lot of rows and want them removed from that table but saved to some other and hwm lowered? and preferably do all this transparently to any other session so they don't fail on insert. My intended approach (lock -> backup -> truncate) doesn't work...
Tom Kyte
March 24, 2010 - 6:03 am UTC

your solution would not solve the problem either, it just delays it - if your lock table worked, how would it *solve* the problem???


How about this, you tell us what your GOAL IS, don't present code that doesn't work and expect us to reverse engineer it and have us figure out what you are trying to do.

so, now we know your goal:

... I've got a table with a lot of rows and
want them removed from that table but saved to some other and hwm lowered? and
preferably do all this transparently to any other session so they don't fail on
insert. My intended approach (lock -> backup -> truncate) doesn't work... ..


I would suggest:


You have your table, call it 'A'
you have a synonym T that points to A

you create table b as select * from a where 1=0;
you create or replace synonym T for B

your application now uses B instead of A. You have A to do with as you please. You could add A as a partition to some existing history table or leave it as it is.


You do this process every time you want to "archive"



working with table

Michal Pravda, March 25, 2010 - 6:38 am UTC

Hello,
your proposed "synonym" solution works nicely, I tested it. Thank you. It has one tiny problem of having to have synonyms present when a problem arises. Which is probably a best practice anyway, but is not 100% followed here :(. I'll look up the exact name resolution order in the documentation and then follow accordingly.

"your solution would not solve the problem either, it just delays it - if your lock table worked, how would it *solve* the problem??? "
It would clear ("archive" - I never thought of the problem from this perspective, but it really did resemble archiving) the table without failing and without affecting other sessions more than pausing them for a while.
The plan was: lock the table to get exclusive access (and be able to atomically backup rows and truncate table) -> backup up all present rows -> clear the table -> unlock it. I didn't know that truncate would release the lock (before trying to acquire it again) for a moment and therefore break the planned atomicity.

"How about this, you tell us what your GOAL IS, don't present code that doesn't work and expect us to reverse engineer it and have us figure out what you are trying to do."
I intended to state my goal (and honestly I think I did). I do apologize that I wasn't clear enough. This service is of an incredible value (and yet it's free), I don't want to waste it with impossible questions. Thank you very much for doing it.

Exclusive Locks on OWB

MiM, June 22, 2010 - 6:36 am UTC

Hi Tom

Needs a bit of clarity/comment from you on the below:
1. APPEND hint in a INSERT statement of OWB Mapping locks the table invoved as exclusively and no other session can insert rows simultaneously even though its in PARALLEL mode. For Eg: INSERT /*+ APPEND PARALLEL("IND1") */ INTO "TAB1"
2. By default, OWB considers "APPEND" mode even though it has not been explicitly mentioned and negate it "NO APPEND" has to be hinted. For Eg: INSERT /*+ NO APPEND PARALLEL("IND1") */ INTO "TAB1"

Expert comments please
Tom Kyte
June 22, 2010 - 1:51 pm UTC

1) correct, if the append hint is followed - then the segment that is being direct path loaded will be locked by that session.


2) if you see
insert /*+ NO APPEND */
that would actually be the same as INSERT /*+ APPEND */, NOAPPEND would be one word.

If OWB is running with parallel dml (PDML), then append would be assumed. If not, no, it would not be.

Table Lock Disable.

Snehasish Das, July 14, 2010 - 3:47 am UTC

Hi Tom ,

we are in oracle 10.2.0.2.0 version.

SQL >alter table sf_stg9A disable table lock;

Table altered.

Elapsed: 00:00:01.22
SQL >drop table sf_stg9A purge;
drop table sf_stg9A purge
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for sf_stg9A


Elapsed: 00:00:01.53
SQL >alter table sf_stg9A enable table lock;
alter table sf_stg9A enable table lock
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified


Elapsed: 00:02:10.79
SQL >commit;

Commit complete.

Elapsed: 00:00:01.11
SQL >alter table sf_stg9A enable table lock;
alter table sf_stg9A enable table lock
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

I Read the previous reviews and the metalink review too. I guess this was fixed in 10.2 , Please let us know if it was otherwise also please let us know a method to enable to table lock , ours is a mutiuser RAC environment.

Please help.

Concurrent Booking

Abhisek, January 25, 2011 - 2:04 am UTC

Hi Tom,

I have a scenario of Ticket Booking System. Suppose we have to enable bulk reservation (more than 1 tickets will be booked at the same time). Now, suppose I have 25 tickets left.

One gentleman wants to book 15 tickets over a counter. On the next counters at the same time, we have another customer who wants to book 8 and 3 tickets respectively. Now how do we implement this logic in Oracle that the customer is enabled to do a bulk booking, based on tickets booked. Can it be done through row-level locking?

At the end of trancation, my desired result is:

Customer A : gets all 15 tickets(Highest priority)
Customer B : gets his 8 only after customer A gets
Customer C : gets the remaining after Cusomer A and B ahve theirs.

Please suggest
Tom Kyte
February 01, 2011 - 10:26 am UTC

sounds like you just need to lock the table - you want everyone to go one after the other - we'll queue them up.

Is that what you really want though - one transaction at a time?

Transaction Queue

Abhisek, February 02, 2011 - 3:59 am UTC

Hi Tom,

Yes, you are correct. I want to do a transaction at a single time. The only concern is: In a scenario where flight booking is done, there can be three customers booking the tickets at different counters at the same time. Now I have to decide which customer has the highest priority in terms of number of tickets, getting booked.

Customer A: books 10 tickets(Priority 2)
Customer B: books 15 tickets(Priority 1)
Customer C: books 5 tickets(Priority 3)
Tom Kyte
February 02, 2011 - 7:54 am UTC

well, I have to leave it to YOU to figure out the priority - only you can do that - but all you need to do is use the "lock table" command to serialize, it'll be that simple.

There isn't much information to go on here. Don't know if this is a client server application (lock table works) or a stateless 3 tier one (lock table doesn't work, you are stateless, you lose your locks after each page)

If you are stateless, sounds like AQ (Advanced Queues, part of the database) would be the thing to look at. Your customers put requests into a queue. They can be prioritized. One process would dequeue from the queue and process the request.

Regading lock and partition exchange

Jim, March 07, 2011 - 4:15 pm UTC

Hi, Tom,

I have a question regarding locking and partition exchange and I couldn't find any topic regarding this anywhere and I was wondering if you could help.

At the moment, I am loading a big set of data and I am doing trunc and reload ( don't ask me why). Since the data might be actively used, we are debating two approaches.

1.) Create two tables and one view. We first trunc and load one table and then point that view to the newly populated the table and then trunc and load the other and point view to the other. ( We load data once a week).

2.) create one regular table and one partition table with only one partition. we trunc and load that regular table and partition exchange to the partitioned table.

I think the second approach is better but the first one just does the job except that we might need to maintain some metadata to see which one is current. Other than that, is there any benefit using the second approach ( or some other one you can suggest )?

Thanks a lot,
Tom Kyte
March 08, 2011 - 12:38 pm UTC

they are both sound. You could also just use a synonym (create or replace synonym T for T1, create or replace synonym T for T2) instead of a view. For such a simple process, I would probably just use the two table and synonym approach, perhaps using last_analyzed_time to determine which is "older" and should be replaced.

How about lock?

Jim, March 08, 2011 - 3:12 pm UTC

Hi, Tom,

Thank you for your reply.
The point I am more interested in is that what if the underline tables are being used by some long running process?
will the create synonym/view or partition exchange fail because the table is locked?

to make things clear. Here is the scenario.
1.) T1 is populated.
2.) some query against T1 is issued and is running for a long time.
3.) we issue create synonym/view or partition exchange to point T to T2.
4.) will it fail ? how does this impact the existing query for each scenario? ( view/ synonym / partition exchange). Are they pretty much the same or there are some implications?

Thanks
Tom Kyte
March 08, 2011 - 3:37 pm UTC

4) it will not fail - the query will continue to run against the old objects as long as you do not drop them.

help on this

Venkata, June 01, 2011 - 2:20 am UTC

Tom,

I have a situation here, i have a procedure p1 in a package x1. The procedure structure is as below, my question is (might seem to be nonsence to you) will i get deadloack error, anywhere (particularly in the merge statement) if i call this procedure at the same time from multiple sessions.

update table t1 set col1 = 99 where col1 = 0;

update table t2 set col2 = 99 where col2 = 0;

update table t3 set col3 = 99 where col3 = 0;

commit;

for i in 1..userenv('sessionid') loop
null;
end loop;

lock table mytable in exclusive mode;

merge into mytable using....;

commit;

Tom Kyte
June 01, 2011 - 8:52 am UTC

question for you - are you observing a deadlock?

the updates look OK - as long as they represent the entire transaction (there is nothing that happens before them that we don't see here).


The merge into mytable looks ok as long as it is not a parent table in a primary/foreign key relationship and the child tables foreign key is not indexed.

If you merge into a parent table that has a child with an unindexed foreign key - we'll attempt to lock the child table under certain circumstances.

lock

sam, June 01, 2011 - 9:26 am UTC

Tom:

If USER1 locks the table T1, it will lock the table for DML (insert ,update, delete) for all other sessions until transaction completes.

Can't the wait by other sessions for the main transaction to complete eventually turn into deadlocks if transaction took a while to complete?


Tom Kyte
June 01, 2011 - 2:37 pm UTC

Sam,

lay it out, tell us the sequence of steps necessary. Use your knowledge of how it works to tell us what sequence of steps it would take to get a deadlock.

A deadlock doesn't happen because you hold a lock for a long time, it has nothing to do with duration.

It has everything to do with two (or more) sessions requiring locks on objects that the other sessions have.


session 1 locks resource A (I don't care if A is a table, a row, a user defined lock - whatever)

session 2 locks resource B (ditto on the i don't care)

session 1 tries to lock B, is blocked by session 2 (and can remain blocked forever, that would not deadlock)

session 2 tries to lock A, gets blocked by session 1 and shortly we'll discover DEADLOCK.



not much clear

venkata, June 02, 2011 - 2:41 am UTC

Tom,

I am getting deadlock, but not able to find out if its after locking or before locking in update statements i mentioned in the pseudo code. The code seems to be fine, when run in realtime we get errors i think. can you please help it.
Tom Kyte
June 02, 2011 - 9:06 am UTC

did you review the trace files that are generated.

Lock

Sunny gambhir, July 01, 2011 - 8:59 pm UTC

I have question regarding locking
Why do Query1 and Query2 running in different sessions
are blocking each other( dependant on each other)
Query2 is waiting for Query1 to commit.
But if i do not commit query1 , then Query2 goes into wait


1. Query1 (running in Session1):-

INSERT /*+ parallel(claim 24) */
INTO ABC(CLM_SEQ_NBR)
SELECT /*+ parallel(fclm 24) */
FCLM.CLM_SEQ_NBR,
FROM XYZ FCLM
WHERE NVL(FCLM.TEM_CLM, 0) = 0
OR FCLM.TEM_CLM= FCLM.CLM_SEQ_NBR;
2.Query2(running in Session2):-
UPDATE /*+ PARALLEL(S.C 24)*/
(SELECT /*+ PARALLEL(FCLM 24) use_hash(FCLM C)*/
C.C_ID A1,
C.SAT_CD B1
FROM ABC C, XYZ FCLM
WHERE C.CLM_SEQ_NBR = FCLM.CLM_SEQ_NBR
AND NVL(TEM_CLM, 0) <> 0) S
SET A1 = A2

Query2 is waiting for Query1 to commit.
But if i do not commit query1 , then Query2 goes into wait

Above two queries are running in parallel, rows inserted and rows updated are mutually exclusive.( Rows which are inserted from XYZ into ABC & Rows which are updated from XYZ into ABC are different with no dependancy)

All foreign constraints are disabled for above tables.



Tom Kyte
July 05, 2011 - 7:40 am UTC

parallel dml (pdml) locks all segments it touches. The first pdml statement hits ABC(clm_seq_nbr) and locks it.

The second hits abc and locks it.

maybe you should see if you can code this as a single DML - a merge statement, they can insert and update at once. I didn't look into whether you could or not - just an idea to think about.

Locks while inserting

Arvind Mishra, July 20, 2011 - 11:29 pm UTC

Hi Tom,

I am just checking Oracle locking. I have a table with primary key column and I am trying to insert rows from two different sessions having same primary key value. One of my session is blocked and when I check the v$lock I found following:

SQL>  select username, v$lock.sid, trunc(id1/power(2,16)) rbs, id2 seq, lmode, request,id1
  2   from v$lock, v$session
  3   where v$lock.type = 'TX'
  4   and  v$lock.sid = v$session.sid
  5   and v$session.username = user
  6  /

USERNAME                              SID        RBS        SEQ      LMODE
------------------------------ ---------- ---------- ---------- ----------
   REQUEST        ID1        ID2
---------- ---------- ----------
SCOTT                                 142          3        740          0
         4     196641        740

SCOTT                                 138          3        740          6
         0     196641        740

SCOTT                                 142          9        872          6
         0     589829        872

My question are:

*why there is another row for session 142 with request = 4? (It should be 6).

*why there are two rows for session 142 when I am inserting only one row?

Regards,

Arvind

Tom Kyte
July 22, 2011 - 1:39 pm UTC

o we attempt to take the lock at the lowest level and then raise it up as needed. To initiate the insert - start at 4, then go to 6.


o the one TX row for each transaction is your transaction row. the other one - that is blocked - is for your enqueue wait, it'll go away when the thing blocking you goes away

I like this little script to see blockers/blockee's

ops$tkyte%ORA11GR2> select
  2        (select username from v$session where sid=a.sid) blocker,
  3         a.sid,
  4        ' is blocking ',
  5         (select username from v$session where sid=b.sid) blockee,
  6             b.sid
  7    from v$lock a, v$lock b
  8   where a.block = 1
  9     and b.request > 0
 10     and a.id1 = b.id1
 11     and a.id2 = b.id2;

BLOCKER                               SID 'ISBLOCKING'  BLOCKEE                               SID
------------------------------ ---------- ------------- ------------------------------ ----------
OPS$TKYTE                              69  is blocking  OPS$TKYTE                             197

Windows locking issue on datafiles

Rahul, November 22, 2011 - 1:28 am UTC

Hi Tom,
We are having Oracle database (10.2.0.3) on Windows 2003 (R2 Standard Edition) server. We have database residing on the server, however, the issue is that the database is getting shutdown due to some errors. When we check the alert.log, we understand that some OS process is locking the database files due to which the database is getting shutdown every day around 3.15 - 3.45 am.


The error as per alert.log is as below;

Errors in file f:\oracle\product\10.2.0\admin\orclint\bdump\orclint_ckpt_7680.trc:
ORA-00206: error in writing (block 3, # blocks 1) of control file
ORA-00202: control file: 'F:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCLINT\CONTROL02.CTL'
ORA-27072: File I/O error
OSD-04008: WriteFile() failure, unable to write to file
O/S-Error: (OS 33) The process cannot access the file because another process has locked a portion of the file.

When we check the orclint_ckpt_7680.trc file, we have;

Dump file f:\oracle\product\10.2.0\admin\orclint\bdump\orclint_ckpt_7680.trc
Sat Nov 19 03:22:15 2011
ORACLE V10.2.0.3.0 - Production vsnsta=0
vsnsql=14 vsnxtr=3
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
Windows NT Version V5.2 Service Pack 2
CPU : 2 - type 586, 2 Physical Cores
Process Affinity : 0x00000000
Memory (Avail/Total): Ph:475M/2047M, Ph+PgF:934M/3434M, VA:1266M/2047M
Instance name: orclint

Redo thread mounted by this instance: 1

Oracle process number: 7

Windows thread id: 7680, image: ORACLE.EXE (CKPT)


*** 2011-11-19 03:22:15.440
*** SERVICE NAME:(SYS$BACKGROUND) 2011-11-19 03:22:15.409
*** SESSION ID:(165.1) 2011-11-19 03:22:15.409
ORA-00206: error in writing (block 3, # blocks 1) of control file
ORA-00202: control file: 'F:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCLINT\CONTROL02.CTL'
ORA-27072: File I/O error
OSD-04008: WriteFile() failure, unable to write to file
O/S-Error: (OS 33) The process cannot access the file because another process has locked a portion of the file.
error 221 detected in background process
ORA-00221: error on write to control file
ORA-00206: error in writing (block 3, # blocks 1) of control file
ORA-00202: control file: 'F:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCLINT\CONTROL02.CTL'
ORA-27072: File I/O error
OSD-04008: WriteFile() failure, unable to write to file
O/S-Error: (OS 33) The process cannot access the file because another process has locked a portion of the file.


We have disabled the Antivirus and checked, still the problem exists. We need additional help in identifying the OS process that might be locking the datafiles.Also, when we check the Windows Event Log, it shows nothing wrt the same.

Please help us with the issue.

Thanks,
Rahul

Tom Kyte
November 22, 2011 - 8:13 am UTC

you have someone running a filesystem backup. Tell them to STOP doing that to the database files - since those backups would be *useless* anyway.

find your system admins and ask them when they do their full file system backups. You'll find that they probably start that at, oh, probably around 3am :)

Inserts also Blocks

Raghu, July 05, 2012 - 2:11 am UTC

Hi Tom,
Thanks for all the help you provide for Oracle community.

Until today i was thinking that Inserts will never block another insert,whatsoever the conditions be.
But i was surprised to know, that it does block when we have a Primary key and trying to insert same value from another session.

create table temp_a(col1 number primary key,col2 varchar2(10));

From Session1:
insert into temp_a values (1,'proc1');
insert into temp_a values (2,'proc1');
Do not commit yet

From Session 2:
insert into temp_a values (2,'proc1');
This keeps waiting until we complete the transaction in Session1.

The way i thought it would work was, inserts would go fine in both sessions and the first session commits and when we try to commit in second session it will fail.
Can you please shed some light on this behavior in Oracle.
Thanks.




Tom Kyte
July 05, 2012 - 8:41 am UTC

why would that surprise you?


statements fail by default, not transactions.

A statement is validated as it is happening, when the statement completes, you can assume a commit will succeed unless some fatal error occurs. You would not expect a transaction that just issued 50 sql statements to fail upon commit with a constraint violation (only if you were using deferrable constraints)

pretty much all relational databases work this way.

Inserts also Blocks

Raghu, July 05, 2012 - 9:20 am UTC

Thanks for your reply Tom.

Query timeout !!

Ankit, September 07, 2012 - 5:45 am UTC

Hi Tom.
Thanks a ton for your guidance.

I need to know:
1) What general steps should we follow when there is query timeout issue ? I know about missing indexes, tuning (hints) etc. Anything else ? When should we think about partitioning ?

2) I am facing a weird problem. At 11 PM everyday, one of our job kicks off and process records one by one. Till 12:30, I noticed, it gave query timeout error for each record and logged it, but after 12:30, every record gets processed successfully. This is happening for last one week in PROD. Before that, there was no such issue and everything was ok. I tested in DEV, but there was no problem in DEV.

I understand that more data may cause delays, but its happening initially, after that, it goes fine.
Please guide.

Thanks a lot.
Tom Kyte
September 10, 2012 - 8:07 pm UTC

1) not really sure what to say here. query timeout is a very 'personal' thing. I've *never* had a query time out on me.

that is because I know how long (approximately) my queries will take prior to production runs. but.... anyway....

sometimes a query runs "slow" because an index exists and was used.
sometimes a query runs "slow" because an index doesn't exist.
sometimes a query runs "slow" because a table or tables wasn't partitioned
sometimes a query runs "slow" because a table or tables were partitioned

and so on, and so on.

2) slow by slow processing, ugh. hate it.

what is a query timeout? we have no such concept.

strange blocking!

A reader, September 12, 2012 - 9:59 pm UTC

Tom,
Here is a test made on oracle11gr2,please tell me who bock sid=7:

session 1
sql>create table t(id int);
sql>lock table t in share mode;

session 2
sql>lock table t in share mode;
sql> insert into t values (1);

session 3
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid in (133,7) and type in ('TM','TX');

       SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
       133 TM      74979          0          4          5          1
         7 TM      74979          0          4          0          1

Regards
Alan
Tom Kyte
September 14, 2012 - 6:40 pm UTC

if you use this query:

select
      (select username from v$session where sid=a.sid) blocker,
       a.sid,
      ' is blocking ',
       (select username from v$session where sid=b.sid) blockee,
           b.sid
  from v$lock a, v$lock b
 where a.block = 1
   and b.request > 0
   and a.id1 = b.id1
   and a.id2 = b.id2
/


you'll see the anomaly, the session is reported as blocking itself (which is obviously not correct - but relatively harmless).

You have a really good simple small test case - can you file a bug against it?

not strange

DarrenL, September 13, 2012 - 7:23 am UTC

@Alan .

not sure why you think that is strange.

session 2
sql>lock table t in share mode;
sql> insert into t values (1);

session 2 will lock on the insert, as you've specified
lock table t in share mode;
in session 1. so session 2 cannot actually update the table until session 1 releases its lock.
Tom Kyte
September 14, 2012 - 6:43 pm UTC

he was commenting on the block column - why are both of them showing as blocking someone...

Altering the locked table.

Sagar, September 19, 2012 - 1:35 pm UTC

Hi Tom,

On oracle 11g:

Session one:

gorav@XE> select * from t1;

         N
----------
         1
         2
         3

gorav@XE> update t1
  2  set n=10;

3 rows updated.



Session two:

gorav@XE> alter table t1 add m number;

[[No response from oracle: Wait]]


Session One:

gorav@XE> Alter table t1 add m number;
Alter table t1 add m number
                   *
ERROR at line 1:
ORA-01430: column being added already exists in table


Session two:

gorav@XE> alter table t1 add m number;

Table altered.

----------------

1)Why table t1 got altered by session two when i execute the          Alter command in session one.

2)Is X lock on definition implemented in a queue so Session two was served first for X lock on definition.

3)The sequence of locking (What i understood is):
   a) X lock on Row and shared lock on the definition of table t1 ( by session one)
   b) X lock on the definition of t1 ( by session two)
   c) X lock on definition of t1 ( by session one)

Now i assume that at a single moment, a session can have only one type of lock on the definition of table, so shared lock on table t1 by session one( step a) is replaced by in-waiting X lock by step c.

I am missing some vital point here, Kindly help.

Thanks.

 



Tom Kyte
September 20, 2012 - 5:51 am UTC

when you issued the alter in sessoin1 (the session that did the update), the alter starts by committing - which unblocked the other session which added column M - which you tried to add again.

DDL commits, does work, commits.

the first step of the alter was to commit - the other session was free to create the column

Partly indexed FK

Lise, October 02, 2012 - 10:25 am UTC

Hi,

Imagine that I have the following scenario:

table p (col1, col2, col3..)
primary key on col1 and col2

table c (col1, col2, col4..)
primary key on col1.

foreign key from c to p on col1 and col2.

There are several rows on p which are updated by lots of parallel sessions, but each session will never update a row that the other session is updating.

There is no data in c.

What will happen to locking of table c in these cases when the index (PK) on table c is just partly containing all the columns that are part of the FK?
Will it do a row lock exclusive on all the rows (is that even possible?) or a full table lock on c?

Any advice greatly appreciated.

Thanks
Tom Kyte
October 09, 2012 - 11:38 am UTC

do you delete from p?
do you update p.col1/col2 (the key??)
do you merge into p?

if not, no additional locking for the foreign key is done.

if so, you will get a full table lock on C during the duration of the delete/update or merge statement.

and the lock is in 'share mode', many sessions can have it simultaneously;



waiting session sql

samar, October 25, 2012 - 12:07 pm UTC

Hello,

I tries test case like"

As user A
1- create table test as select * from dba_objects;
update test set owner='ABCD';

session B
select count(*) from A.test;
update test set owner='PQRS';
<This waits>

I tried catching the blocking and waiting sid and corresponding sql stmt.

For the blocking session I get the UPDATE stmt from the v$sql/v$sqlarea, but the waiting session shows as "select count(*) from A.test;"

Waiting session does not show the actual UPDATE stmt.
A graphical monitoring tool like TOAD etc. shows the correct sql.

Is there ant v$views to get the waiting session sql?

Thanks.
Samar
Tom Kyte
October 28, 2012 - 10:24 pm UTC

well, when I use my "showsql" script that shows sessions currently executing sql, I see the update. I have no idea what query you tried....

just take the sql_address from v$session and join to v$sql or any of the v$sql like views


ops$tkyte%ORA11GR2> set feedback off
ops$tkyte%ORA11GR2> 
ops$tkyte%ORA11GR2> column username format a20
ops$tkyte%ORA11GR2> column sql_text format a55 word_wrapped
ops$tkyte%ORA11GR2> 
ops$tkyte%ORA11GR2> set serveroutput on size 1000000
ops$tkyte%ORA11GR2> declare
  2      x number;
  3          pid number;
  4  procedure p ( p_str in varchar2 )
  5  is
  6     l_str   long := p_str;
  7  begin
  8     loop
  9        exit when l_str is null;
 10        dbms_output.put_line( substr( l_str, 1, 250 ) );
 11        l_str := substr( l_str, 251 );
 12     end loop;
 13  end;
 14  begin
 15      for x in
 16      ( select username||'('||sid||','||serial#||
 17                  ') ospid = ' ||  process ||
 18                                  ' command = ' || command ||
 19                  ' program = ' || program username,
 20               to_char(LOGON_TIME,' Day HH24:MI') logon_time,
 21               to_char(sysdate,' Day HH24:MI') current_time,
 22               sql_address, LAST_CALL_ET, sid, paddr
 23          from v$session
 24         where status = 'ACTIVE'
 25               and sid <> ( select sid from v$mystat where rownum = 1 )
 26           and rawtohex(sql_address) <> '00'
 27           and username is not null order by last_call_et )
 28      loop
 29                  select max(spid) into pid from v$process where addr = x.paddr;
 30  
 31          dbms_output.put_line( '--------------------' );
 32          dbms_output.put_line( x.username || ' dedicated server=' || pid );
 33          dbms_output.put_line( x.logon_time || ' ' ||
 34                                                    x.current_time||
 35                                                    ' last et = ' ||
 36                                                    x.LAST_CALL_ET);
 37          for y in ( select sql_text
 38                       from v$sqltext_with_newlines
 39                      where address = x.sql_address
 40                                            order by piece )
 41          loop
 42                          p( y.sql_text );
 43          end loop;
 44  
 45      end loop;
 46  end;
 47  /
--------------------
OPS$TKYTE(152,651) ospid = 16199 command = 6 program = sqlplus@localhost.localdomain (TNS V1-V3) dedicated server=16200
Thursday  10:58  Sunday    23:23 last et = 12
update t set owner = 'xyz'
ops$tkyte%ORA11GR2> 

"TO" Lock type

Jeff, November 20, 2012 - 12:04 am UTC

Hi Tom,

If I query v$lock I can see a large number of locks
with a lock type of "TO"

To keep the result se small I ran this
select distinct type from v$lock
and got the following

RS
RT
CF
XR
MR
JQ
TO
TM
TX
TS

We are running 10GR2 so I checked the doco on v$lock here
http://docs.oracle.com/cd/B19306_01/server.102/b14237/dynviews_1147.htm#g1427852
No mention of type TO.

Could you please let me know what a TO type lock is please
Thankyou
Jeff


Tom Kyte
November 20, 2012 - 8:34 am UTC

temporary object

a lock taken to prevent DDL on temporary tables whilst someone is using it.

since we all know you don't do DDL in production OLTP systems - this shouldn't be causing any issues. It would only be blocking if someone is trying to do DDL on a temporary table while there is outstanding DML on it.

ORA-00060: deadlock HELP

A reader, November 26, 2012 - 5:02 am UTC

Hi Tom, 
SQL> select
  2      sid,
  3      sql_text
  4  from
  5      v$session s,
  6      v$sql q
  7  where
  8      sid in
  9      (select
 10         sid
 11      from
 12         v$session
 13     where
 14         state in ('WAITING')
 15     and
 16         wait_class != 'Idle'
 17     and
 18         event='enq: TM - contention'
 19     and
 20        (q.sql_id = s.sql_id or q.sql_id = s.prev_sql_id));

       SID SQL_TEXT                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
---------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
      2079 SELECT CL2M1,CL2M2,CL2M3,CL2M4,CL2M5,CL2M6,CL2M7,CL2M8,CL2M9,CL2M111,CL2M11,CL2M12,CL2M13,CL2M14,CL2M15,CL2M16,CL2M17,CL2M171,CL2M18,CL2M181,CL2M19,CL2M191,CL2M20,CL2M201,CL2M21,CL2M22,CL2M23,CL2M24,CL2M25,CL2M26,CL2M27,CL2M28,CL2M29,CL2M30,CL2M31,CL2M32,CL2M33,CL2M34,CL2M35,CL2M36,CL2M37,CL2M38,CL2M39,CL2M40,CL2M410,CL2M41,CL2M42,CL2M46,CL2M47,CL2M48,CL2M49,CL2M50,CL2M52,CL2M53,CL2M54,CL2M55,CL2M56,CL2M57,CL2M58,CL2M59,CL2M60,CL2M61,CL2M62,CL2M63,CL2M64,CL2M65,CL2M66,CL2M67,CL2M68,CL2M69,CL2M70,CL2M71,CL2M72,CL2M73,CL2M74,CL2M75,CL2M76,CL2M77,CL2M78,CL2M79,CL2M80,CL2M81,CL2M94,CL2M100,CL2M234   FROM CL2M  WHERE CL2M.CL2MCP = :b1  AND CL2M.CL2MYR = :b2  AND CL2M.CL2M1 = :b3  AND CL2M.CL2M2 = :b4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
      2140 SELECT NVL(MAX(CL2T5),0)   FROM CL2T  WHERE CL2TCP = :b1  AND CL2TYR = :b2  AND CL2T1 = :b3  AND CL2T2 = :b4  AND CL2T3 = :b5  AND CL2T4 = :b6                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
      2044 SELECT GRSCTP3,GRSCTP4,GRSCTP5,GRSCTP6,GRSCTP7,GRSCTP8,GRSCTP9,GRSCTP10,GRSCTP11,GRSCTP12,GRSCTP13,GRSCTP14,GRSCTP15,GRSCTP16,GRSCTP17,GRSCTP18,GRSCTP19   FROM GRSCTP  WHERE GRSCTP1 = :b1 ORDER BY GRSCTP3                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
      2101 SELECT GRSCTP3,GRSCTP4,GRSCTP5,GRSCTP6,GRSCTP7,GRSCTP8,GRSCTP9,GRSCTP10,GRSCTP11,GRSCTP12,GRSCTP13,GRSCTP14,GRSCTP15,GRSCTP16,GRSCTP17,GRSCTP18,GRSCTP19   FROM GRSCTP  WHERE GRSCTP1 = :b1 ORDER BY GRSCTP3                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
      2149 SELECT GRSCTP3,GRSCTP4,GRSCTP5,GRSCTP6,GRSCTP7,GRSCTP8,GRSCTP9,GRSCTP10,GRSCTP11,GRSCTP12,GRSCTP13,GRSCTP14,GRSCTP15,GRSCTP16,GRSCTP17,GRSCTP18,GRSCTP19   FROM GRSCTP  WHERE GRSCTP1 = :b1 ORDER BY GRSCTP3                                                                                                                                                                                                                                                                                                                                             

allocate_unique

Ved, December 04, 2012 - 5:33 am UTC

Hi Tom,
for a heavily used concurrent program, we have a code in our application as below

-- CODE STARTS------------

FUNCTION lock_statement(lockhandle IN OUT NOCOPY VARCHAR2) RETURN BOOLEAN IS
x_material_header_id ece_material_headers.material_header_id%TYPE;
lock_status NUMBER;
expiration_secs NUMBER;
lockname VARCHAR2(128);
lockmode NUMBER;
timeout NUMBER;
release_on_commit BOOLEAN;
BEGIN

SELECT material_header_id
INTO x_material_header_id
FROM ece_material_headers
WHERE rowid = ECE_MATCH.csh_rowid
FOR UPDATE OF material_header_id NOWAIT;


lockname := ECE_MATCH.csh_rowid;
timeout := 1;
lockmode := 6;
expiration_secs := 10;
release_on_commit := TRUE;

dbms_lock.allocate_unique (lockname, lockhandle, expiration_secs);

lock_status := dbms_lock.request( lockhandle, lockmode, timeout,
release_on_commit );
IF (lock_status <> 0) THEN

RAISE APP_EXCEPTIONS.record_lock_exception;
END IF;

RETURN(TRUE);
EXCEPTION
WHEN APP_EXCEPTIONS.record_lock_exception THEN
return(FALSE);
WHEN OTHERS THEN

RAISE;
return(FALSE);
END lock_statement;


---- CODE ENDS ----


Customer hit an error ORA-08004: sequence DBMS_LOCK_ID.NEXTVAL exceeds MAXVALUE and cannot be instantiated

Basically the customer suspects that since they use our concurrent program daily ( plus there are sevaral other programs as well which use allocate_unique API) they will reach max sequence in another three months and they don't want to keep on re-setting it every time.

My question
-----------------
As we are already using for update... nowait..
do you think dbms_lock implementation as seen in above function is redundant or not ?

This code's been like this for a decade or so.. so I was just wondering if I can get a second opinion.

schema/account lock

A reader, February 08, 2013 - 3:03 am UTC

Schema owning application objects are locked for security.Want to know if schema gets locked post application is able to connect or does oracle somehow recognize the valid attempt (application's) and prevent every other attempt erroring out saying account is locked.

Mr.

Manoj, March 24, 2013 - 11:03 pm UTC

Hi Tom,

I understood about the locks now. Can you explain it with UNDO segment as well.

I have 2 rows resides in the same block. When i update one row in session 1 and the second row in session 2 then how the lock and undo segment compined will work? how oracle releases the lock adn writing into the redo log and into datafile.

Thanks in advance.
Tom Kyte
March 25, 2013 - 7:39 pm UTC

the undo is totally separate, the two bits of undo have nothing to do with each other. They are managed as if there was only one transaction (or a thousand). Your undo is yours, my undo is mine.

and you already know about the locks - so....

If you want the blow by blow of a transaction - I suggest the Oracle concepts guide (on otn.oracle.com) or if you want more details - see Expert Oracle Database Architecture, which I wrote. I spend a few chapters on this stuff (it is too big to reproduce here)

the blocking session toggled in/out

Jrun, March 26, 2013 - 1:07 am UTC

11gR2, 3rd party web app
I had very a troublesome oracle session of the web app.
we did not know what caused the session to block a number of other oracle sessions in hours shown v$lock.ctime.
we understood that because of holding the resource causing the row level blocking.
that was not problem for the understanding.

The problem was that the session with the SID and its serial# was increasing in every 1 second or less.
Seemed that the session was toggling in/out of database.
we could not kill it from the database nor from the server because of the serial# rapidly increasing.
we could not use ALTER SESSION to kill it.
because of that the v$process.spid was also dynamically changing,
we could not identify spid on the server for the kill.
we ended up having the app restarted. we did notify the 3rd party for the issue.

Question, why the resource was not released as the session toggled to off?

Tom Kyte
March 27, 2013 - 3:02 pm UTC

sounds like it was killed, but it had done something *big* and was in the process of backing itself out.

as pmon is cleaning up that session, it will periodically bump up the serial# to represent its progression through the undo that needs to be applied for the transaction that was in progress.


basically that session did something big.
someone kill that session - maybe by killing it at the OS level even.
pmon became responsible for cleaning it up.
pmon will increase the serial# after each batch of undo it processes.

the resource is locked until the cleanup is done.


it takes much longer to rollback than it does to "roll forward" in general. The database is optimized to succeed, commits are instantaneous, rollbacks take a long time (usually longer than it too to get there in the first place)


by restarting the app, I assume you mean you restarted the database. At that point - the transaction recovery would be done a bit differently - with fast start recovery. The database would roll forward and then open the database and then start rolling back with "on demand" undo being applied. The access to the requested data would be slow, but it wouldn't block anymore.

the blocking session toggled in/out

JRun, March 27, 2013 - 3:17 pm UTC

Tom,
seemed that no option to get rid of the session since pmon was taking over, except have the db restarted?

Can this be simulated?
Tom Kyte
March 27, 2013 - 5:24 pm UTC

perhaps by doing a huge big transaction and killing the session in the same manner you killed it in the first place.

and if you would just have let it run its course, it would have fixed itself.

since this is a 3rd party application with a bug, I'm sure you'll reproduce it sometime soon - until they fix the bug.


If their application should not be processing HUGE modifications - you can consider using the resource manager to set up an undo pool limit - if this is a transactional application - they should be generating tiny bits of undo. This was caused by an application running from your middle tier that generated tons of undo and we were spending time rolling it back. Sort of like they missed a where clause on some delete or update statement.

it's possible to have a deadlock in only one session?

Daniel, August 12, 2013 - 12:27 pm UTC

Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-0008000a-00045e9c 26 465 X 26 465 X
session 465: DID 0001-001A-0001985D session 465: DID 0001-001A-0001985D
Rows waited on:
Session 465: obj - rowid = 00096E0C - AACisQABZAAAGtiAAK
(dictionary objn - 617996, file - 89, block - 27490, slot - 10)
Information on the OTHER waiting sessions:
End of information on OTHER waiting sessions.
Current SQL statement for this session:
UPDATE sp13_observa_expe
SET b_dato = 0, C_ALCANCE='A', C_GRAVEDAD='A',
C_PERSISTENCIA='A', C_LISTADO ='A91', f_actuacion = SYSDATE, c_usuario = 'CARTOSAT'
WHERE c_observa = (SELECT c_observa
FROM sp13_tipo_observa
WHERE c_listado = 'A91' AND NVL (b_ampliar, 0) = 0)
AND c_expe = '34400036'
----- PL/SQL Call Stack -----
object line object
handle number name
0x35b29114 65 function ITA_SATP13.SP13_CALCULA_A91
0x3e1b8420 3392 package body ITA_SATP13.SP13_CALCULO_INCUMPLIMIENTOS
0x3e1b8420 48 package body ITA_SATP13.SP13_CALCULO_INCUMPLIMIENTOS
0x43ff2a98 990 function ITA_SATP13.SP13_CHECKIN
0x3e70d844 1 anonymous block


How can happen this?
It's a procedure that make calls to several functions. There aren't FK's nor map of bits indexes.
It do execute inmediate several times because the name of the tables is variable.

Thanks for your time.



Tom Kyte
August 12, 2013 - 4:07 pm UTC

autonomous transactions make this trivial:

ops$tkyte%ORA11GR2> create table t ( x int primary key );

Table created.

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

1 row created.

ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> declare
  2          pragma autonomous_transaction;
  3  begin
  4          insert into t values ( 1 );
  5          commit;
  6  end;
  7  /
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 4






if your developers are using autonmous transactions, I can almost 100% guarantee you they've done something seriously and horrendously wrong - you will have many transactional inconsistencies in your data if you look at it.


so, look for the autonomous transaction..... and fear it.



Thank you!

Daniel, August 14, 2013 - 3:34 pm UTC

Correct!
Thank you very much for your help. I was completely lost.
Tom Kyte
August 14, 2013 - 3:53 pm UTC

if they are using autonomous transactions - your troubles are only just starting now. they definitely have data inconsistencies due to their botched logic. This is not a guess, based on empirical observation of 15 years of autonomous transactions - every time they are used for anything other than error logging - they are used incorrectly and kill data consistency!

blocked resource

abhishek, September 20, 2013 - 2:03 pm UTC

hi tom,

i have seen the below query many time in my databases. whenever it appears, it is always consuming the maximum execution time alongwith maximum cpu and I/O usage.

/* OracleOEM */ WITH blocked_resources AS (select id1 , id2 , SUM(ctime) as blocked_secs , MAX(request) as max_request , COUNT(1) as blocked_count from v$lock where request > 0 group by id1, id2 ) , blockers AS (select L.* , BR.blocked_secs , BR.blocked_count from v$lock L , blocked_resources BR where BR.id1 = L.id1 and BR.id2 = L.id2 and L.lmode > 0 and L.block <> 0 ) select B.id1||'_'||B.id2||'_'||S.sid||'_'||S.serial# as id , 'SID, SERIAL:'||S.sid||', '||S.serial#||', LOCK_TYPE:'||B.type||', PROGRAM:'||S.program||', MODULE:'||S.module||', ACTION:'||S.action||', MACHINE:'||S.machine||', OSUSER:'||S.osuser||', USERNAME:'||S.username as info , B.blocked_secs , B.blocked_count from v$session S , blockers B where B.sid = S.sid


what does this mean?
the below link says that there is some problem with the fixed object stats.

http://www.bestremotedba.com/2012/04/

but it would be great if you throw some light on it :)

dba_waiters

Rajeshwaran Jeyabal, October 23, 2017 - 2:37 pm UTC

Team,

What does LOCK_ID1 and LOCK_ID2 refers in dba_waiters ?
looked into the docs, but it is not clear.

https://docs.oracle.com/database/122/REFRN/DBA_WAITERS.htm#REFRN23306

Session#1 - did this, but not yet committed.

demo@ORA12C> create table t(x int,y int);

Table created.

demo@ORA12C> insert into t(x,y) values(1,1);

1 row created.

demo@ORA12C> commit;

Commit complete.

demo@ORA12C> select userenv('sid') from dual;

USERENV('SID')
--------------
            15

demo@ORA12C> update t set y = y+1 where x = 1;

1 row updated.


From Session#2 - did this again, blocked due to Session#1 uncommitted changes.

demo@ORA12C> select userenv('sid') from dual;

USERENV('SID')
--------------
           144

demo@ORA12C> update t set y = y+1 where x = 1;



From the another connection ran this query.

demo@ORA12C> column lock_type format a15
demo@ORA12C> column mode_held format a15
demo@ORA12C> column mode_requested format a15
demo@ORA12C> select * from dba_waiters;

WAITING_SESSION WAITING_CON_ID HOLDING_SESSION HOLDING_CON_ID LOCK_TYPE       MODE_HELD       MODE_REQUESTED    LOCK_ID1   LOCK_ID2
--------------- -------------- --------------- -------------- --------------- --------------- --------------- ---------- ----------
            144              0              15              0 Transaction     Exclusive       Exclusive       327698       7900

demo@ORA12C>


Could you help us to understand what does LOCK_ID1 and LOCK_ID2 refers to?
Connor McDonald
October 24, 2017 - 2:13 am UTC

They are the same as columns from v$lock, so for a TX, it will be the transaction, eg

SQL> create table t ( x int );

Table created.

SQL> insert into t values (1);

1 row created.

SQL> commit;

Commit complete.

SQL> delete from t;

1 row deleted.

-- another session runs the same delete to get a block

SQL> select * from v$lock where type in ('TM','TX');

ADDR             KADDR                   SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK     CON_ID
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
00007FFA6CA4D910 00007FFA6CA4D990        397 TX     524309      27772          0          6         59          0          0
000001A96A45E698 000001A96A45E708        271 TM     158792          0          3          0         62          0          0
000001A96A45E698 000001A96A45E708        397 TM     158792          0          3          0         59          0          0
00007FFA656543A8 00007FFA65654430        271 TX     524309      27772          6          0         62          1          0

SQL> select * from dba_waiters;

WAITING_SESSION WAITING_CON_ID HOLDING_SESSION HOLDING_CON_ID LOCK_TYPE                  MODE_HELD                                MODE_REQUESTED                             LOCK_ID1   LOCK_ID2
--------------- -------------- --------------- -------------- -------------------------- ---------------------------------------- ---------------------------------------- ---------- ----------
            397              0             271              0 Transaction                Exclusive                                Exclusive                                    524309      27772

SQL> select
  2    trunc(524309/power(2,16)) x1,
  3    bitand(524309,to_number('ffff','xxxx'))+0 x2
  4  from dual;

        X1         X2
---------- ----------
         8         21

SQL> select xidusn, xidslot, xidsqn from v$transaction;

    XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ----------
         8         21      27772





A reader, September 29, 2020 - 7:40 am UTC


A reader, September 29, 2020 - 8:37 am UTC


gc transaction table

Rajeshwaran Jeyabal, September 09, 2021 - 7:20 am UTC

Team,

here is a section from sql-monitor report from an application workload.
|        |                                |                    |         |       |           |        |       |          |       |       |       |       |       |       |          | direct path write temp (4)  |          |
| -> 495 |   JOIN FILTER USE              | :BF0002            |     71M |    1M |       386 |  +1257 |     1 |       9M |       |       |       |       |     . |     . |          |                             |          |
| -> 496 |    PARTITION LIST SINGLE       |                    |     71M |    1M |       386 |  +1257 |     1 |       9M |       |       |       |       |     . |     . |          |                             |          |
| -> 497 |     TABLE ACCESS STORAGE FULL  | XXXXXXXXXXXXXXXXXX |     71M |    1M |       386 |  +1257 |     1 |       9M |  6509 |   6GB |       |       |   3MB |     . |    19.02 | gc transaction table (254)  |          |
|        |                                |                    |         |       |           |        |       |          |       |       |       |       |       |       |          | Cpu (43)                    |          |
|        |                                |                    |         |       |           |        |       |          |       |       |       |       |       |       |          | cell smart table scan (15)  |          |

could you help us to understand what is "gc transaction table" wait event is? and why it is impacting the full scan?

Tried looking at the docs @ https://docs.oracle.com/en/database/oracle/oracle-database/18/refrn/descriptions-of-wait-events.html#GUID-2FDDFAA4-24D0-4B80-A157-A907AF5C68E2 , but dont find any, please help to understand it better.
Chris Saxon
September 10, 2021 - 12:56 pm UTC

This paper on RAC performance optimizations on Exadata discusses this event:

https://www.oracle.com/a/otn/docs/oracle-rac-cache-fusion-performance-optimization-on-exadata-wp.pdf

It relates to batching transaction lookups for In-Memory.

Also note this wait has been renamed "gc transaction table 2-way" in 21c.

Auto stats

Apr, May 15, 2022 - 4:12 pm UTC

Lots of lock waits on SELECTs (without FOR UPDATE clause) after implementing auto stats in 19c - even though they are of the order of less than a few msecs

Also Quite a few waits on seq.nextval which I guess can be reduced by increasing the cache value of the sequences from default 20.

What could be the reason for TOAD showing mutliple lockwaits on SELECTs ? Maybe the SQLs are running faster after implementing auto stats ? : ) Seriously
Connor McDonald
May 16, 2022 - 2:32 am UTC

We'd need to see some evidence, eg an AWR report for a short period of time around the locking issues.

If you have one, email it to asktom_us at oracle dot com with subject: Question 839412906735

athanasios, February 07, 2024 - 9:32 pm UTC

HI Tom,
Is it normal to have TM enqueue in ASH very regularly often short or few seconds sometimes even minutes on a SELECT without 'for update' and on mode 6 requested ?

Thanks in advance.

Atta



Chris Saxon
February 08, 2024 - 2:28 pm UTC

Standard selects (without for update) should not be blocked by anything. What evidence do you have that they are?

atta, March 04, 2024 - 2:21 pm UTC

Hi Tom and thanks for the prompt answer. Sorry I missed it.
All tables I use bring me to the same conclusion and data.
Here below a query that I capture some data on blockers and lockers of TM.
select
(select username|| ' ' ||event || 'logon'||logon_time  from gv$session where sid=a.sid and inst_id=a.inst_id) blocker,
a.sid sid_blocker,
(select username || ' ' || sql_id from gv$session where sid=b.sid and inst_id=b.inst_id) blockee,
b.sid sid_blockee,
CASE WHEN a.type = 'TM' THEN (SELECT  o.object_name|| o.object_type 
FROM dba_objects o
WHERE a.id1 = o.object_id  ) 
             END object_name
--a.*,b.*
,a.INST_ID
,a.ADDR
,a.KADDR
,a.SID
,a.TYPE
,a.ID1
,a.ID2
,a.LMODE
,a.REQUEST
,a.CTIME
,a.BLOCK
,b.INST_ID INST_ID1
,b.ADDR addr1
,b.KADDR kaddr1
,b.SID sid1
,b.TYPE type1
,b.LMODE lmode1
,b.REQUEST request1
,b.CTIME ctime1
,b.BLOCK block1
,sysdate
from
gv$lock a,
gv$lock b,
gv$session s1, 
gv$session s2
WHERE s1.sid=a.sid and s1.inst_id=a.inst_id 
AND s2.sid=b.sid  and s2.inst_id=b.inst_id
and a.sid=s2.blocking_session
and a.block = 1
and b.request > 0
AND a.sid > b.sid
and a.id1 = b.id1
and a.id2 = b.id2;


ASH data confirm the same. The sql_id on session/ash views is a simply this :

select id from table
that comes from a small function with OUT SYS_REFCURSOR parameter to a web app I guess :
  OPEN c FOR
        SELECT EVENT_TRACKING_ID
          FROM EVENT_TRACKING_TASK

atta, March 04, 2024 - 2:33 pm UTC

Just to add the holder is in 3 mode (maybe from an uncommitted insert or select for update, an idle session. That's probably a bug but I don't know the application. It's another story. )
The blocker is asking TM lock in 6 mode.

Atta, March 04, 2024 - 11:12 pm UTC

Some extract from AWR data :

SELECT sample_time,event,p1,p2,p3,sql_opname
FROM dba_hist_active_sess_history
where snap_id =94348
and instance_number=1
and session_id=334
and sql_id='0ywyg4n76dzkh'
order by 1


SAMPLE_TIME                       EVENT                                                                    P1         P2         P3 SQL_OPNAME                                                      
--------------------------------- ---------------------------------------------------------------- ---------- ---------- ---------- ----------------------------------------------------------------
01-MAR-2024 12.52.31.770000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.52.42.011000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.52.52.250000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.53.02.618000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.53.12.858000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.53.23.099000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.53.33.338000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.53.43.579000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.53.53.818000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.54.04.058000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.54.14.298000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT                                                          
01-MAR-2024 12.54.24.538000000 PM enq: TM - contention                                             1414332422    3156968          0 SELECT              

SELECT * FROM dba_hist_sqltext where sql_id='<b>0ywyg4n76dzkh</b>'

      DBID SQL_ID        SQL_TEXT                                                                         COMMAND_TYPE   CON_DBID     CON_ID
---------- ------------- -------------------------------------------------------------------------------- ------------ ---------- ----------
3473786237 0ywyg4n76dzkh <b>SELECT EVENT_TRACKING_ID FROM R_EVENT_TRACKING_TASK    </b>                                     3 3473786237          0
                                            

A reader, March 06, 2024 - 9:31 am UTC

I add some minor info.

Confirmation from dba_waiters.

Holder with TM in mode 3 and simple select asking for TM in mode 6,

WAITING_SESSION WAITING_CON_ID HOLDING_SESSION HOLDING_CON_ID LOCK_TYPE                  MODE_HELD                                MODE_REQUESTED                             LOCK_ID1   LOCK_ID2
--------------- -------------- --------------- -------------- -------------------------- ---------------------------------------- ---------------------------------------- ---------- ----------
           2026              0            1687              0 DML                        Row-X (SX)                               Exclusive                                   3156968          0 
           2356              0            1687              0 DML                        Row-X (SX)                               Exclusive                                   3156968          0 
           4367              0            1554              0 DML                        Row-X (SX)                               Exclusive                                   3156968          0 


I think there is something strange just don't know how to go deeper in diagnosis.
It's hard to accuse an Oracle bug in lock functioning or in the diagnostic data, but that's what is looks like.
Chris Saxon
March 06, 2024 - 2:43 pm UTC

Hmmm, I'm not sure what's going on here. I find it very surprising that simple selects are requesting exclusive locks.

MOS note 1905174.1 has details on investigating enq: TM - contention waits. Check that to see if anything applies to your case.

Finding out what exactly is holding the lock would also help.

Finally - while the select looks basic, is it a complex statement hidden behind a view?

Atta, March 06, 2024 - 4:02 pm UTC

Yes that's very surprising, my queries seem correct and show this that
it happens continuously and regularly.

I have well present MOS note 1905174.1 .
I've checked presence of PDML, MV logs, FK, stats calculation etc cases and they don't apply.

But sill the select shouldn't require exclusive TM. This remains unexplained.

From what I see who holding the lock seems a session that corresponds to web app ( or a pool of sessions related to one oracle session) that is always idle holding the lock in 3 mode.

Once the holder commits the blockee continues, sometimes quickly and others not. How can I use that information ? what kind of info do I need on that ? But still is not normal as you said that the select shows EXCLUSIVE TM request. holder and blockee are the same application with different sessions.

There is no complex view, actually. It's a simple heap table with a unique index, CBO makes a Index full scan to read it.

Can it be a discrepancy on those gv$ views ? ))

Last thing, even more confusing. The current_obj# in ASH table corresponds to a totally different table or index that is not in the sql of the ash row.


select        count(*) cnt, 
              session_id sid,
              substr(ash.event,1,30) event, 
              mod(ash.p1,16)  as lm,
              ash.sql_id,
--              s.sql_id,
              ash.CURRENT_OBJ# || ' ' || object_name obj
            , o.object_type type
            , ash.CURRENT_FILE# file#
            , ash.CURRENT_BLOCK#  block#
            , ash.blocking_session bsid
             ,ash.CON_ID "CON_ID**"
 from gv$active_session_history ash,
      all_objects o
 where 1=1
     and    ash.event  like 'enq: T%'
     and ash.sql_id='0ywyg4n76dzkh'
   and o.object_id (+)= ash.current_obj#
and sample_time > sysdate - interval '15' minute
group by ash.event,ash.session_id,ash.p1,ash.sql_ID,ash.CURRENT_OBJ#,OBJECT_NAME,OBJECT_TYPE,ash.CURRENT_FILE#, ash.CURRENT_BLOCK#,ash. BLOCKING_SESSION,ash.CON_ID
order by  object_name



       CNT        SID EVENT                                  LM SQL_ID        OBJ                                                                                                                                                                       TYPE                         FILE#     BLOCK#       BSID   CON_ID**
---------- ---------- ------------------------------ ---------- ------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------- ---------- ---------- ---------- ----------
         1       4285 enq: TM - contention                    6 0ywyg4n76dzkh 175869 M_NOTIFICATION_QUEUE                                                                                                                                               TABLE                          735     843723       4709          0
         1       1527 enq: TM - contention                    6 0ywyg4n76dzkh 3156968 R_EVENT_TRACKING_TASK                                                                                                                                             TABLE                          733     125388       2792          0
         1       1527 enq: TM - contention                    6 0ywyg4n76dzkh 3156968 R_EVENT_TRACKING_TASK                                                                                                                                             TABLE                          733     125388                     0
         1       2227 enq: TM - contention                    6 0ywyg4n76dzkh 2712668 XFK1_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          255     485475       1464          0
         1       2227 enq: TM - contention                    6 0ywyg4n76dzkh 2712668 XFK1_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          255     485475                     0
         1       3724 enq: TM - contention                    6 0ywyg4n76dzkh 2712668 XFK1_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          255     483869       4709          0
         1       4821 enq: TM - contention                    6 0ywyg4n76dzkh 2712668 XFK1_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          255     483478       5160          0
         1         28 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                           12      19711        476          0
         6       2270 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          758    2023284       2936          0
         2       2270 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          758    2023284                     0
         1       3606 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          759    2187156       3724          0
         1       3924 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                          749    2215983       4881          0
         1       4708 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                           13      41193       3724          0
         9       5052 enq: TM - contention                    6 0ywyg4n76dzkh 2712669 XFK2_R_EVENT_TRACKING_ACT                                                                                                                                         INDEX                           13      41426       2936          0
         1       2270 enq: TM - contention                    6 0ywyg4n76dzkh 3023796 XFK4_REFERRAL_SMS_ACTIVITY                                                                                                                                        INDEX                          757    2417007         37          0
         1       1129 enq: TM - contention                    6 0ywyg4n76dzkh 2712685 XIE1_A_EVENT_TRACKING_R                                                                                                                                           INDEX                          747    2217833        711          0
         3       4709 enq: TM - contention                    6 0ywyg4n76dzkh 2712685 XIE1_A_EVENT_TRACKING_R                                                                                                                                           INDEX                          746    2270076       2792          0
         1        161 enq: TM - contention                    6 0ywyg4n76dzkh 3731567 XIE1_R_EVENT_TRACKING_TASK                                                                                                                                        INDEX                          749    1374800                     0
         2       4708 enq: TM - contention                    6 0ywyg4n76dzkh 3731567 XIE1_R_EVENT_TRACKING_TASK                                                                                                                                        INDEX                          749    1374800                     0
         1        161 enq: TM - contention                    6 0ywyg4n76dzkh 2712679 XPK_R_EVENT_TRACK_RESP                                                                                                                                            INDEX                          752    2440245        711          0
         1       1784 enq: TM - contention                    6 0ywyg4n76dzkh 0                                                                                                                                                                                                          8        340         37          0
         2       2437 enq: TM - contention                    6 0ywyg4n76dzkh 0                                                                                                                                                                                                          8     516232       1829          0
         1       4065 enq: TM - contention                    6 0ywyg4n76dzkh 0                                                                                                                                                                                                          3    1601656       4400          0
         1       5052 enq: TM - contention                    6 0ywyg4n76dzkh 0                                                                                                                                                                                                          3     516168       3597          0
         1       5138 enq: TM - contention                    6 0ywyg4n76dzkh 2712665                                                                                                                                                                                                    0          0       3591          0


Lastly, just now found this page maybe I get a chance to find out more.
https://www.dbi-services.com/blog/investigating-oracle-lock-issues-with-event-10704/


Chris Saxon
March 07, 2024 - 4:14 pm UTC

But sill the select shouldn't require exclusive TM. This remains unexplained.

My thoughts too. I recommend raising this with support to figure out what's going on.