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

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

теги:

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

Гранулярность блокировок

Гранулярность блокировок указывает, какой блокируется ресурс в одной попытке блокирования. Database Engine может блокировать такие ресурсы, как:

  • строка
  • страница
  • индексный ключ или диапазон индексных ключей
  • таблица
  • экстент
  • сама база данных

Прежде всего, следует учесть, что SQL Server самостоятельно выбирает гранулярность блокировки.

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

Если таблица является кластеризованной, то страницы данных хранятся на уровне листьев (кластеризованной) индексной структуры и поэтому блокируются именно они вместе с индексными ключами, а не строки.

Блокировка также выполняется для участков диска, называемых экстентами,  которые имеют размер 64 Кбайт. Блокировка экстента устанавливается автоматически, когда растет таблица (или индекс) и требуется дополнительное дисковое пространство.

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

Укрупнение блокировок

Если установлено много блокировок с одной и той же гранулярностью в процессе выполнения транзакции, Database Engine автоматически преобразует эти блокировки в блокировку таблицы. Это процесс конвертирования множества блокировок уровней страницы, строки или индекса в блокировку уровня таблицы называется укрупнением блокировки. Начало укрупнения определяется системой динамически и не требует конфигурирования. В настоящий момент значением границы укрупнения является 5000 блокировок).

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

SET {  LOCK_ESCALATION = { TABLE | AUTO | DISABLE } }

Опция TABLE является значением по умолчанию; она задает, что укрупнение блокировки будет устанавливаться на уровне грануляции таблицы. Это поведение точно такое же, как и в SQL Server 2005. Опция AUTO позволяет Database Engine выбирать гранулярность укрупнения блокировки, которая будет лучше подходить для таблиц схемы. Наконец, опция DISABLE позволяет отменить в большинстве случаев укрупнение блокировки. Это тот же самый случай, когда Database Engine должен выбирать блокировку таблицы для защиты целостности данных.

Влияние блокировок

Подсказки блокировки

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

Все подсказки блокировки записываются как часть предложения FROM в операторе SELECT. При этом можно использовать следующие подсказки блокировки:

  • UPDLOCK устанавливает блокировку обновлений для каждой строки таблицы в процессе операций чтения. Все блокировки обновлений сохраняются до завершения транзакции;
  • TABLOCK (TABLOCKX) устанавливает разделяемую (или исключительную) блокировку таблицы для всей таблицы. Все блокировки сохраняются до завершения транзакции;
  • ROWLOCK заменяет существующую разделяемую блокировку таблицы на разделяемые блокировки строк для каждой указанной строки таблицы;
  • PAGLOCK заменяет разделяемую блокировку таблицы на разделяемые блокировки страниц для каждой страницы, содержащей указанные строки;
  • NOLOCK – синоним для READUNCOMMITTED;
  • HOLDLOCK – синоним для REPEATABLEREAD;
  • XLOCK указывает, что исключительные блокировки будут установлены и сохранены до завершения транзакции. Если XLOCK указано вместе с ROWLOCK, PAGELOCK или TABLOCK, то применяется исключительная блокировка для соответствующего уровня гранулярности;
  • READPAST указывает, что Database Engine не читает строки, заблокированные другими транзакциями.

Все эти опции могут быть объединены в произвольном порядке, если такая комбинация имеет смысл. Например, комбинация TABLOCK и PAGELOCK бессмысленна, потому что эти опции применяются к различным ресурсам.

Опция LOCK_TIMEOUT

Опция LOCK_TIMEOUT оператора SET может быть использована для задания количества миллисекунд, в течение которых транзакция будет ожидать снятия блокировки. Значение –1 (значение по умолчанию) указывает на отсутствие времени ожидания, иными словами, транзакция вообще не будет ожидать. Подсказка блокировки READPAST предоставляет альтернативу этой опции SET.

Отображение информации блокировки

Информация о блокировке может быть отображена либо при использовании системной процедуры sp_lock, либо динамически управляемым представлением, называемым sys.dm_tran_locks. Поскольку sp_lock является нерекомендуемым средством, и не будет поддерживаться в следующих версиях SQL Server, мы подробней рассмотрим только представление sys.dm_tran_locks.

Представление sys.dm_tran_locks возвращает информацию о текущей активной блокировке менеджера ресурсов. Каждая строка отображает активный в настоящий момент запрос на блокировку, которая была предоставлена или предоставление которой ожидается. Столбцы этого представления соответствуют двум группам: ресурсам и запросам. Группа ресурсов описывает ресурсы, которым предоставлена блокировка на основании запросов, а группа запросов описывает запросы на блокировку. Наиболее важными столбцами этого представления являются следующие:

  • resource_type указывает тип ресурса
  • resource_database_id задает идентификатор базы данных, в которой находится этот ресурс
  • request_mode задает режим запроса
  • request_status задает текущее состояние запроса

Взаимная блокировка

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

SQL Server обрабатывает взаимную блокировку, выбрав одну из транзакций в качестве “жертвы” (victim) – фактически ту, которая закрыла цикл в запросах на блокировку), и выполнив ее откат. Другая транзакция после этого будет выполнена. Разработчик может обрабатывать взаимные блокировки, используя условный оператор, который проверяет номер возвращаемой ошибки (1205), а затем заново выполняя отмененную транзакцию.

Кроме того, можно повлиять на то, какая транзакция будет выбрана в качестве жертвы, используя опцию DEADLOCK_PRIORITY в операторе SET. Существует 21 уровень приоритетов: значения от –10 до 10. Значение LOW соответствует –5, значение NORMAL (значение по умолчанию) соответствует 0, а HIGH соответствует 5. “Жертва” сессии выбирается в соответствии с установленными в сессии приоритетами взаимных блокировок.

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

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

Проблемы конкурентного доступа

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

  • потеря обновлений
  • грязное чтение
  • неповторяемое чтение
  • фантомные записи

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

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

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

Database Engine и уровни изоляции

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

  • READ UNCOMMITED;
  • READ COMMITED;
  • REPEATABLE READ;
  • SERIALIZABLE;
  • SNAPSHOT.

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

На этом мы остановимся, и более подробно об уровнях изоляции поговорим с следующей статье.


Комментарии




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