Главная » Microsoft SQL Server, Базы данных » Целостность транзакций

0

Изучение влияния транзакций на производительность не может обойтись без рассмотрения вопроса о целостности транзакций, затрагивающей их качество. Существуют три типа проблем, которые нарушают целостность транзакций: “грязное” чтение, неповторяющееся чтение и призрачные строки. Решение этих трех проблем включает в себя выбор одного из уровней изоляции транзакций.

Свойства АСЮ

Качество базы данных измеряется соблюдением ее транзакций требованиям свойств АСЮ (т.е. атомарности, целостности, изолированности и живучести). Архитектура большинства современных реляционных баз данных базируется на этих свойствах. Понимание этих свойств является предпосылкой понимания SQL Server.

Атомарность

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

Целостность

Транзакция должна не нарушать целостность базы данных. Это значит, что транзакция начинается в целостном состоянии базы данных и должна вернуть ее в целостное состояние по завершении, независимо от результата операций. С точки зрения АСЮ целостность означает то, что все строки и значения должны соответствовать моделируемой реальности, а все ограничения — соблюдаться. Если все заказы были записаны на диск, а его строки остались не записанными, то целостность между таблицами Order и OrderDetails будет нарушена.

Изоляция

Каждая транзакция должна быть изолирована, т.е. отделена от эффекта других транзакций. Независимо от действий, осуществляемых другими транзакциями, транзакция должна быть способна продолжать работать именно с тем же набором данных, с которым начала. Изоляция является своеобразным барьером между двумя транзакциями. Доказательством существования изоляции является способность воспроизведения последовательного набора транзакций на исходном множестве данных и постоянного получения одного и того же результата.

Для примера предположим, что некий Саша обновил 100 строк. В то время как транзакция Саши выполнялась, Таня прочитала одну из строк, над которыми в это время работал Саша. Если выполняется чтение, то эти транзакции нельзя назвать полностью изолированными друг от друга. Это свойство менее критично в базах данных, доступных только для чтения, а также в базах данных, доступных только узкому кругу лиц.

Живучесть

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

Сбои транзакций

Puc. 51.2. Открытие нескольких окон редактора запросов является лучшим способом экспериментирования с транзакциями. В данном примере транзакция в левом окне обновляет псевдоним на “Transaction Fault”, но не подтверждает изменения. Транзакция в правом окне извлекает значение столбца псевдонима и читает в нем “Transaction Fault”

Будет получен следующий результат:

NickName

Transaction Fault

Несмотря на то что транзакция 1 не завершила свою работу с набором данных, транзакция 2 смогла прочитать строку “Transaction Fault5’. Таким образом, целостность транзакции была нарушена.

Для завершения примера в первом окне следует подтвердить транзакцию:

– Транзакция 1 COMMIT TRANSACTION

Неповторяющееся чтение

Неповторяющееся чтение аналогично “грязному” чтению, однако оно возникает, когда транзакция может видеть подтвержденные обновления другой транзакции (рис. 51.3). Истинная изоляция предполагает, что одна транзакция никогда не влияет на другую. Если изоляция полная, то транзакция не может увидеть внешние изменения, происходящие с данными во время ее работы. Чтение некоторой строки в транзакции должно всегда приводить к одним и тем же результатам. Если два последовательных чтения одной и той же строки дают разные результаты, то такой тип ошибки транзакции называют неповторяющимся чтением.

В следующем примере приведены две конкурентные транзакции. Транзакция 1 открывается и выполняет чтение данных. Изначальный псевдоним заказчика с кодом 1 является "Transaction Fault".

– Транзакция 1

SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRANSACTION USE CHA2 SELECT NickName FROM Customer WHERE CustomerlD = 1;

Будет получен следующий результат:

Nickname

Transaction Fault

В то время как первая транзакция остается открытой, вторая изменяет значение поля псевдонима на "Non-Repeatable Read" и подтверждает изменение:

