|
Sybase
|
|
|
|
|
Продукты
|
|
|
|
|
Сообщества
|
|
|
|
|
Меню
|
|
|
|
|
Вход
|
|
|
|
|
Рассылка
|
|
|
|
|
Статистика
|
|
|
|
|
Выпуск 16
|
Выпуск 16Доброй день, уважаемые подписчики. Предлагаю Вашему вниманию очередной, 16-й номер рассылки. В данном номере рассылки я публикую вторую статью, посвященную механизму транзакций в ASA 9.
Все что мы знаем о транзакциях в ASA 9 (часть 2 – блокировки)
Вступление от автора
Данная статья рассчитана на читателей, имеющих точное представление о транзакции в ASA 9. Подробное описание механизма реализации транзакций было описано в предыдущем 15-ом выпуске рассылки.
Назначение блокировок
Для обеспечения атомарности транзакций и поддержки различных уровней изоляции транзакций, сервер ASA использует механизм блокировок, который позволяет серверу путем наложения блокировок на записи, управлять последовательностью доступа и изменения к ним параллейных транзакций. Сервер автоматически управляет блокировками, в зависимости от проводимой операции и установленным уровнем изоляции для транзакции. Снимаются блокировки с записей по окончании проведения транзакции, то есть операторами COMMIT и ROLLBACK.
Любая транзакция, работающая с записями, может на них наложить блокировки, что приведет, в зависимости от типа блокировок, к частичному или полному ограничению доступа к этим записям конкурирующим транзакциям.
Реализация механизма блокировок
Существуют следующие виды блокировок:
Служебная блокировка
Накладываются на мето-описание схемы объектов, участвующих в проводимой транзакции. Такая блокировка запрещает изменение описания этих объектов до завершения транзакции, гарантируя таким образом, что другие транзакции не изменят их описание, что могло бы привести к непредсказуемым результатам (например: одна транзакция проводит чтение всех полей таблицы, а другая в этот момент пытается удалить столбцы с данной таблицы).
Табличная блокировка (TABLE LOCK (SHARED/EXCLUSIVE))
Накладывается как одна блокировка на всю таблицу. Автоматически используется в монопольном режиме DDL операторами во время изменения структуры таблицы. Так же может быть явно использована сессией для блокировки всей таблицы с помощью оператора LOCK TABLE, как в разделяемом, так и монопольном режиме блокировки, что позволяет снизить ресурсоемкость работы сессии для тех случаев, где сессия изначально знает, что в ходе работ будет блокирован больший процент от всего кол-ва записей таблицы. Соответствующе данный
способ будет изначально менее ресурсозатратным и более выгодным, чем наложение многочисленных позаписных блокировок, так как все последующие операции над таблицей с такой блокировкой не будут приводить к возникновения новых блокировок, где такая блокировка может считаться частным случаем экскалации блокировок. Особенно удобно применять данную блокировку для массового обновления или удаления записей, а так же чтения записей на уровне “Serializable”. На момент существования блокировки на таблицу другие транзакции
не смогут добавлять, изменять и удалять записи для разделяемой блокировки, а так же читать данные, если блокировка указана, как монопольная.
Разделяемые на чтение “READ LOCK (SHARED)”
Накладываются читающими сессиями. Запрещают пишущим сессиями изменять данные с такими блокировками. Другие читающие сессии имеют право читать данные с такими блокировками.
Монопольные пишущие “WRILE LOCK (EXCLUSIVE)”
Накладываются пишущими или читающими сессиями (в случае явного указания в запросе хинтом XLOCK). Запрещают читать и изменять данные как пишущим, так и читающим сессиям (здесь исключение имеют только читающие сессии с уровнем изоляции READ UNCOMMITED).
Блокировка запрета вставки “PHANTOM LOCK OR ANTI-INSERT LOCK (SHARED)”
Накладывается читающими сессиями на момент чтения данных транзакцией на уровне изоляции “Serializable”. Предотвращает появление фантомов. Это мешает другим транзакциям вставить записи немедленно в таблицу рядом с записью, на которую наложена такая блокировка. Во время чтения записей, при такой блокировке на каждую считанную запись накладывается блокировка разделения на чтение и дополнительная блокировка на индекс, блокирующая вставку узлов индекса от заблокированного узла. Если подходящих индексов не найдено,
то для борьбы с фантомами, блокировки накладываются на все записи таблицы, находящиеся на одной странице рядом с блокируемой записью, что может плохо повлиять на эффективность конкурентного доступа других транзакций из за блокировок лишних записей, казалось бы не участвующих в транзакциях. Другие читающие сессии имеют право читать данные с такими блокировками.
Блокировка резервирование вставки “INSERT LOCK, OR ANTI-PHANTOM LOCK (SHARED)”
Накладывается пишущими сессиями для предотвращения вставки записи другими транзакциями с значениями уникальных полей, обрабатываемых текущей транзакцией. Когда транзакция накладывает такую блокировку, это предотвращает появление записей, значения которых были бы способны нарушить уникальность и целостность данных, согласно описанным правилам таблицы. Другие читающие сессии имеют право читать данные с такими блокировками.
Блокировки могут накладываться на следующие объекты:
На таблицы
Могут накладываться только табличные блокировки для блокировки от изменений описания таблицы, от изменений данных или полного доступа к данным других транзакций.
На записи (ROW LEVEL)
Могут накладываться разделяемые и эксклюзивные позаписные блокировки. Стоит всегда помнить о том, что кол-во блокированных записей может изменяться в зависимости от используемого уровня изоляции для читающих транзакций и всегда будет равным кол-ву изменяемых записей для пишущих транзакций.
На позицию сканирования (Insertion points between rows)
Обычно транзакция перебирает все записи, используя существующий подходящий индекс или полным перебором записей таблицы при отсутствии индексов. Вне зависимости от способа поиска записи, сервер может поставить блокировку на позицию сканирования перед записью, таким образом, исключив возможность другими транзакциями вставить запись перед блокируемой записью, что бывает актуально для поддержки уникальных индексов и получения данных на уровне изоляции serializable. На позицию сканирования могут применяться
блокировки запрета и резервирования вставки.
Связь между индексами и блокировками сканирования
Сервер ASA при наложении блокировок на позиции сканирования старается активно пользоваться существующими индексами с целью поиска записей, удовлетворяющих условию, снижения затрат на ведение блокировок и соответствующе увеличению скорости работы, обусловленному поиску по индексам, без необходимости физического обращения к записям таблицы . Даже если таблица не имеет индексов, то записи считываются в последовательном порядке, определяемом самим сервером в зависимости от способа их получения, предложенным
оптимизатором запросов и далее на них накладываются блокировки на позиции сканирования так же, как если бы они накладывались на индекс, то есть можно сказать сервер сам строит некий упорядоченный список записей для корректного наложения блокировок.
Чтобы, лучше понять работу блокировок на позиции сканирования, рассмотрим примеры:
Блокировки резервирования вставки
Текущая транзакция удаляет запись из таблицы по значению первичного ключа ID, равного 2:
DELETE FROM Table
WHERE ID = 2;
| Физически запись удаляется с таблицы и индексов, причем в случае включенной опции READ_PAST_DELETED = ‘ON’, другие транзакции будут считать, что записи не существует, а в случае выключенной – существующей, но заблокированной и поэтому ждать окончания транзакции. В итоге, из за физического отсутствия записи в таблице и индексах, другие сессии могли бы вставить свою запись с ID = 2, что привело бы к нарушению уникальности первичного ключа, если бы текущая транзакция бы решила откатить
свое состояние, вызвав ROLLBACK. Так что, в любом случае, с одной стороны, пока текущая транзакция не подтвердит (COMMIT) или откатит изменения (ROLLBACK), другие сессии не имеют право вставить или изменить запись, где значение ID равнялось бы 2. С другой стороны нельзя наложить блокировку на уже несуществующую физически запись. С целью решения этой проблемы, при удалении записи, сервер наложит блокировку на позицию сканирование индекса первичного ключа, установив ее на позицию индекса, после которой располагалась
удаляемая запись, использовав блокировку резервирования вставки. Таким образом, любая сессия, пытающаяся создать в таблице запись с значением ID равным 2, пройдет по веткам индекса, найдет подходящий элемент, после которого необходимо вставить новую запись и наткнется на блокировку резервирования вставки, что переведет ее в режим ожидания до снятия блокировки текущей транзакцией. Если удаление будет подтверждено COMMIT, то другая сессия удачно вставит новую запись, с ID = 2. Если же текущая транзакция сделает
откат посредством ROLLBACK, то другая сессия будет вынуждена прервать транзакцию с ошибкой о недопустимости вставки дублирующих значений для уникального индекса.
Блокировки запрета вставки
Текущая транзакция должна получить все записи за 2006 год по полю Year в режиме уровня изоляции Serializable, что таким образом гарантирует повторное чтение и отсутствие фантомов. На поле Year существует обычный индекс:
SELECT *
FROM Table
WHERE Year = 2006;
| Допустим, пока текущая транзакция получает данные, в этот момент конкурирующая другая транзакция пытается удалить или изменить запись, которая уже была обработана текущей транзакцией (получена). Этого не будет допущено по причине того, что на обрабатываемые записи транзакция устанавливает разделяемые блокировки, которые не дают другим сессиям их изменять до завершения транзакции. Однако такие блокировки не смогут помочь сохранить указанный уровень изоляции для случаев, когда например
одна транзакция обновила запись, у которой значение поля Year было 2005 на 2006 или же вставила новую запись с Year = 2006. В данном случае такой транзакции не будут мешать блокировки на записи, так как она изначально будет манипулировать с записями, на которые наша текущая транзакция не ставила блокировки. Именно для предотвращения этих случаев, текущая транзакция помимо разделяемой блокировки на запись, поставит блокировку запрета вставки на позицию сканирования в индексе на поле Year. Таким образом, другая
транзакция, пытающаяся создать фантома (то есть создать новую запись, подходящую под условие Year=2006), при попытке вставки в индекс на поле Year новой записи, будет остановлена блокировкой запрета вставки и ей придется дожидаться завершения текущей транзакции.
Двухфазный протокол блокировок
Для поддержки обеспечения целостности данных, корректной работы блокировок, различных уровней изоляции и проведения различных согласованных операций над данными множества транзакций, сервер ASA работает в режиме двухфазного протокола блокировок.
Такой протокол блокировок контролирует соблюдение 2 правил:
1. Любая транзакция, перед проведением операции изменения записи обязана повесить на нее блокировку и далее имеет право повесить блокировки на любые другие объекты.
2. После снятия блокировки с записи, транзакция обязана снять все остальные блокировки и не накладывать их вновь.
Соблюдение правил протокола позволяет вывести следующее утверждение:
Если все транзакции соблюдают правила двуфазного протокола блокировок, то значит любая транзакция может работать на сериализуемом уровне изоляции, где работа каждой транзакции считается непрерывной и последовательной так, как будто бы с данными работает только одна она.
Иными словами, если 2 транзакции одновременно изменяют данные таблицы, то с помощью данного протокола всегда будет гарантироваться, что при их работе в таблице не возникнет несогласованных или нарушающих целостность данных.
Рекомендации по управлению и оптимизации блокировок
1. Старайтесь не делать длинными транзакции, с целью уменьшения времени захватов ресурсов, а значит увеличению ожидания к этим ресурсам конкурирующих транзакций.
2. Помните, что для вставок, изменений и удалений записей всегда используется эксклюзивная блокировка, запрещающая как изменение, так и чтение данных записей другими транзакциями.
3. Старайтесь пользоваться подходящим уровнем изоляции для каждой таблицы запроса, снижая его везде, где это возможно и помните, что для разных таблиц запроса можно указать разный уровень изоляции через хинт запроса WITH. Например на таблицы, в которых записи только вставляются, не обязателен уровень изоляции serializable и вполне достаточно уровня repeatable read.
4. Не забывайте, что для более эффективной работы блокировок на таблицу должен существовать уникальный индекс.
5. В случае обработки большей части записи таблицы от существующего не забывайте про возможность блокировки всей таблицы оператором LOCK TABLE, применение которого поставит всего одну блокировку на таблицу, снизит потребление ресурсов и таким образом увеличит скорость выполнения транзакции, где остальным транзакциям будет быстрее подождать снятия блокировки с таблицы, чем ожидать, пока блокирующая транзакция обработает все записи, создавая на них всех позаписные блокировки и потом их все снимет.
6. Для уменьшения времени действия блокировок транзакции с сериализуемым уровнем изоляции, можно воспользоваться нетранзакционными временными таблицами, в которые можно перенести записи или промежуточно рассчитанные результаты с таблицы с нужным уровне изоляции в временную таблицу, снять блокировки, завершив транзакцию по COMMIT и далее работать с полученным во временных таблицах снимком данных, без обращения к самим таблицам и наложением их блокировок, где такой способ работы можно приблизительно назвать
аналогом уровня изоляции snapshot.
7. Старайтесь максимально ограничивать необходимыми условиями для сериализуемого уровня изоляции так, чтобы они охватывали только подходящие под условия записи, где в условиях выборки желательно условие, поля которого входят в один из уникальных индексов таблицы, что позволит серверу наложить блокировки на позицию сканирования, без дополнительного блокирования располагающихся рядом записей.
8. Встраивайте в таблицы timestamp поле с DEFAUL TIMESTAMP, которое будет автоматически изменять время при добавлении и изменении записей и таким образом можно будет дополнительно наложить на запрос с требуемым сериализуемым уровнем изоляции условие WHERE Timestamp < Now(), что гарантирует обработку только подтвержденных на момент выполнения запроса транзакций и таким образом позволит вместо serializable указать более низкий уровень изоляции repeatable read.
Материалы данной рассылки являются собственностью ее автора. При использовании информации из рассылки, ссылка на автора обязательна.
|
Дата публикации: Monday 27 March 2006 16:26:52 Материал прочитан: 17189 раз(а) [ Назад ] |
|
|
|
|
|
|