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: September 10, 2021 - 12:56 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 we 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

  (443 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