– Транзакция 2 USE СНА2

BEGIN TRANSACTION UPDATE Customer SET Nickname = ‘Non-Repeatable Read1 WHERE CustomerlD = 1;

COMMIT TRANSACTION;

После обновления псевдонима транзакцией 2 транзакция 1 извлекает ту же строку и пытается получить тот же псевдоним. Если она видит обновления, выполненные транзакцией 2, имеет место ошибка неповторяющегося чтения:

– Transaction 2 USE СНА2 SELECT Nickname FROM Customer WHERE CustomerlD = 1;

Будет получен следующий результат:.

Nickname

Non-Repeatable Read

Мы видим, что транзакция 2 столкнулась с ошибкой неповторяющегося чтения. На вторую инструкцию SELECT транзакции 1 повлияла инструкция UPDATE второй. Для завершения работы подтвердим транзакцию 1:

COMMIT TRANSACTION

Призрачные строки

– Transaction 2 BEGIN TRANSACTION USE CHA2

SELECT CustomerlD, LastName

FROM Customer

WHERE NickName = ‘Missy';

Наименее серьезной ошибкой транзакций являются призрачные строки. Подобно неповторяющемуся чтению, призрачные строки возникают, когда обновления, выполненные одной транзакцией, приводят к изменению набора данных, возвращаемого инструкцией SELECT другой транзакции (рис. 51.4).

Рис. 51.4. Когда состав строк, возвращаемый инструкцией SELECT, изменяется в результате работы другой транзакции, этот эффект называют призрачными строками

В следующем примере транзакция 1 изменяет значение поля псевдонима на 1 Missy’, в то время как транзакция 2 отбирает строки со значениями псевдонимов:

Результат следующий: CustomerlD LastName

2          Anderson

– Transaction 1 USE CHA2

BEGIN TRANSACTION UPDATE Customer

SET Nickname = ‘Missy’ WHERE CustomerlD = 1; COMMIT TRANSACTION;

Если изоляция между транзакциями полная, то результирующий набор транзакции 2 будет содержать тот же набор строк, что и в предыдущем случае:

– Transaction 2 USE СНА2

SELECT CustomerlD, LastName FROM Customer WHERE Nickname = ‘Missy';

Результат следующий:

CustomerlD LastName

1            Adams

2            Anderson

Строка с фамилией Adams является призрачной, так как она появилась только во втором результирующем наборе данных в результате работы транзакции 2.

Завершим транзакцию 2 инструкцией COMMIT TRANSACTION.

Из всех ошибок транзакций “грязное” чтение является самым опасным, неповторяющееся чтение стоит на втором месте, а призрачные строки можно считать наименее опасными.

Уровни изоляции

Базы данных справляются с тремя описанными выше ошибками транзакций, изолируя транзакции друг от друга. Уровни изоляции можно сравнить с высотой ограды между транзакциями — они позволяют управлять тем, какие ошибки считаются допустимыми. В спецификации ANSI SQL-92 определены четыре уровня изоляции (табл. 51.1).

Таблица 51.1. Уровни изоляции ANSI-92

Уровень

изоляции

“Грязное”

чтение

Неповторяющееся чтение

Призрачные

строки

Блокировка

записи

Возможность видеть неподтвержденные изменения другой транзакции

Способность видеть подтвержденные изменения другой транзакции

Отбор предложением where дополнительных строк, внесенных другой транзакцией

Первая операция записи блокируется второй

Read Uncommited

(наименее жесткий)

Допустимо

Допустимо

Допустимо

Нет

Read Commited

(принят в SQL Server по умолчанию)

Запрещено

Допустимо

Допустимо

Нет

Repeatable Read

Запрещено

Запрещено

Допустимо

Нет

Serializable

(наиболее жесткий)

Запрещено

Запрещено

Запрещено

Нет

Snapshot

Запрещено

Запрещено

Допустимо

Да

