Конкурентный доступ в SQL Server 2008 (часть 3)

добавлено: 10 янв 11
понравилось:0
просмотров: 4549
комментов: 1

теги:

Автор: Николай Байбородин

Intro

В прошлой статье мы остановились на уровнях изоляции, используемых в Database Engine. Кратко напомню основные моменты.

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

  • READ UNCOMMITTED;
  • READ COMMITTED;
  • REPEATABLE READ;
  • SERIALIZABLE;
  • SNAPSHOT.

Уровни изоляции READ UNCOMMITTED, REPEATABLE READ и SERIALIZABLE доступны только в пессимистической модели конкурентного доступа, в то время как уровень SNAPSHOT доступен только в оптимистической модели конкурентного доступа. Уровень изоляции READ COMMITTED доступен в обеих моделях.


READ UNCOMMITED

Уровень изоляции READ UNCOMMITTED предоставляет наипростейшую форму изоляции транзакций, потому что он вообще не изолирует операции чтения других транзакций. Когда транзакций этого уровня изоляции отыскивает строку, она не запрашивает блокировки и не признает никаких существующих блокировок. Данные, которые читаются этой транзакцией, могут быть несогласованными. В этом случае транзакция читает данные, которые были изменены какой-нибудь другой активной транзакцией. Если для второй транзакции позже будет выполнен откат, то значит, что первая транзакция прочла данные, которые никогда реально не существовали.

Из четырех проблем одновременного доступа к данным, рассмотренных ранее, READ UNCOMMITTED допускает грязное чтение, неповторяемое чтение и фантомные записи. Уровень изоляции READ UNCOMMITED обычно является весьма нежелательным и должен быть использован, только когда не требуется точности чтения данных или когда данные изменяются редко.

READ COMMITED

Уровень изоляции READ COMMITTED имеет две формы. Первая форма применяется для пессимистической модели модели конкурентного доступа, а вторая форма – для оптимистической модели конкурентного доступа.

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

Разделяемые блокировки, устанавливаемые на читаемые данные транзакцией этого уровня изоляции, немедленно отменяются сразу после того, как данные будут обработаны. Обычно все блокировки отменяются после завершения транзакции. По этой причине доступ к одновременно используемым данным улучшен, однако неповторяемое чтение и фантомные записи все еще возможны. Уровень изоляции READ COMMITED является уровнем изоляции по умолчанию для Database Engine.

REPEATABLE READ

В отличие от уровня изоляции READ COMMITTED уровень изоляции REPEATABLE READ устанавливает разделяемую блокировку на все данные, которые читаются, и сохраняет эту блокировку, пока транзакция не будет подтверждена, или отменена. Следовательно, в этом случае выполнение запроса несколько раз внутри транзакции всегда вернет один и тот же результат. Недостатком такого уровня изоляции является то, что одновременный доступ ухудшается, потому что временной интервал, в течение которого другие транзакции не могут обновлять те же данные, значительно больше, чем в случае READ COMMITTED.

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

SERIALIZABLE

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

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

Каждый из описанных ранее уровней изоляции снижает степень параллельности менее чем самый последний. Следовательно, уровень изоляции READ UNCOMMITTED меньше всего уменьшает степень параллельности. С другой стороны, он также менее всего изолирует транзакцию от конкурентных транзакций. Уровень SERIALIZABLE наиболее сильно снижает степень параллельности, однако гарантирует полную изоляцию от всех других конкурентных транзакций.

Установка и редактирование уровней изоляции

Можно установить уровень изоляции, используя следующее:

  • предложение TRANSACTION ISOLATION LEVEL оператора SET
  • подсказки уровня изоляции

Предложение TRANSACTION ISOLATION LEVEL в операторе SET предоставляет пять постоянных значений, которые имеют те же имена и те же значения, что и только что описанные стандартные уровни изоляции. Предложение FROM оператора SELECT поддерживает несколько подсказок для уровней изоляции:

  • READUNCOMMITTED;
  • READCOMMITTED
  • REPEATABLEREAD
  • SERIALIZABLE

Эти подсказки соответствуют уровням изоляции с теми же самыми именами (но при наличии пробелов в именах). Задание уровней изоляции в предложении FROM оператора SELECT перекрывает текущее значение, установленное оператором SET TRANSACTION ISOLATION LEVEL.

Оператор DBCC USEROPTIONS возвращает, помимо другой информации, информацию об уровне изоляции.

Контроль версий строк

Database Engine поддерживает механизм оптимистического управления параллельной работой, основанный на контроле версий строк. Когда данные изменяются с использованием контроля версий строк, то для всех изменений данных в базе данных поддерживаются логические копии. Каждый раз, когда изменяется строка, SQL Server сохраняет ее образ до изменения подтвержденной строки в системной базе данных tempdb. Каждая версия отмечается последовательным номером транзакции (XSN) той транзакции, которая выполнила это изменение. XSN используется для уникальной идентификации транзакций. Самая последняя версия строки всегда сохраняется в базе данных и соединяется через список связей с соответствующей версией, сохраненной в tempdb. Старая версия строки в базе данных tempdb может содержать указатели на другую, еще более старую версию этой строки. Каждая версия строки сохраняется в базе данных tempdb до тех пор, пока существую операции, которым она может потребоваться.

Контроль версий строк изолирует транзакции от эффектов модификаций, выполненных другими транзакциями, без необходимости запроса разделяемых блокировок для строк, которые были прочитаны. Значительное сокращение общего количества блокировок для этого уровня изоляции сильно увеличивает доступность данных. Однако исключительные блокировки все еще необходимы: транзакции, использующие оптимистический уровень изоляции, называемый SNAPSHOT, требует блокировок, когда они модифицируют строки.

Контроль версий строк, помимо прочего, используется для:

  • поддержки уровня изоляции READ COMMITED SNAPSHOT;
  • поддержки уровня изоляции SNAPSHOT;
  • создания в триггерах таблиц inserted и deleted.

Уровень изоляции READ COMMITED SNAPSHOT

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

Основное преимущество уровня изоляции READ COMMITED вы том, что операции чтения не блокируют обновления, а обновления не блокируют операции чтения. С другой стороны, обновления блокируют другие обновления, потому что устанавливается исключительная блокировка до начала выполнения операци обновления.

Для задания уровня изоляции READ COMMITED SNAPSHOT вы используете предложение SET оператора ALTER DATABASE. После активации в дальнейшем не требуются никакие изменения. Любая транзакция, заданная с уровнем изоляции READ COMMITED, не будет выполняться под READ COMMITED SNAPSHOT.

Уровень изоляции SNAPSHOT

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

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

Реализация уровня изоляции SNAPSHOT является процессом, состоящим из двух шагов. Во-первых, нужно установить опцию для базы данных ALLOW_SNAPSHOT_ISOLATION. Во-вторых, для каждой сессии, которая будет использовать этот уровень изоляции, нужно задать для оператора SET TRANSACTION ISOLATION LEVEL значение SNAPSHOT. Когда установлены эти опции, будут создаваться версии для всех строк, изменяемых в базе данных.

READ COMMITED SNAPSHOT в сравнении с SNAPSHOT

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

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


Комментарии


  • я бы вот так написал по SERIALIZABLE:
    Этот уровень изоляции также не допускает добавления новых строк другими транзакциями (в выбранный диапазон данных), пока первая транзакция не будет подтверждена или отменена.
    А то может сложится впечатление что он не дает добавить записи во всю таблицу.



Необходимо войти на сайт, чтобы оставлять комментарии