Блокировки

Данные о блокировках можно увидеть в следующих системных таблицах:

v$transaction, v$lock, v$session.

Воспользуемся таким запросом

SELECT /*+ rule */ l.SID, s.username,s.machine,s.MODULE,s.action, 
l.TYPE, id1, o.OBJECT_NAME, id2 seq, lmode, request
FROM v$lock l, v$session s, DBA_OBJECTS o
WHERE l.SID = s.SID AND username IS NOT NULL AND l.id1=o.OBJECT_ID(+)
ORDER BY sid
получаем (основные поля запроса) 
	
username sid type lmode request
А 	    10	TM		3	  0
B 	    19	TM		3	  0
А 	    10	TX		6	  0
B 	    19	TX		0	  6

Тут мы видим ситуацию, когда пользователь А (sid=10) начал транзакцию (type=TX) , сделав update одной строки, тем самым ввёл исключительную блокировку (lmode=6) на эту строку. Поле request=0 - значает, что пользователь А удерживает блокировку.

Пользователь В также попытался сделать update той же строки, но, нарвался на блокировку и теперь ожидает освобождения этого ресурса для того, что бы самому выставить исключительную блокировку request=6.

Когда пользователь А сделал commit, получаем такую картинку:

B		19	TM		3	0
B		19	TX		6	0

Теперь пользователь В полностью владеет этой строкой.


Рассмотрим поле TYPE.

TX - блокировка транзакций.
Устанавливается (одна на транзакцию), если пользователь изменил что-то в базе - данные, структуру таблиц и т.д.
Снимается, как только пройдёт COMMIT или rollback.

TM - блокировка изменений от операторов drop и alter.
То есть, если пользователь начал изменять данные в таблице, то он блокирует изменения структуры таблицы или её удаление. Блокировка устанавливается для каждого изменяемого объекта. Поле ID1в этом случае содержит идентификатор объекта.

ST - Space Transaction Lock - блокировка устанавливается при любых действиях связанных с изменениями размеров объектов - это CREATE, drop, ALTER tablespace ...

UL - User Defined Locks


Значения полей Request/Lmode
0: нет блокировки
2: Row Share: used for shared DML locks
4: Share: used for shared TX when waiting for ITL entry
6: Exclusive used for row level, DML locks

 


Что делать если произошла блокировка ?

Вначале нужно определить кто и кого заблокировал.

-- запрос выдаёт блокирующего и заблокированного пользователей 
SELECT /*+ rule */ 
       s1.username blocker,    s1.sid sid_blocker, s1.serial#, s1.MACHINE, s1.MODULE, s1.ACTION, 
       s2.username is_blocked, s2.sid sid_blocked, s2.serial#, s2.MACHINE, s2.MODULE, s2.ACTION,
       s1.SQL_HASH_VALUE sql_blocker,
       s2.SQL_HASH_VALUE sql_blocked 
  FROM v$lock a, v$lock b, v$session s1, v$session s2 
 WHERE a.id1 = b.id1 AND a.id2 = b.id2 AND b.request > 0 
   AND a.sid=s1.sid AND b.sid=s2.sid AND a.sid<>b.sid
  

поля module и action во многих случаях могут быть не заполнены, но следует заставлять разработчиков приложений заполнять эти поля названием программы (module) и совершаемым в данный момент ею действием (action). Это очень сильно помогает при подобных разборках.

Можно посмотреть и тексты SQL у этих пользователей. Следует иметь в виду, что у блокирующего пользователя в момент этого запроса может выполняться уже другой, например следующий запрос из транзакции.

-- запрос выдаёт запросы блокирующего и заблокированного пользователей 
SELECT 'blocker', s1.username, s1.sid sid, 
       q1.SQL_text, q1.PIECE string
  FROM v$lock a, v$lock b, v$session s1, V$SQLtext q1 
 WHERE a.id1 = b.id1 AND a.id2 = b.id2 AND b.request > 0 
   AND a.sid=s1.sid  AND a.sid<>b.sid
   AND q1.HASH_VALUE=s1.SQL_HASH_VALUE
UNION ALL
SELECT 'blocked', s2.username, s2.sid sid, 
       q2.SQL_text, q2.PIECE string
  FROM v$lock a, v$lock b, v$session s2, V$SQLtext q2 
 WHERE a.id1 = b.id1 AND a.id2 = b.id2 AND b.request > 0 
   AND b.sid=s2.sid  AND a.sid<>b.sid
   AND q2.HASH_VALUE=s2.SQL_HASH_VALUE
 ORDER BY sid, string

Запрос может выполняться относительно долго (10-15 сек).

Ну а дальше нужно искать виновника блокировки по данным первого запроса, и заставить его завершить транзакцию. Если это невозможно - пользователь ушел на обед и бросил форму приложения в режиме редактирования, то его можно прибить... В смысле

ALTER system kill session '9,81'

где '9,81' это 'sid,serial#' виновника.

Хостинг от uCoz