Блокировки
Данные о блокировках можно увидеть в следующих системных таблицах:
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#' виновника.