#sql #oracle
Вопрос:
У меня есть Oracle DB 19c, которая является основой для клиентского приложения.
Когда приложение обращается к строке таблицы, оно блокирует ее, а затем приложение, запущенное с другого компьютера, больше не может получить доступ к этой записи. Я хочу выяснить, кто и на каком компьютере блокирует какую запись.
В своем исследовании я нашел следующее руководство: http://www.orafaq.com/node/854 В нем довольно хорошо перечислены шаги, которые необходимо выполнить, и, наконец, я создал следующий запрос для своих целей:
select LCK.*,OBJ.*,SESS.*, (CASE WHEN SESS.ROW_WAIT_OBJ# > -1 THEN dbms_rowid.rowid_create( 1, obj.Object_ID, SESS.ROW_WAIT_FILE#, SESS.ROW_WAIT_BLOCK#, SESS.ROW_WAIT_ROW# ) ELSE 'NA' END) as ROWID111
from v$locked_object LCK
left join dba_objects OBJ
on LCK.OBJECT_ID = OBJ.OBJECT_ID
left join v$session SESS
on LCK.SESSION_ID = SESS.SID;
Моя цель-вернуть строку таблицы, которая заблокирована.
К сожалению, метод dbms_rowid.rowid_create() не генерирует правильный идентификатор строки. Я провел некоторую обратную разработку и выяснил, что…
- идентификатор объекта, предоставляемый rovid_create (), должен быть идентификатором объекта из dba_objects
- ФАЙЛ SESS.ROW_WAIT_FILE# указывает на правильный файл
- SESS.ROW_WAIT_BLOCK НЕ является идентификатором блока таблицы, содержащей заблокированную запись
- SESS.ROW_WAIT_ROW# НЕ является номером строки заблокированной записи
Похоже, что каким-то образом таблица сеансов v$не содержит информации, необходимой мне для получения правильных значений для генерации идентификатора строки….
Ответ №1:
Я всегда использую следующие инструкции в разных версиях Oracle, и у меня никогда не было никаких проблем
Получить блокирующие сеансы и связанные с ними процессы
set lines 300
COLUMN username FORMAT A30
COLUMN osuser FORMAT A10
COLUMN machine FORMAT A30
COLUMN logon_time FORMAT A20
COLUMN PROGRAM format a20
COLUMN MODULE format a20
COLUMN sid_serial_inst format a20
SELECT level,
LPAD(' ', (level-1)*2, ' ') || NVL(s.username, '(oracle)') AS username,
s.osuser,
s.sid || ',' || s.serial# || ',@'|| inst_id as sid_serial_inst,
s.blocking_session,
s.lockwait,
s.status,
s.module,
s.machine,
s.program,
TO_CHAR(s.logon_Time,'DD-MON-YYYY HH24:MI:SS') AS logon_time
FROM gv$session s
WHERE level > 1
OR EXISTS (SELECT 1
FROM gv$session
WHERE blocking_session = s.sid and inst_id=s.inst_id)
CONNECT BY PRIOR s.sid || '@inst'|| inst_id = s.blocking_session || '@inst'|| inst_id
START WITH s.blocking_session IS NULL;
Чтобы заблокировать строки
set lines 200
select s.sid,do.object_name,
row_wait_obj#, row_wait_file#, row_wait_block#, row_wait_row#,
dbms_rowid.rowid_create ( 1, ROW_WAIT_OBJ#, ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, ROW_WAIT_ROW# )
from v$session s, dba_objects do
where sid in (SELECT sid FROM GV$LOCK WHERE request>0)
and s.ROW_WAIT_OBJ# = do.OBJECT_ID ;
ДЕМОНСТРАЦИЯ
Сессия 1
SQL> create table test1 ( c1 number, c2 number );
Table created.
SQL> insert into test1 values ( 1, 1);
1 row created.
SQL> insert into test1 values ( 2,2) ;
1 row created.
SQL> commit ;
Commit complete.
Сессия 2
SQL> update test1 set c1=3 where c1=2 ;
1 row updated.
SQL>
Затем снова в сеансе 1
SQL> update test1 set c1=4 where c1=2 ;
Здесь сеанс заблокирован, ожидая, пока другой совершит фиксацию или откат, поэтому давайте запустим запрос, чтобы проверить затронутые строки
SQL> r
1 select s.sid,do.object_name,
2 row_wait_obj#, row_wait_file#, row_wait_block#, row_wait_row#,
3 dbms_rowid.rowid_create ( 1, ROW_WAIT_OBJ#, ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, ROW_WAIT_ROW# )
4 from v$session s, dba_objects do
5 where sid in (SELECT sid FROM GV$LOCK WHERE request>0)
6* and s.ROW_WAIT_OBJ# = do.OBJECT_ID
Session-ID OBJECT_NAME ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW# DBMS_ROWID.ROWID_C
---------- ------------------------------ ------------- -------------- --------------- ------------- ------------------
601 TEST1 1032538 1 123257 1 AAD8FaAABAAAeF5AAB