Базы данных Oracle - статьи

         

Выполнение DML операторов над таблицами, организованными по индексу


Этот сценарий взаимной блокировки можно в какой-то мере отнести к предыдущему случаю. Здесь ожидающие сеансы также запрашивают блокировки транзакций в разделяемом режиме и TX-блокировки в исключительном режиме также  выставляются на строки индекса. Но, в отличие от наложения первичных ключей при вставке, эта взаимная блокировка может проявляться при выполнении любого DML-оператора. Продемонстрируем это на примере. Организуем два сеанса. В первом сеансе создадим индекс-организованную таблицу, вставим в неё две строки и включим трассировку:

ZH@XE(31)> CREATE TABLE t2 (c1 NUMBER PRIMARY KEY, c2 VARCHAR2(50)) ORGANIZATION INDEX;   Таблица создана

ZH@XE(31)> INSERT INTO t2 (c1) VALUES(1);   Вставлено: 1 строка

ZH@XE(31)> INSERT INTO t2 (c1) VALUES(2);   Вставлено: 1 строка

ZH@XE(31)> COMMIT;   Commit complete

ZH@XE(31)> ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';   Session altered

Теперь в первом сеансе изменим  первую и вторую строки.  Во втором сеансе проделаем эти же действия, но в обратной последовательности:

Первый сеанс:

ZH@XE(31)> UPDATE t2 SET c2 = 'Строка1' WHERE c1 = 1;   Изменено: 1 строка

Второй сеанс:

ZH@XE(38)> UPDATE t2 SET c2 = 'Строка2' WHERE c1 = 2;   Изменено: 1 строка

Далее в первом сеансе изменим вторую строку таблицы. Так как на эту строку во втором сеансе выставлена TX-блокировка в исключительном режиме, данные действия приведут к ожиданию:

ZH@XE(31)> UPDATE t2 SET c2 = 'Строка2' WHERE c1 = 2;

Ожидание …

В трассировочном файле первого сеанса в это время наблюдаем ожидание  “конкуренция блокировки строки”:

WAIT #1: nam='enq: TX - row lock contention' ela= 3000041 name|mode=1415053316 usn<<16 | slot=262149 sequence=180 obj#=-1 tim=6315257799



Если после этого мы заглянем в представление v$lock, то обнаружим там точно такую же картину, как и при наложении значений первичных или уникальных ключей:

SYSTEM@XE> SELECT * FROM v$lock WHERE sid IN (31, 38) AND type = 'TX';   ADDR     KADDR    SID TYPE ID1    ID2 LMODE REQUEST CTIME BLOCK -------- -------- --- ---- ------ --- ----- ------- ----- ----- 2A201668 2A20167C 31  TX   262149 180 0     4       114   0     296F5604 296F5720 31  TX   196615 179 6     0       447   0     296F6648 296F6764 38  TX   262149 180 6     0       339   1  


Продолжим изменения, и во втором сеансе поправим первую строку таблицы:

ZH@XE(38)> UPDATE t2 SET c2 = 'Строка1' WHERE c1 = 1;

Ожидание …

И снова, как и раньше,  у нас возникло взаимное блокирование:

ZH@XE(31)> UPDATE t2 SET c2 = 'Строка2' WHERE c1 = 2;   UPDATE t2 SET c2 = 'Строка2' WHERE c1 = 2        * Ошибка в строке 1: ORA-00060: deadlock detected while waiting for resource

Рассмотрим содержимое трассировочного файла взаимной блокировки.

Текущий отменённый оператор:

Current SQL statement for this session: UPDATE t2 SET c2 = 'Строка2' WHERE c1 = 2

Граф взаимоблокировки:

Deadlock graph:                        ---------Blocker(s)--------  ---------Waiter(s)--------- Resource Name          process session holds waits  process session holds waits TX-00030007-000000b3        21      31     X             18      38           S TX-00040005-000000b4        18      38     X             21      31           S

Сеансы, ожидающие строки:

Rows waited on: Session 38: no row Session 31: no row

Как видим, в секции «Rows waited on» нет значений. Это связано с тем, что таблица, организованная по индексу, представляет по своей организационной структуре в некотором смысле индекс. И хотя в данной таблице представлен идентификатор строки, он, по сути, является логическим идентификатором, построенным на основе значений первичного ключа, а не на основе физического размещения. Поэтому, если в предыдущем случае взаимной блокировки в данной секции трассировочного файла иногда и могла появиться информация о сеансе, ожидающем строку, здесь он будет отсутствовать в любых случаях.

В остальном все секции трассировочного файла очень похожи на предыдущий случай. Поэтому, для того чтобы определить, что произошло именно взаимное блокирование при выполнении DML-операторов над таблицами, организованными по индексу, необходимо обратиться в первую очередь в секции Current SQL statement for this session. Если среди объектов, включённых в отменённый SQL-оператор, присутствует таблица этого типа, то вполне возможно, что произошёл именно данный сценарий взаимного блокирования.

Как избежать возникновения взаимной блокировки на таблицах организованных по индексу? Рекомендации здесь такие же, как и в первых двух случаях: последовательность обработки, сокращение времени транзакции и генерация уникальных значений первичных ключей при вставке.


Содержание раздела