SQL Server 2000 тупик - PullRequest
       8

SQL Server 2000 тупик

1 голос
/ 02 июня 2009

В производственной базе данных SQL Server 2000 возникают очень неприятные тупиковые ситуации.

Основные настройки следующие:

  • SQL Server 2000 Enterprise Edition.
  • Сервер написан на C ++ с использованием базы данных ATL OLE.
  • Все объекты базы данных доступны через хранимые процедуры.
  • Все хранимые процедуры UPDATE / INSERT заключают свои внутренние операции в блок BEGIN TRANS ... COMMIT TRANS.

Я собрал некоторые начальные трассировки с помощью SQL Profiler после нескольких статей в Интернете, таких как эта ( игнорируйте, что это относится к инструментам SQL Server 2005, применяются те же принципы ). Судя по трассировкам, между двумя запросами UPDATE возникает тупик.

Мы приняли некоторые меры, которые могли бы снизить вероятность возникновения проблемы:

  • ВЫБРАТЬ С (NOLOCK) . Мы изменили все запросы SELECT в хранимых процедурах, чтобы использовать WITH (NOLOCK). Мы понимаем последствия грязного чтения, но запрашиваемые данные не так важны, так как мы выполняем много автоматических обновлений и в нормальных условиях пользовательский интерфейс будет иметь правильные значения.
  • ЧИТАТЬ НЕОГРАНИЧЕННЫЙ . Мы изменили уровень изоляции транзакции в коде сервера, чтобы он стал ЧИТАТЬ НЕКОММИТИРОВАННЫМ.
  • Сокращенный объем транзакции . Мы сократили время удержания транзакции, чтобы минимизировать вероятность возникновения тупика базы данных.

Мы также подвергаем сомнению тот факт, что у нас есть транзакция внутри большинства хранимых процедур (блок BEGIN TRANS ... COMMIT TRANS). В этой ситуации я предполагаю, что уровень изоляции транзакции SERIALIZABLE, верно? А что, если у нас также есть уровень изоляции транзакции, указанный в исходном коде, который вызывает хранимую процедуру, которая применяется?

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

Если бы это была база данных SQL Server 2005, я мог бы пойти с Джефф Далгас ответил на тупиковую проблему, касающуюся переполнения стека , если это даже применимо к проблеме, с которой я сталкиваюсь , Но в настоящее время обновление до SQL Server 2005 не является приемлемым вариантом.

Поскольку эти первоначальные попытки потерпели неудачу, мой вопрос: Как бы вы пошли отсюда? Какие шаги вы бы предприняли, чтобы уменьшить или даже избежать тупика, или какие команды / инструменты я должен использовать, чтобы лучше разоблачить проблему?

Ответы [ 4 ]

1 голос
/ 02 июня 2009

Несколько комментариев:

  1. Уровень изоляции, явно указанный в вашей хранимой процедуре, переопределяет уровень изоляции вызывающего.

  2. Если sp_getapplock доступен на 2000, я бы использовал его:

    http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

  3. Во многих случаях сериализуемый уровень изоляции повышает вероятность получения тупика.

  4. Хороший ресурс на 2000 год:

    http://www.code -magazine.com / article.aspx? Quickid = 0309101 & страница = 1

Также могут быть применимы некоторые советы Барта Дункана:

http://blogs.msdn.com/bartd/archive/2006/09/09/747119.aspx

0 голосов
/ 29 июля 2009

Причина тупиков в моем сценарии установки была после всех индексов. Мы использовали (генерируемые по умолчанию) non clustered индексы для первичных ключей таблиц. Изменение на clustered индексы решило проблему.

0 голосов
/ 02 июня 2009

Полагаю, вы испытываете взаимоблокировку:

  1. Потому что ваши операторы DML (вероятно, Updates) получают эскалацию к блокировкам таблиц, или
  2. Различные хранимые процедуры обращаются к одним и тем же таблицам в транзакциях, но в другом порядке.

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

Примечание: это относится как к целевым таблицам, так и к исходным таблицам (несмотря на NOLOCK, исходные таблицы UPDATE также получат блокировки. Проверьте планы запросов для сканирования пользовательских хранимых процедур. В отличие от пакетных или массовых операций, большинство пользовательских запросов и DML работают с небольшими подмножествами строк таблицы и поэтому не должны блокировать всю таблицу.

Затем, во-вторых, я бы проверил хранимые процедуры, чтобы убедиться, что весь доступ к данным в хранимой процедуре осуществляется в согласованном порядке (обычно предпочтительнее Parent -> Child).

0 голосов
/ 02 июня 2009

В дополнение к ответу Алекса:

  • Наберите код, чтобы увидеть, обращаются ли к таблицам в том же порядке. Мы сделали это недавно и переупорядочили код так, чтобы он всегда был родительским, а потом дочерним. Система выросла, код и функции стали более сложными, более пользовательскими: мы просто начали получать взаимоблокировки.

- Проверьте, можно ли сократить транзакции (например, начать позже, закончить раньше, уменьшить обработку)

  • Определите, какой код вы не хотите потерпеть неудачу, и используйте SET DEADLOCK PRIORITY LOW в другом Мы использовали это (в SQL 2005 есть больше опций), чтобы гарантировать, что некоторый код никогда не будет заблокирован и не принесет в жертву другой код.

  • Если у вас есть SELECT в начале транзакции для подготовки какого-либо материала, рассмотрите HOLDLOCK (может быть, UPDLOCK), чтобы сохранить его заблокированным на время. Мы используем это время от времени, поэтому прекращаем запись в эту таблицу другими процессами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...