Выполнение 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-оператор, присутствует таблица этого типа, то вполне возможно, что произошёл именно данный сценарий взаимного блокирования.
Как избежать возникновения взаимной блокировки на таблицах организованных по индексу? Рекомендации здесь такие же, как и в первых двух случаях: последовательность обработки, сокращение времени транзакции и генерация уникальных значений первичных ключей при вставке.
Содержание раздела