Изменения IsolationLevel SQL Server по умолчанию - PullRequest
4 голосов
/ 26 августа 2009

у нас есть клиент, у которого возникли проблемы с блокировкой нашего приложения базы данных. Мы попросили их запустить трассировку «Отчет о заблокированных процессах», и трасса, которую они нам дали, показывает блокировку, возникающую между операциями SELECT и UPDATE. Файлы трассировки показывают следующее:

  • Один и тот же запрос SELECT выполняется на разных уровнях изоляции. Одна трассировка показывает Serializable IsolationLevel, в то время как более поздняя трассировка показывает RepeatableRead IsolationLevel. Мы не используем явную транзакцию при выполнении запроса.
  • Запрос UPDATE выполняется с уровнем изоляции RepeatableRead, но блокируется запросом SELECT. Это ожидается, поскольку наши обновления заключены в явную транзакцию с IsolationLevel из RepeatableRead.

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

Есть идеи?

Заранее спасибо,

Graham

Ответы [ 2 ]

6 голосов
/ 26 августа 2009

В вашем сценарии я бы порекомендовал явно установить уровень изоляции для моментального снимка - это предотвратит чтение, препятствующее записи (вставкам и обновлениям), предотвращая блокировки, но эти чтения все равно будут "хорошими" чтениями (т.е. не грязные данные - это не то же самое, что NOLOCK)

Обычно я нахожу, что, когда у меня возникают проблемы с блокировкой моих запросов, я вручную контролирую примененную блокировку. например я бы делал обновления с блокировками на уровне строк, чтобы избежать блокировки на уровне страниц / таблиц, и устанавливал мои чтения на readpast (принимая, что я могу пропустить некоторые данные, в некоторых сценариях, которые могут быть в порядке) ссылка | редактировать | удалить | флаг

РЕДАКТИРОВАТЬ - Объединение всех комментариев в ответ

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

В: Спасибо за полезную информацию о снижении уровней изоляции. Можете ли вы представить себе причину, по которой он будет использовать Serializable IsolationLevel в первую очередь, учитывая, что мы не используем явную транзакцию для SELECT - мы понимали, что неявная транзакция будет использовать ReadCommitted?

A: По умолчанию SQL Server будет использовать Read Commmited, если это ваш уровень изоляции по умолчанию, НО, если вы не дополнительно указываете стратегию блокировки в своем запросе, вы в основном говорите серверу sql «делай то, что считаешь лучшим, но я предпочитаю читать по коммиту ». Поскольку SQL Server свободен в выборе, он делает это для оптимизации запроса. (Алгоритм оптимизации в SQL Server очень сложен, и я не полностью понимаю его сам). Неявное выполнение транзакции не влияет на уровень изоляции, который использует сервер sql.

В: Последнее, кажется ли разумным, что SQL Server повысит уровень изоляции (и, вероятно, количество требуемых блокировок) для оптимизации запроса? Мне также интересно, повлияет ли на это повторное использование соединения в пуле, если оно унаследует последний использованный уровень изоляции?

A: Sql-сервер сделает это как часть процесса, называемого «Lock Escalation». От http://support.microsoft.com/kb/323630, я цитирую: «Microsoft SQL Server динамически определяет, когда выполнять эскалацию блокировок. При принятии этого решения SQL Server учитывает количество блокировок, удерживаемых при определенном сканировании, количество блокировок, которые удерживается всей транзакцией и памятью, которая используется для блокировок в системе в целом. Как правило, поведение SQL Server по умолчанию приводит к эскалации блокировок, возникающей только в тех точках, где это может повысить производительность или когда необходимо уменьшить чрезмерную блокировку системы памяти до более приемлемого уровня. Однако некоторые приложения или конструкции запросов могут вызывать эскалацию блокировки в тот момент, когда это нежелательно, и эскалация блокировки таблицы может блокировать других пользователей ".

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

3 голосов
/ 14 февраля 2012

Дополнительная информация о том, почему SQL будет брать больше блокировок путем эскалации: это неверно, эскалация уменьшает (не увеличивает) количество требуемых блокировок. Блокировка таблицы - это единая блокировка против всех блокировок страниц или строк, необходимых для того же уровня на более низком уровне. Эскалация блокировки всегда выполняется по одной причине: эффективнее использовать блокировку более высокого уровня, чем блокировать все объекты более низкого уровня

Например, возможно, нет доступного индекса для эффективной блокировки. То есть если вы берете счетчик с помощью UPDLOCK для всех записей с полем 2010 года в поле, и в этом поле даты нет индекса, это потребует блокировки строк для каждой записи в 2010 году, что неэффективно, если попадет много записей и блокировка страницы также не поможет, так как они предположительно распределяются случайным образом по страницам, поэтому SQL принимает блокировку таблицы. Более того, SQL ДОЛЖЕН также блокировать изменение других записей на 2010 год, пока удерживается UPDLOCK, и без индекса в этом поле для блокировки диапазона, SQL не имеет выбора, кроме как использовать блокировку таблицы, чтобы этого не происходило , Этот последний момент часто упускается новичками в оптимизации: осознание того, что SQL также должен «защищать» целостность запросов, уже выполненных в транзакции.

...