|
|
|
Управление совместным доступом Василий Шульженко Типы совместного доступа
Управление совместным доступом (Concurrency Control) влияет на то, как данные просматриваются и изменяются пользователями, которые одновременно обращаются к одной и той же информации. Например, хотите ли Вы, чтобы один пользователь мог просматривать заказ, изменяемый в настоящее время другим пользователем? Хотите ли Вы, чтобы заказ, просматриваемый одним пользователем, был доступен для изменения другому пользователю? Существуют два класса управления совместным доступом:
INFORMIX управляет совместным доступом используя блокировки. Существует три типа блокировок, которые могут быть использованы:
Совместный доступ при чтении:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SET TRANSACTION |
SET ISOLATION |
| Read Uncommitted | Dirty Read |
| Read Committed | Committed Read |
| Not Supported | Cursor Stability |
| (ANSI) Repeatable Read | (INFORMIX) Repeatable Read |
| Serializable | (INFORMIX) Repeatable Read |
Оператор SET TRANSACTION соответствует стандарту ANSI SQL-92. Этот оператор похож на оператор INFORMIX SET ISOLATION, однако, оператор SET ISOLATION не является ANSI- совместимым оператором и не обеспечивает режимов доступа.
Уровни изоляции, которые можно установить с помощью оператора SET TRANSACTION, являются почти параллельными тем, что устанавливаются оператором SET ISOLATION, как показано выше в таблице.
Другое отличие между операторами SET TRANSACTION и SET ISOLATION заключается в характере изменения уровней изоляции во время транзакции. Оператор SET TRANSACTION может быть выполнен для каждой транзакции только один раз. Посредством оператора SET ISOLATION можно изменять уровень изоляции несколько раз уже после того, как транзакция началась.
INFORMIX |
ANSI |
Описание |
| DIRTY READ | READ UNCOMMITTED | Уровень изоляции по умолчанию, устанавливаемый в базе данных без ведения журнала. |
| COMMITTED READ | READ COMMITTED | Уровень изоляции по умолчанию, устанавливаемый в несовместимой с ANSI базе данных с ведением журнала. |
| REPEATABLE READ | SERIALIZABLE | Уровень изоляции по умолчанию, устанавливаемый в ANSI совместимой базе данных. |
Уровень изоляции по умолчанию для конкретной базы данных устанавливается в момент создания базы. Значения уровня изоляции для каждого типа баз данных приведены выше.
Уровень изоляции |
Описание |
| Dirty Read или Read Uncommitted | Позволяет этому процессу видеть DIRTY данные. |
| Committed Read или Read Committed | Не позволяет этому процессу видеть DIRTY данные. |
| Cursor Stability | Не позволяет другим процессам изменять текущую запись. |
| (ANSI) Repeatable Read или Serializable | Не позволяет другим процессам изменять любые строки, уже просмотренные текущим процессом, пока он не завершит работу с ними. |
Подводя итог, приведенная выше таблица показывает соответствие уровней изоляции степеням допустимого взаимного влияния (или терпимости вмешательства).
Совместный доступ при обновлении:
уровни детализации блокировок
Уровни детализации блокировок:
Уровни детализации (избирательность) блокировки соотносятся с размером блокируемого объекта. Избирательность изменяется в пределах пяти уровней, от более грубой к более точной. Эти пределы позволяют поддерживать компромисс между совместным доступом и накладными расходами на блокировки.
INFORMIX-OnLine обеспечивает пять различных уровней детализации блокировок, наиболее грубым из них является уровень базы данных; максимально точным - блокировка записей таблиц. Блокировка уровня ключа накладывается на элементы индексов.
DATABASE STORES EXCLUSIVE;
Иногда является необходимым или предпочтительным закрыть некоторым пользователям доступ к какой либо части базы данных в течение некоторого периода времени. Это может потребоваться в следующих случаях:
Полностью база данных может быть заблокирована с помощью оператора DATABASE с операцией EXCLUSIVE. Пример такого выражения приведен выше. Операция EXCLUSIVE открывает базу данных в исключительном режиме и позволяет работать с ней только текущему пользователю.
Для того чтобы разрешить обращение к базе данных другим пользователям, необходимо выполнить оператор CLOSE DATABASE и затем повторно открыть базу данных. Пользователи с любым уровнем привилегий могут открывать базу данных в исключительном режиме. В этом случае они не получают никаких дополнительных привилегий в дополнение к тем, что они имеют при работе с базой данных в обычном режиме.
Блокировка уровня таблицы может использоваться для запрещения изменения записей в таблице другими пользователями. Использование блокировок уровня таблицы полезно в следующих случаях:
Блокировки уровня таблицы следует использовать только в том случае, когда требуется выполнить большой объем обновлений записей таблицы при работе в многопользовательской среде и когда одновременная работа нескольких пользователей будет помехой.
На таблицу может быть наложена только одна блокировка одновременно. Поэтому, если один пользователь заблокировал таблицу, никакой другой не сможет сделать это еще раз до тех пор, пока первый пользователь не отменит блокировку.
Блокировка таблиц системного каталога не допускается.
Если Ваша база данных работает с транзакциями, блокировка уровня таблицы может применяться только внутри транзакции. Таким образом, удостоверьтесь, что вы выполнили оператор BEGIN WORK перед тем, как пытаться заблокировать таблицу. Таблица будет автоматически разблокирована по окончании транзакции.
Блокировка таблицы в разделяемом режиме
LOCK TABLE customer IN SHARE MODE;
В случаях, когда желательно дать другим пользователям возможность чтения данных, однако запретить им изменение данных таблицы, следует использовать оператор LOCK TABLE совместно с операцией IN SHARE MODE.
Когда таблица заблокирована в режиме SHARE, другим пользователям разрешается пользоваться оператором SELECT для чтения данных из таблицы, однако они не будут иметь возможности выполнять операторы INSERT, DELETE или UPDATE над записями таблицы или оператор ALTER над самой таблицей.
Важно: Необходимо помнить, что блокировка таблицы в SHARE MODE не запрещает применять блокировки для выполнения операций обновления записей тем же процессом. Во избежание применения исключительных блокировок записей в дополнение к разделяемой блокировке таблицы необходимо использовать блокировку таблицы в EXCLUSIVE MODE.
Блокировка таблицы в исключительном режиме
LOCK TABLE orders IN EXCLUSIVE MODE;
Если является необходимым запретить другим пользователям обращаться к таблице каким бы то ни было образом, требуется применить к таблице блокировку EXCLUSIVE MODE.
В EXCLUSIVE MODE другие пользователи не будут иметь возможности пользоваться операторами SELECT (исключая случаи использования уровня изоляции DIRTY READ), INSERT, UPDATE и DELETE по отношению к записям таблицы до тех пор, пока таблица не будет разблокирована.
К таблице может быть применена только одна блокировка, независимо от того, сколько записей обновляется в течение всей транзакции.
В случае если таблица содержит BLOB-объекты, которые содержатся в blobspace: если таблица заблокирована в EXCLUSIVE MODE, и выполнение изменений касается значений типа BLOB, на каждый BLOB-объект накладывается исключительная блокировка. Эти блокировки снимаются автоматически. На одну страницу blobspace используется две блокировки. Если BLOB'ы хранятся в таблице, дополнительные блокировки не применяются.
UNLOCK TABLE customer
Оператор UNLOCK TABLE восстанавливает возможность обращения к заблокированной перед этим таблице. Этот оператор используется в случаях, когда необходимость в ограничении возможности доступа к таблице другим пользователям отпадает.
Внимание: В тех случаях, когда таблица была заблокирована во время транзакции, выполнение оператора UNLOCK TABLE не допускается и возвращает ошибку, окончание транзакции (посредством операторов COMMIT или ROLLBACK) снимает блокировку автоматически.
| SET LOCK MODE TO WAIT | Ждать, пока блокировка не будет снята |
| SET LOCK MODE TO NOT WAIT | Не ждать, пока блокировка будет снята |
| SET LOCK MODE TO WAIT 20 | Ждать 20 секунд, пока блокировка не будет снята |
Оператор SET MODE используется для определения, должен ли вызов, изменяющий или удаляющий строку в таблице, ожидать снятия блокировки этой строки.
Опция TO NOT WAIT заставляет оператор возвратить ошибку, если запись, которую требуется изменить или удалить (или выбрать для обновления (SELECT row FOR UPDATE)), заблокирована другим процессом. Этот режим устанавливается по умолчанию.
Опция TO WAIT при попытке изменить или удалить строку заставляет оператор ждать, пока запись, заблокированная другим процессом, не будет разблокирована. В этом случае можно также указать время ожидания разблокирования в секундах.
Когда создается таблица, пользователь должен определить режим блокировки, используемый при обращении к любой строки этой таблицы. Блокировка уровня страницы блокирует всю страницу всегда, когда есть необходимость заблокировать одну из записей, содержащихся в таблице. Блокировки уровня строки при запросе на блокировку блокируют только одну запись. Уровень блокировки по умолчанию, применяемый при создании таблицы - блокировка уровня страницы.
Блокировки уровня страницы полезны в тех случаях, когда во время транзакции обработка записей выполняется в порядке, установленном cluster-индексом или в порядке физического хранения записей в таблице. Блокировки уровня строки полезны, напротив, в случаях, когда во время транзакции данные читаются в произвольном порядке.
Когда количество блокировок становится достаточно большим, появляется риск возникновения следующих ситуаций:
Существует компромисс между этими двумя уровнями блокировок. Блокировка уровня страницы требует меньших ресурсов, чем требуется для блокировки уровня строки, однако она также уменьшает совместный доступ. Если блокировка уровня страницы применена к странице, содержащей большое количество записей, другие процессы, которым необходим доступ к данным этой же страницы, его не получат.
|
|||||
B |
X |
U |
S |
нет |
|
| Запрошено | X |
нет |
нет |
нет |
да |
U |
нет |
нет |
да |
да |
|
S |
нет |
да |
да |
да |
|
Приведенная таблица показывает взаимодействие между уже наложенными блокировками и запрошенными блокировками, по отношению к одной и той же строки/странице двумя разными процессами. На горизонтальной оси показаны блокировки, которые могли бы быть наложены процессом A. На вертикальной оси показаны блокировки, запрошенные процессом B. Матрица показывает результат запроса на применение блокировки (да - блокировка разрешена, нет - блокировка запрещена).
Когда множество процессов работают с одними и теми же записями таблицы, возможно возникновение мертвых точек (deadlock).
Процесс A заблокировал строка x. После этого он собирается заблокировать вторую запись, y. Однако строка y уже заблокирована другим пользователем, процессом B. Если процесс A ожидает снятия блокировки, он будет ждать, пока процесс B не разблокирует строка y. Тем временем процесс B удерживает заблокированной строка y, и собирается заблокировать строка x. Она уже заблокирована другим пользователем, и если процесс B ожидает снятия блокировки, он будет ждать, пока процесс A не снимет блокировку строки x. Другими словами, A ждет B и B ждет A. Это мертвая точка и оба процесса будут ждать вечно. Эта ситуация может также возникать и для большего количества пользователей. Мертвые точки являются серьезной проблемой, поскольку она могут заморозить большую часть активности базы данных. INFORMIX содержит механизм, позволяющий определять мертвые точки и предотвращать их возникновение. Следующий параграф описывает, как это делается.
Сервер базы данных поддерживает список блокировок каждого пользователя системы. Перед тем, как разрешить блокировку, сервер рассматривает список блокировок каждого пользователя. Если ресурс, который процесс желает заблокировать, уже заблокирован, определяется владелец этой блокировки и его список блокировок анализируется на предмет наличия в нем ожиданий снятия блокировки с ресурса, заблокированного процессом, ожидающим выполнения новой блокировки. Если таковые имеются, ситуация определяется как мертвая точка и пользователю, ожидающему выполнения блокировки возвращается сообщение об ошибке:
The ISAM error code returned is: -143 ISAM error: deadlock detected
Блокировка значения ключа - метод блокировки B+ дерева, в котором блокируется ключ, который обновляется, вставляется или удаляется.
| значение ключа |
идентификатор записи (rowid) |
флаг удаления |
0 = не удален 1 = удален
INFORMIX-OnLine Dynamic Server использует метод блокировки B+ дерева, называемый блокировкой значения ключа. Для оператора DELETE, например, это означает, что OnLine в действительности блокирует только ключевое значение, которое удаляется в течение транзакции. Для того чтобы это сделать, OnLine не удаляет значение ключа в действительности, однако помечает его, как удаленное, путем установки системного флага удаления, который физически расположен в каждом элементе индекса.
Флаг удаления является частью значения ключа любого индекса. Это однобайтовое значение содержит 0 для ключей, которые не удалены и 1 - для удаленных ключей. Дополнительно в заголовке страницы есть флаг, показывающий, что на странице существуют помеченные удаленными ключи, которые должны быть удалены физически.
Блокировки значений ключей не выполняются в тех случаях, когда истинными являются следующие утверждения:
Пользователь 1:
begin work;
delete from customer where lname = "Sadler";
Пользователь 2:
begin work;
insert into customer values(..,"Smith",..);
| После удаления Sadler: | После вставки Smith: | ||||
lname |
Блокировка |
Флаг удаления |
lname |
Блокировка |
Флаг удаления |
Sadler |
X |
1 |
Sadler |
X |
1 |
Smith |
X |
0 |
|||
Vector |
0 |
Vector |
0 |
||
Приведенная таблица показывает пример того, как работает блокировка значения ключа.
Первый пользователь удаляет строку из таблицы customer, в которой хранилась фамилия Sadler. Значение ключа не удаляется до подтверждения транзакции. Вместо этого, флаг удаления устанавливается в 1 и это значение ключа блокируется в исключительном режиме.
Второй пользователь вставляет строку, содержащую фамилию Smith. Значение ключа, соответствующее вставленной строке, блокируется в исключительном режиме.
Обратите внимание на то, что блокировки остаются в таблице блокировок до тех пор, пока транзакция не будет подтверждена.
Пользователь 1:
begin work;
insert into customer values(..,"Richards",..)
Пользователь 2:
begin work;
delete from customer where lname = "Pauli"
| После вставки Richards: | После удаления Pauli: | ||||
lname |
Блокировка |
Флаг удаления |
lname |
Блокировка |
Флаг удаления |
Pauli |
0 |
Pauli |
X |
1 |
|
Richards |
X |
0 |
Richards |
X |
0 |
Sadler |
0 |
Sadler |
0 |
||
В приведенном выше примере первый пользователь вставляет, содержащую ключевое значение Richards, строку в таблицу customer. Ключевое значение блокируется в исключительном режиме.
Второй пользователь удаляет ключ, содержащий фамилию Pauli. При использовании блокировки ключевого значения, ключ остается в индексе заблокированным в исключительном режиме и флаг удаления устанавливается в значение 1.
Другие пользователи, читающие данные
Если другие пользователи читают ключи и обращаются к ключу, флаг удаления которого установлен в 1, такой пользователь обязан определить существование блокировки. Если блокировка существует, это означает, что удаление не было завершено и при этом генерируется ошибка (или начинается ожидание снятия блокировки, если использовано SET LOCK MODE TO WAIT). Если блокировка отсутствует, это означает, что транзакция была подтверждена и рассматриваемый ключ в действительности не существует. Ключ пропускается.
Пользователь, читающий данные, и для которого установлен уровень изоляции DIRTY READ, пропускает ключи с установленным в 1 флагом удаления, не выполняя никаких проверок на блокировки.
Если пользователь выполняет INSERT при уровне изоляции REPEATABLE READ
Пользователь 1:
begin work;
set isolation to repeatable read;
select * from customer where customer_num >= 104
customer_num |
Блокировка |
Флаг удаления |
103 |
0 |
|
105 |
SR |
0 |
Пользователь 2 (этот оператор завершится неудачно):
insert into customer(customer_num) values(104);
INFORMIX-OnLine Dynamic Server использует два типа блокировок для управления уровнем изоляции REPEATABLE READ:
Неудачи могут возникнуть только в тех случаях, когда примыкающий ключ заблокирован SR-блокировкой (это показывает, что к этой строке было применено разделяемое повторяемое чтение) или XR-блокировкой (это означает, что эта строка была вставлена или удалена при повторяющемся (REPEATABLE) чтении). Приведенный выше пример показывает такое чтение с SR-блокировкой, примененной к заказчику номер 105. Другой пользователь пытается добавить заказчика номер 104 и получает ошибку, потому что примыкающий ключ заблокирован SR-блокировкой. Вставка завершается неудачно, несмотря на ее уровень изоляции.
Эта специальная проверка на уровень изоляции REPEATABLE READ необходима, поскольку этот уровень должен защищать совокупность записей, которые он прочитал. Во всех других отношениях, XR-блокировка работает как X-блокировка и SR-блокировка работает как S-блокировка. Выполнение оператора вставки с уровнем изоляции REPEATABLE READ будет завершено успешно в том случае, когда к примыкающему ключу применена X-блокировка (но не XR).
Блокировки, при использовании которых применяется блокировка значений ключа
Операция |
Блокировка текущего элемента |
Блокировка следующего элемента |
| SELECT | S блокировка (CS) S проверка блокировки (CR) SR блокировка (RR) |
Нет |
| INSERT | X блокировка XR блокировка (RR) |
Проверить наличие XR или SR блокировки |
| DELETE | X блокировка XR блокировка (RR) |
Нет |
Итоговая информация по блокировкам, примененным к текущей и примыкающей записям индекса, собрана в приводимой таблице. Использованные в ней сокращения - различные уровни изоляции, которые можно получить.
| CR | Committed read |
| CS | Cursor stability |
| RR | Repeatable read |
Постольку оператор DELETE не удаляет связанные ключи из индекса, должен существовать некий механизм, периодически проводящий удаление ключей. Этот механизм известен как btcleaner thread.
Когда элемент удаляется, взводится флаг удаления. Во время подтверждения транзакции в специальную область памяти общего пользования (называемую btree cleaner pool) помещается запрос на удаление элемента. Запрос представляет собой 20 байтовую структуру, содержащую номер tblspace, номер страницы и номер удаляемого ключа. Btree cleaner pool может содержать только один запрос на удаление для одной и той же страницы. Начальный размер btree cleaner pool равен 1 килобайту, однако, если btree cleaner pool заполнен, к нему добавляется еще 1 килобайт для размещения новых запросов и так далее.
Каждую минуту или каждый раз, когда количество запросов в btree cleaner pool превысит 100, btcleaner thread <просыпается> и считывает запросы из btree cleaner pool. Для каждого запроса btcleaner thread находит страницу и удаляет ключ, помеченный как удаленный. Однако перед удалением btcleaner thread удостоверяется в том, что строка была подтверждена, проверяя ее на наличие блокировки.
Как другие процессы видят удаленные ключи
Если при чтении индекса другой процесс обнаружит удаленный ключ, он проверит, является ли значение ключа заблокированным. Если это так, процесс будет работать в предположении, что строка существует. Если, однако, строка помечена, как удаленная, но не заблокирована (btcleaner thread еще не удалил ее), процесс пропускает запись, как если бы ее вообще не было.
Оператор UPDATE STATISTICS обычно просматривает листовые страницы btree для сбора статистики для оптимизатора запросов. Кроме того, оператор UPDATE STATISTICS просматривает также страницы, которые имеют взведенный флаг удаления в заголовке таблицы. Если ключи найдены, страница помещается в btree cleaner pool для очистки.
Оператор UPDATE STATISTICS действует, как запасной вариант для нормальных механизмов, которые удаляют элементы, предназначенные для удаления. Например, если аварийная остановка системы приведет к потере данных из btree cleaner pool (поскольку он находится в памяти общего доступа), ключи не будут удалены. Когда нормальная работа системы будет восстановлена, все будет работать нормально, а предназначенные для удаления ключи будут просто занимать место, которое невозможно будет немедленно повторно использовать. Чтобы удалить такие элементы можно запустить оператор UPDATE STATISTICS.
Для выполнения этого упражнения требуется, чтобы Вы имели два терминальных сеанса, выполняющих утилиту dbaccess в Вашей базе данных Stores7.
Сеанс A - введите:
begin work;
update manufact set lead_time = "2"
where manu_code = "ANZ";
Сеанс B - введите:
select * from manufact
where manu_code = "HRO";
Что происходит и почему?
Сеанс A - введите:
rollback work;
alter table manufact lock mode(row);
begin work; update manufact set lead_time = "2"
where manu_code = "ANZ";
Сеанс B - введите:
select * from manufact
where manu_code = "HRO";
Каким образом этот оператор получает доступ к данным? Какова разница между результатами шага ?4 и ?2?
Сеанс B - введите:
select * from manufact;
Что происходит и почему?
Сеанс B - введите:
set isolation to dirty read;
select * from manufact
Что произошло иначе и почему?
Сеанс B - введите:
set isolation to committed read;
set lock mode to wait;
select * from manufact;
Что происходит и почему?
Сеанс A - введите:
commit work;
Что произошло в сеансе B после выполнения этого оператора и почему?
Сеанс A - введите:
set isolation to repeatable read;
begin work;
update manufact set lead_time = "2"
where manu_name = "Husky";
Каким образом происходит обращение к данным оператором UPDATE - последовательно или по индексу? Какие типы блокировок создаются во время выполнения оператора UPDATE?
Сеанс B - введите:
set lock mode to not wait;
update manufact set lead_time = "2"
where manu_code = "ANZ";
Как происходит обращение к данным во время выполнения этого оператора? Что происходит и почему?
Сеанс B - введите:
select * from manufact
where manu_code = "ANZ";
Какой уровень изоляции имеет этот оператор? Как Вы думаете, были ли созданы во время его выполнения какие-либо блокировки? Что происходит и почему?
|
Украинская баннерная сеть
|