Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

2010 г.

Взаимные блокировки в Oracle

Сергей Жилин, январь – март 2010 года
http://dba.ucoz.ru

Назад Содержание Вперёд

Нехватка слотов в таблице транзакций блока

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

В ранних версиях Oracle начальное и максимальное количество слотов таблицы транзакций можно было задавать  с помощью параметров таблицы INITRANS и MAXTRANS. Теперь изменение этих параметров не  имеет никакого значения. В связи с этим, для того чтобы смоделировать данный сценарий взаимного блокирования, нам пришлось бы организовать одновременно более 255 транзакций. Сделать это было бы затруднительно, поэтому для моделирования ситуации мы будем использовать экземпляр Oracle версии 9i, где изменение одного из перечисленных параметров всё ещё было возможно.

Для начала создадим две одинаковые таблицы t4 и t5, с искусственно ограниченным максимальным размером таблицы транзакций блока, равным двум слотам:

 Подключение к:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 – Production

ZH@ALFA9> CREATE TABLE t4 (c1 NUMBER PRIMARY KEY, c2 VARCHAR2(50)) PCTFREE 0 INITRANS 2 MAXTRANS 2;
 
Таблица создана
 
ZH@ALFA9> CREATE TABLE t5 (c1 NUMBER PRIMARY KEY, c2 VARCHAR2(50)) PCTFREE 0 INITRANS 2 MAXTRANS 2;
 
Таблица создана

Занесём в каждую из этих таблиц по три значения. Причём все добавленные строки должны уместиться в двух блоках, по одному на каждую таблицу:

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

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

ZH@ALFA9> INSERT INTO t4 (c1) VALUES(3);
 
Вставлено: 1 строка

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

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

ZH@ALFA9> INSERT INTO t5 (c1) VALUES(3);
 
Вставлено: 1 строка

ZH@ALFA9> COMMIT;
 
Commit complete

Далее образуем три сеанса и в каждом из них изменим следующие строки.

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

ZH@ALFA9I(12)> UPDATE t4 SET c2 = 'Строка1' WHERE c1 = 1;
 
Изменено: 1 строка
 
ZH@ALFA9I(12)> UPDATE t5 SET c2 = 'Строка1' WHERE c1 = 1;
 
Изменено: 1 строка

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

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

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

Третий сеанс:

ZH@ALFA9I(14)> UPDATE t5 SET c2 = 'Строка3' WHERE c1 = 3;
 
Изменено: 1 строка

Теперь снова вернёмся ко второму сеансу:

ZH@ALFA9I(13)> UPDATE t5 SET c2 = 'Строка2' WHERE c1 = 2;

Ожидание …

Почему возникло ожидание, ведь изменяются совершенно разные и не зависящие друг от друга строки? На самом деле, в этом нет ничего неожиданного. Ещё при создании таблиц  мы указали, что слотов в таблице транзакций блока не может быть больше двух. Так как данные в каждой из созданных нами таблиц занимают по одному блоку, то выполнив команды, перечисленные выше, мы исчерпали лимит слотов в блоке таблицы t5.  В результате этого, при попытке обновить данные в блоке таблицы второй сеанс вынужден ждать появления свободного слота. Чтобы убедиться в этом, как говорится, наглядным образом, заглянем в трассировочный файл второго сеанса, а также в системное представление v$lock.

В файле трассировки у нас довольно скудная информация. Здесь мы видим только то, что в сеансе постоянно возникает непонятное ожидание «очередь»:

WAIT #1: nam='enqueue' ela= 3077805 p1=1415053316 p2=65545 p3=455

А вот представление v$lock даёт нам гораздо больше информации:

SYSTEM@ALFA9I> SELECT * FROM v$lock WHERE type = 'TX';
 
ADDR     KADDR    SID TYPE ID1    ID2 LMODE REQUEST CTIME BLOCK
-------- -------- --- ---- ------ --- ----- ------- ----- -----
67B7F044 67B7F150 12  TX   589870 447 6     0       211   1    
67B7A1FC 67B7A308 13  TX   393245 450 6     0       110   0    
682BED20 682BED30 13  TX   589870 447 0     4       3     0    
67BAB4A8 67BAB5B4 14  TX   65545  455 6     0       39    0    
 
Выбрано: 4 строки

Тут мы действительно видим во втором сеансе (13) ожидающую TX-блокировку в разделяемом режиме. Причем, судя по значениям столбцов ID1 и ID2 , второй сеанс ожидает освобождения слота, занятого первым сеансом (12).  Выбор Oracle первого сеанса в качестве блокирующего не носит какого-то обязательного характера. Если мы попробуем смоделировать это ожидание снова, то блокировать у нас будет уже третий сеанс. Есть ли в этом отличие для нашей моделируемой ситуации? По большому счёту – нет, поэтому продолжим наши изменения, и в третьем сеансе изменим строку в таблице t4:

ZH@ALFA9I(14)> UPDATE t4 SET c2 = 'Строка3' WHERE c1 = 3;

Ожидание …

Возникает бесконечное ожидание. Вследствие этого, во втором сеансе мы наблюдаем ошибку взаимного блокирования:

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

Отчего произошла взаимная блокировка? Почему Oracle посчитала, что данная ситуация является тупиковой? Попробуем ответить на эти вопросы. Как мы видели ранее, у нас возникло ожидание в одном из сеансов из-за того,  что все слоты таблицы транзакций в блоке таблицы t5 были заняты первым и третьим сеансами. То есть второй сеанс ожидал освобождения свободного слота ITL, чтобы заблокировать строку таблицы t5 для изменения. Пытаясь обновить строку в таблице t4, мы создали идентичное ожидание в третьем сеансе, но уже для блока таблицы t4. В результате на момент времени возникновения взаимной блокировки у нас получилось два ожидающих сеанса – второй и третий. Причём второй сеанс ожидал свободного слота в ITL блоке таблицы t5, все слоты которой были заняты первым и третьим сеансами, а третий сеанс – свободного слота в ITL блоке таблицы t4, занятой первым и вторым сеансами.

Из этой ситуации выходило, что второй и третий сеансы не могли освободить слоты ITL в блоках таблиц, так как сами находились в ожидании друг друга. Вроде бы складывается ситуация взаимного блокирования. Но мы забыли про первый сеанс. Ведь он находился не в режиме ожидания. Что если мы бы попробовали откатить или зафиксировать изменения в нём? В этом случае в ITL блоков таблиц t4 и t5 обязаны освободиться два слота, вследствие чего второй и третий сеансы  должны были выйти из ожидания.  Но на самом деле всё не так просто. СУБД Oracle в этой сложившейся ситуации как бы не принимает во внимание возможность освобождения слотов таблицы транзакций блока первым сеансом и определяет такое блокирование как взаимное. Вполне возможно, это связано с особенностью построения и анализа графа ожидания транзакций. Посмотрим, как он будет выглядеть в нашем случае.

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

Что же нам в этом случае покажет файл трассировки взаимной блокировки? Заглянем в его содержимое:

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

Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-0006001d-000001c2        15      13     X             16      14           S
TX-00010009-000001c7        16      14     X             15      13           S

Rows waited on:
Session 14: no row
Session 13: no row

Ничего особенного. Все секции файла трассировки похожи на предыдущие сценарии. Правда, следует отметить, что в файле отсутствует хоть какое-то упоминание о первом сеансе, и это ещё раз  подтверждает то, что он не участвует в ситуации взаимного блокирования, хотя содержимое представления v$lock явно указывало, что именно этот сеанс осуществляет блокировку.

Если вам в будущем придётся анализировать файл с подобным содержимым, обращайте своё внимание в первую очередь на версию Oracle. Такие взаимные блокировки на старших релизах Oracle маловероятны. Кроме этого, такая взаимная блокировка никогда не возникнет на операторах вставки INSERT. Ясно, что если сеанс при вставке  столкнётся с нехваткой слотов в ITL, он просто осуществит вставку в другой блок.

Как сделать, чтобы подобные ситуации взаимных блокировок не возникали? Рецепт  довольно прост. Во-первых, старайтесь не изменять параметры  INITRANS  и MAXTRANS в сторону уменьшения без острой необходимости. Во-вторых, если параметр был всё же изменён, увеличивайте его до полного исчезновения взаимных блокировок.

Назад Содержание Вперёд

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...