Лекции и практики (1). Курс лекций и материалы для практических занятий
Скачать 1.01 Mb.
|
Лекция 8. Уровни изоляции транзакцийСтандарт ANSI/ISO для SQL устанавливает различные уровни изоляции для операций, выполняемых над БД, которые работают в многопользователь- ском режиме. Уровень изоляции определяет, может ли читающая транзакция считывать ("видеть") результаты работы других одновременно выполняемых завершённых и/или незавершённых пишущих транзакций (табл. 5.1). Использо- вание уровней изоляции обеспечивает предсказуемость работы приложений. Таблица 5.1. Уровни изоляции по стандарту ANSI / ISO
По умолчанию в СУБД обычно установлен уровень Read Commited. Уровень изоляции позволяет транзакциям в большей или меньшей степе- ни влиять друг на друга: при повышении уровня изоляции повышается согласо- ванность данных, но снижается степень параллельности работы и, следователь- но, производительность системы. Подробнее об "узких" местах уровней изоля- ции можно прочитать в [9]. Наиболее распространённый механизм разграничения пишущих транзак- ций – использование блокировок. БлокировкиБлокировка – это временное ограничение доступа к данным, участвующим в транзакции, со стороны других транзакций. Блокировка относится к пессимистическим алгоритмам, т.к. предполага- ется, что существует высокая вероятность одновременного обращения несколь- ких пишущих транзакций к одним и тем же данным. Различают следующие ти- пы блокировок: по степени доступности данных: разделяемые и исключающие; по множеству блокируемых данных: строчные, страничные, табличные; по способу установки: автоматические и явные. Строчные, страничные и табличные блокировки накладываются соот- ветственно на строку таблицы, страницу (блок) памяти и на всю таблицу цели- ком. Табличная блокировка приводит к неоправданным задержкам исполнения запросов и сводит на нет параллельность работы. Другие виды блокировки уве- личивают параллелизм работы, но требуют накладных расходов на поддержа- ние блокировок: наложение и снятие блокировок требует времени, а для хране- ния информации о наложенной блокировке нужна дополнительная память (для каждой записи или блока данных). Разделяемая блокировка, установленная на определённый ресурс, предоставляет транзакциям право коллективного доступа к этому ресурсу. Обычно этот вид блокировок используется для того, чтобы запретить другим транзакциям производить необратимые изменения. Например, если на таблицу целиком наложена разделяемая блокировка, то ни одна транзакция не сможет удалить эту таблицу или изменить её структуру до тех пор, пока эта блокировка не будет снята. (При выполнении запросов на чтение обычно накладывается разделяемая блокировка на таблицу.) Исключающая блокировка предоставляет право на монопольный до- ступ к ресурсу. Исключающая (монопольная) блокировка таблицы накладыва- ется, например, в случае выполнения операции ALTER TABLE, т.е. изменения структуры таблицы. На отдельные записи (блоки) монопольная блокировка накладывается тогда, когда эти записи (блоки) подвергаются модификации. Блокировка может быть автоматической и явной. Если запускается но- вая транзакция, СУБД сначала проверяет, не заблокирована ли другой транзак- цией строка, требуемая этой транзакции: если нет, то строка автоматически блокируется и выполняется операция над данными; если строка заблокирована, транзакция ожидает снятия блокировки. Явная блокировка, накладываемая ко- мандой LOCK TABLE языка SQL, обычно используется тогда, когда транзакция затрагивает существенную часть отношения. Это позволяет не тратить время на построчную блокировку таблицы. Кроме того, при большом количестве по- строчных блокировок транзакция может не завершиться (из-за возникновения взаимных блокировок, например), и тогда все сделанные изменения придётся откатить, что снизит производительность системы. Явную блокировку также можно наложить с помощью ключевых слов for update, например: SELECT * FROM <имя_таблицы> WHERE <условие> for update; При этом блокировка будет накладываться на те записи, которые удовлетворя- ют <условию>. И явные, и неявные блокировки снимаются при завершении транзакции. Блокировки могут стать причиной бесконечного ожидания и тупиковых ситуаций. Бесконечное ожидание возможно в том случае, если не соблюдается очерёдность обслуживания транзакций и транзакция, поступившая раньше дру- гих, всё время отодвигается в конец очереди. Решение этой проблемы основы- вается на выполнении правила FIFO (first input – first output): "первый пришел – первый ушел". Тупиковые ситуации (deadlocks) возникают при взаимных блокировках транзакций, которые выполняются на пересекающихся множествах данных (рис. 6.3). Здесь приведён пример взаимной блокировки трех транзакций Ti на отношениях Rj. Транзакция T1 заблокировала данные B1 в отношении R1 и ждёт освобождения данных B2 в отношении R2, которые заблокированы транзакцией T2, ожидающей освобождения данных B3 в отношении R3, заблокированных транзакцией T3, которая не может продолжить выполнение из-за транзакции T1. Если не предпринимать никаких дополнительных действий, то эти транзакции никогда не завершатся, т.к. они вечно будут ждать друг друга.
Рис. 6.3. Взаимная блокировка трех транзакций Существует много стратегий разрешения проблемы взаимной блокиров- ки, в частности: Транзакция запрашивает сразу все требуемые блокировки. Такой метод снижает степень параллелизма в работе системы. Также он не может приме- няться в тех случаях, когда заранее неизвестно, какие данные потребуются, например, если выборка данных из одной таблицы осуществляется на осно- вании данных из другой таблицы, которые выбираются в том же запросе. СУБД отслеживает возникающие тупики и отменяет одну из транзакций с последующим рестартом через случайный промежуток времени. Этот метод требует дополнительных накладных расходов. Вводится таймаут (time-out) – максимальное время, в течение которого транзакция может находиться в состоянии ожидания. Если транзакция нахо- дится в состоянии ожидания дольше таймаута, считается, что она находится в состоянии тупика, и СУБД инициирует её откат с последующим рестартом через случайный промежуток времени. |