• Aucun résultat trouvé

5-15. Identifying a Locked Object

Dans le document Oracle Database 11g (Page 168-171)

Problem

You are aware of a locking situation, and you’d like to find out the object that’s being locked.

Solution

You can find the locked object’s identity by looking at the value of the ID1 (LockIdentifier) column in the V$LOCK view (see Recipe 5-13). The value of the ID1 column where the TYPE column is TM (DML enqueue) identifies the locked object. Let's say you've ascertained that the value of the ID1 column is 99999. You can then issue the following query to identify the locked table:

SQL> select object_name from dba_objects where object_id=99999;

OBJECT_NAME --- TEST

SQL>

An even easier way is to use the V$LOCKED_OBJECT view to find out the locked object, the object type, and the owner of the object.

SQL> select lpad(' ',decode(l.xidusn,0,3,0)) || l.oracle_username "User", o.owner, o.object_name, o.object_type

from v$locked_object l, dba_objects o where l.object_id = o.object_id order by o.object_id, 1 desc;

User OWNER OBJECT_NAME OBJECT_TYPE --- --- --- --- HR HR TEST TABLE SH HR TEST TABLE SQL>

Note that the query shows both the blocking and the blocked users.

How It Works

As the “Solution” section shows, it’s rather easy to identify a locked object. You can certainly use Oracle Enterprise Manager to quickly identify a locked object, the ROWID of the object involved in the lock, and the SQL statement that’s responsible for the locks. However, it’s always important to understand the underlying Oracle views that contain the locking information, and that’s what this recipe demonstrates.

Using the queries shown in this recipe, you can easily identify a locked object without recourse to a monitoring tool such as Oracle Enterprise Manager, for example.

In the example shown in the solution, the locked object was a table, but it could be any other type of object, including a PL/SQL package. Often, it turns out that the reason a query is just hanging is that one of the objects the query needs is locked. You may have to kill the session holding the lock on the object before other users can access the object.

5-16. Resolving enq: TM Lock Contention

Problem

Several sessions in your database are taking a very long time to process some insert statements. As a result, the “active” sessions count is very high and the database is unable to accept new session connections. Upon checking, you find that the database is experiencing a lot of enq: TM – contention wait events.

Solution

The enq: TM – contention event is usually due to missing foreign key constraints on a table that’s part of an Oracle DML operation. Once you fix the problem by adding the foreign key constraint to the relevant table, the enq: TM – contention event will go away.

The waits on the enq: TM – contention event for the sessions that are waiting to perform insert operations are almost always due to an unindexed foreign key constraint.. This happens when a dependent or child table’s foreign key constraint that references a parent table is missing an index on the associated key. Oracle acquires a table lock on a child table if it’s performing modifications on the primary key column in the parent table that’s referenced by the foreign key of the child table. Note that these are full table locks (TM), and not row-level locks (TX)—thus, these locks aren’t restricted to a row but to the entire table. Naturally, once this table lock is acquired, Oracle will block all other sessions that seek to modify the child table’s data. Once you create an index in the child table performing on the column that references the parent table, the waits due to the TM contention will go away.

CHAPTER 5 ■ MINIMIZING SYSTEM CONTENTION

How It Works

Oracle takes out an exclusive lock on a child table if you don’t index the foreign key constraints in that table. To illustrate how an unindexed foreign key will result in contention due to locking, we use the following example. Create two tables, STORES and PRODUCTS, as shown here:

SQL> create table stores

(store_id number(10) not null, supplier_name varchar2(40) not null, constraint stores_pk PRIMARY KEY (store_id));

SQL>create table products

(product_id number(10) not null, product_name varchar2(30) not null, supplier_id number(10) not null, store_id number(10) not null, constraint fk_stores

foreign key (store_id) references stores(store_id) on delete cascade);

If you now delete any rows in the STORES table, you’ll notice waits due to locking. You can get rid of these waits by simply creating an index on the column you’ve specified as the foreign key in the PRODUCTS table:

create index fk_stores on products(store_id);

You can find all unindexed foreign key constraints in your database by issuing the following query:

SQL> select * from (

select c.table_name, co.column_name, co.position column_position from user_constraints c, user_cons_columns co

where c.constraint_name = co.constraint_name and c.constraint_type = 'R'

minus

select ui.table_name, uic.column_name, uic.column_position from user_indexes ui, user_ind_columns uic

where ui.index_name = uic.index_name )

order by table_name, column_position;

If you don’t index a foreign key column, you’ll notice the child table is often locked, thus leading to contention-related waits. Oracle recommends that you always index your foreign keys.

■ Tip

If the matching unique or primary key for a child table’s foreign key never gets updated or deleted, you don’t have to index the foreign key column in the child table.

Oracle will tend to acquire a table lock on the child table if you don’t index the foreign key column.

If you insert a row into the parent table, the parent table doesn’t acquire a lock on the child table;

however, if you update or delete a row in the parent table, the database will acquire a full table lock on

the child table. That is, any modifications to the primary key in the parent table will result in a full table lock (TM) on the child table. In our example, the STORES table is a parent of the PRODUCTS table, which contains the foreign key STORE_ID. The table PRODUCTS being a dependent table, the values of the STORE_ID column in that table must match the values of the unique or primary key of the parent table, STORES. In this case, the STORE_ID column in the STORES table is the primary key of that table.

Whenever you modify the parent table's (STORES) primary key, the database acquires a full table lock on the PRODUCTS table. Other sessions can’t change any values in the PRODUCTS table, including the columns other than the foreign key column. The sessions can only query but not modify the PRODUCTS table. During this time, any sessions attempting to modify any column in the PRODUCTS table will have to wait (TM: enq contention wait). Oracle will release this lock on the child table PRODUCTS only after it finishes modifying the primary key in the parent table, STORES. If you have a bunch of sessions waiting to modify data in the PRODUCTS table, they’ll all have to wait, and the active session count naturally will go up very fast, if you’ve an online transaction processing–type database that has many users that perform short DML operations. Note that any DML operations you perform on the child table don’t require a table lock on the parent table.

Dans le document Oracle Database 11g (Page 168-171)