Read Commited Snapshot

Запрещено

Допустимо

Допустимо

Да

SQL Server реализует уровни изоляции с помощью блокировок. Так как блокировки влияют на производительность, то существует компромисс между уровнями изоляции и производительностью. Принятый в SQL Server уровень изоляции Read Commited является своеобразным балансом, подходящим большинству проектов OLTP.

Уровень изоляции можно устанавливать для подключения и пакета. В качестве альтернативы можно устанавливать уровень изоляции для отдельной инструкции DML, используя параметры блокировки таблицы в предложении FROM.

Уровень 1 — Read Uncommited

Этот, наименее строгий, уровень изоляции не предотвращает никаких ошибок транзакций. Он подобен отсутствию забора, так как не обеспечивает никакой изоляции между транзакциями. Установка этого уровня изоляции является аналогом указания серверу баз данных не выполнять блокировок. Этот режим лучше всего подходит для отчетов и приложений чтения данных. Так как этот режим имеет достаточно блокировок, чтобы предотвратить повреждение данных, но недостаточно, чтобы отслеживать конфликты строк, он не очень подходит базам данных, в которых регулярно выполняется обновление данных.

Уровень 2 — Read Commited

Этот уровень изоляции позволяет избежать самой опасной ошибки транзакций, но не нагружает систему излишними блокировками. По этой причине уровень изоляции Read Commited принят в SQL Server по умолчанию и является идеальным выбором для большинства проектов OLTR

Уровень 3 — Repeatable Read

Предотвращая “грязное” и неповторяющееся чтение, этот уровень обеспечивает повышенную изоляцию транзакций без чрезмерных блокировок, характерных для уровня изоляции Serializable.

Уровень 4 — Serializable

Это наиболее строгий уровень изоляции, позволяющий избежать всех ошибок транзакций. Он больше всего подходит для баз данных, в которых абсолютная целостность транзакций важнее производительности. Обычно этот уровень изоляции используется в банковских, бухгалтерских базах, а также в очень загруженных приложениях продаж.

Использование уровня изоляции Serializable равноценно установке и удержанию блокировки на всем протяжении транзакции. Несмотря на то что этот уровень обеспечивает абсолютную изоляцию транзакций, он способен привести к серьезному снижению производительности.

Выйдя за пределы стандарта ANSI, разработчики SQL Server добавили еще Новикка 4 один УР°вень изоляции— Snapshot. Этот уровень создает копию обновляемых 2005 G  данных в собственном физическом пространстве, которая полностью изолиро

вана от других транзакций.

Уровень ИЗОЛЯЦИИ Snapshot

Этот уровень реализует оптимистическую блокировку на уровне базы данных. Как правило, конфликт конкуренции происходит между процессами чтения и записи. Это ни в коей мере не относится к изоляции Snapshot. В данном случае создается мгновенный снимок данных для обновления, и во время этого обновления операции чтения продолжают работать с исходными данными. Когда обновление будет подтверждено, измененная копия будет записана поверх исходных данных.

Изоляция Snapshot позволяет предотвратить конфликт между процессами чтения и записи, но, к сожалению, не в полной мере. Если второй процесс записи попытается обновить ресурс, который в данный момент уже обновляется, второй ресурс будет заблокирован.

Уровень изоляции Snapshot использует версионность строк, записывая их ко- . йа заметку пии во временную базу данных TempDB, что создает невероятную ее загрузку.

Если вы используете изоляцию Snapshot, то лучше разместить журнал транзакций и данные базы TempDB в отдельной дисковой подсистеме.

Уровень изоляции Read Commited Snapshot

Этот вариант уровня изоляции Snapshot подобен Read Commited, но устраняет конфликт между процессами чтения и записи.

Источник: Нильсен, Пол. Microsoft SQL Server 2005. Библия пользователя. : Пер. с англ. — М. : ООО “И.Д. Вильямс”, 2008. — 1232 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии