Как найти заблокированные строки в Oracle - PullRequest
15 голосов
/ 02 февраля 2010

У нас есть база данных Oracle, а таблица учетных записей клиентов насчитывает около миллиона строк. За прошедшие годы мы создали четыре различных интерфейса пользователя (два в Oracle Forms, два в .Net), и все они остаются в использовании. У нас также есть ряд фоновых задач (как постоянных, так и запланированных).

Иногда что-то удерживает длинную блокировку (скажем, более 30 секунд) в строке таблицы счетов, что приводит к сбою одной из постоянных фоновых задач. Фоновая задача, о которой идет речь, перезапускается сама по себе после истечения времени обновления. Мы узнаем об этом через несколько минут после того, как это произойдет, но к тому времени замок будет снят.

У нас есть основания полагать, что это может быть неадекватный пользовательский интерфейс, но мы не смогли найти «дымящийся пистолет».

Я нашел несколько запросов, в которых перечислены блоки, но это для случая, когда у вас есть две работы, борющиеся за строку. Я хочу знать, какие строки имеют блокировки, когда не обязательно вторая работа, пытающаяся получить блокировку.

Мы находимся на 11g, но проблема с 8i.

Ответы [ 5 ]

12 голосов
/ 02 февраля 2010
Концепция блокировки

Oracle сильно отличается от концепции других систем.

Когда строка в Oracle блокируется, сама запись обновляется новым значением (если есть) иКроме того, блокировка (которая по сути является указателем на блокировку транзакции, находящуюся в сегменте отката) помещается прямо в запись.

Это означает, что блокировка записи в Oracle означает обновление метаданных записи.и выдача логической страницы записи.Например, вы не можете сделать SELECT FOR UPDATE в табличном пространстве только для чтения.

Более того, сами записи не обновляются после принятия: вместо этого обновляется сегмент отката.

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

В Oracle нет традиционного менеджера блокировок, и этоозначает, что получение списка всех блокировок требует сканирования всех записей во всех объектах.Это займет слишком много времени.

Вы можете получить некоторые специальные блокировки, такие как заблокированные объекты метаданных (используя v$locked_object), ожидания блокировки (используя v$session) и т. Д., Но не список всех блокировок для всех объектовв базе данных.

6 голосов
/ 03 февраля 2010

Посмотрите на dba_blockers, dba_waiters и dba_locks для блокировки. Имена должны быть самоочевидными.

Вы можете создать задание, которое будет запускаться, скажем, раз в минуту и ​​регистрировать значения в dba_blockers и текущий активный sql_id для этого сеанса. (через v $ session и v $ sqlstats).

Вы также можете посмотреть в v $ sql_monitor. Это будет журнал по умолчанию для всего SQL, который занимает более 5 секунд. Он также отображается на странице мониторинга SQL в Enterprise Manager.

5 голосов
/ 03 февраля 2010

Вместо блокировок я предлагаю вам посмотреть долгосрочные транзакции , используя v$transaction.Оттуда вы можете присоединиться к v$session, что должно дать вам представление об интерфейсе пользователя (попробуйте столбцы программы и машины), а также о пользователе.

3 голосов
/ 03 апреля 2015

вы можете найти заблокированные таблицы в устной форме, запросив следующий запрос

    select
   c.owner,
   c.object_name,
   c.object_type,
   b.sid,
   b.serial#,
   b.status,
   b.osuser,
   b.machine
from
   v$locked_object a ,
   v$session b,
   dba_objects c
where
   b.sid = a.session_id
and
   a.object_id = c.object_id;
0 голосов
/ 26 октября 2018

Приведенный ниже код найдет все заблокированные строки в таблице.

(Однако вам, вероятно, не нужно запускать этот код. Если у вас возникла проблема с блокировкой, обычно легче найти виновного, используя GV$SESSION.BLOCKING_SESSION и другие связанные представления словаря данных. Пожалуйста, попробуйте другой подход перед запуском это ужасно медленный код.)

Во-первых, давайте создадим пример таблицы и некоторые данные. Запустите это в сессии № 1.

--Sample schema.
create table test_locking(a number);
insert into test_locking values(1);
insert into test_locking values(2);
commit;
update test_locking set a = a+1 where a = 1;

В сеансе # 2 создайте таблицу для хранения заблокированных идентификаторов ROWID.

--Create table to hold locked ROWIDs.
create table locked_rowids(the_rowid rowid);
--Remove old rows if table is already created:
--delete from locked_rowids;
--commit;

В сеансе # 2 запустите этот блок PL / SQL, чтобы прочитать всю таблицу, проверить каждую строку и сохранить заблокированные ROWID. Имейте в виду, это может быть смехотворно медленным. В вашей реальной версии этого запроса измените обе ссылки на TEST_LOCKING на свою собственную таблицу.

--Save all locked ROWIDs from a table.
--WARNING: This PL/SQL block will be slow and will temporarily lock rows.
--You probably don't need this information - it's usually good enough to know
--what other sessions are locking a statement, which you can find in
--GV$SESSION.BLOCKING_SESSION.
declare
    v_resource_busy exception;
    pragma exception_init(v_resource_busy, -00054);
    v_throwaway number;
    type rowid_nt is table of rowid;
    v_rowids rowid_nt := rowid_nt();
begin
    --Loop through all the rows in the table.
    for all_rows in
    (
        select rowid
        from test_locking
    ) loop
        --Try to look each row.
        begin
            select 1
            into v_throwaway
            from test_locking
            where rowid = all_rows.rowid
            for update nowait;
        --If it doesn't lock, then record the ROWID.
        exception when v_resource_busy then
            v_rowids.extend;
            v_rowids(v_rowids.count) := all_rows.rowid;
        end;

        rollback;
    end loop;

    --Display count:
    dbms_output.put_line('Rows locked: '||v_rowids.count);

    --Save all the ROWIDs.
    --(Row-by-row because ROWID type is weird and doesn't work in types.)
    for i in 1 .. v_rowids.count loop
        insert into locked_rowids values(v_rowids(i));
    end loop;
    commit;
end;
/

Наконец, мы можем просмотреть заблокированные строки, присоединившись к таблице LOCKED_ROWIDS.

--Display locked rows.
select *
from test_locking
where rowid in (select the_rowid from locked_rowids);


A
-
1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...