• Aucun résultat trouvé

5-19. Identifying Time Spent Waiting Due to Locking

Dans le document Oracle Database 11g (Page 175-178)

Problem

You want to identify the total time spent waiting by sessions due to locking issues.

Solution

You can use the following query to identify (and quantify) waits caused by locking of a table’s rows. Since the query orders the wait events by time waited, you can quickly see which type of wait events accounts for most of the waits in your instance.

SQL> select wait_class, event, time_waited / 100 time_secs 2 from v$system_event e

3 where e.wait_class <> 'Idle' AND time_waited > 0 4 union

5 select 'Time Model', stat_name NAME, 6 round ((value / 1000000), 2) time_secs 7 from v$sys_time_model

8 where stat_name NOT IN ('background elapsed time', 'background cpu time') 9* order by 3 desc;

CHAPTER 5 ■ MINIMIZING SYSTEM CONTENTION

In this example, the wait event enq: TX - row lock contention reveals the total time due to row lock enqueue wait events. Note that the shared pool latch events are classified under the Concurrency wait class, while the enqueue TX - row lock contention event is classified as an Application class wait event.

How It Works

The query in the “Solution” section joins the V$SYSTEM_EVENT and the V$SYS_TIME_MODEL views to show you the total time waited due to various wait events. In our case, we’re interested in the total time waited due to enqueue locking. If you’re interested in the total time waited by a specific session, you can use a couple of different V$ views to find out how long sessions have been in a wait state, but we recommend using the V$SESSION view, because it shows you various useful attributes of the blocking and blocked sessions. Here’s an example showing how to find out how long a session has been blocked by another session.

SQL>select sid, username, event, blocking_session, seconds_in_wait, wait_time

from v$session where state in ('WAITING');

The query reveals the following about the session with SID 81, which is in a WAITING state:

SID : 81 (this is the blocked session)

username: SH (user who's being blocked right now)

event: TX - row lock contention (shows the exact type of lock contention) blocking session: 68 (this is the "blocker")

seconds_in_wait: 3692 (how long the blocked session is in this state)

The query reveals that the user SH, with a SID of 81, has been blocked for almost an hour (3,692 seconds). User SH is shown as waiting for a lock on a table that is currently locked by session 68. While the V$SESSION view is highly useful for identifying the blocking and blocked sessions, it can’t tell you the SQL statement that’s involved in the blocking of the table. Often, identifying the SQL statement that’s involved in a blocking situation helps in finding out exactly why the statement is leading to the locking behavior. To find out the actual SQL statement that’s involved, you must join the V$SESSION and the V$SQL views, as shown here.

SID SQL_TEXT

--- --- 68 select * from test for update

81 update hr.test set name='nalapati' where user_id=1111 SQL>

The output of the query shows that session 81 is being blocked because it’s trying to update a row in a table that has been locked by session 68, using the SELECT … FOR UPDATE statement. In cases such as this, if you find a long queue of user sessions being blocked by another session, you must kill the blocking session so the other sessions can process their work. You’ll also see a high active user count in the database during these situations—killing the blocking session offers you an immediate solution to resolving contention caused by enqueue locks. Later on, you can investigate why the blocks are occurring, so as to prevent these situations.

For any session, you can identify the total time waited by a session for each wait class, by issuing the following query:

SQL> select wait_class_id, wait_class, total_waits, time_waited

from v$session_wait_class where sid = <SID>;

If you find, for example, that this session endured a very high number of waits in the application wait class (wait class ID for this class is 4217450380), you can issue the following query using the V$SYSTEM_EVENT view, to find out exactly which waits are responsible:

SQL> select event, total_waits, time_waited

In our example, the waits in the application class (ID 4217450380) are due to locking contention as revealed by the wait event enq:TM - contention. You can further use the V$EVENT_HISTOGRAM view, to find out how many times and for how long sessions have waited for a specific wait event since you started the instance. Here’s the query you need to execute to find out the wait time pattern for enqueue lock waits:

SQL> select wait_time_milli bucket, wait_count from v$event_histogram

where event = 'enq: TX - row lock contention';

A high amount of enqueue waits due to locking behavior is usually due to faulty application design.

You’ll sometimes encounter this when an application executes many updates against the same row or a set of rows. Since this type of high waits due to locking is due to inappropriately designed applications, there’s not much you can do by yourself to reduce these waits. Let your application team know why these waits are occurring, and ask them to consider modifying the application logic to avoid the waits.

CHAPTER 5 ■ MINIMIZING SYSTEM CONTENTION

Any of the following four DML statements can cause locking contention: INSERT, UPDATE, DELETE, and SELECT FOR UPDATE. INSERT statements wait for a lock because another session is attempting to insert a row with an identical value. This usually happens when you have a table that has a primary key or unique constraint, with the application generating the keys. Use an Oracle sequence instead to generate the key values, to avoid these types of locking situations. You can specify the NOWAIT option with a SELECT FOR UPDATE statement to eliminate session blocking due to locks. You can also use the SELECT FOR UPDATE NOWAIT statement to avoid waiting by sessions for locks when they issue an UPDATE or DELETE statement.

The SELECT FOR UPDATE NOWAIT statement locks the row without waiting.

Dans le document Oracle Database 11g (Page 175-178)