2010-11-03 4 views
0

У меня возникает ситуация с прерывистым тупиком со следующим (упрощенным) кодом.ADO.NET DeadLock

DataSet my_dataset = new DataSet() 
SqlCommand sql_command = new SqlCommand(); 

sql_command.Connection = <valid connection> 
sql_command.CommandType = CommandType.Text; 
sql_command.CommandText = 'SELECT * FROM MyView ORDER BY 1' 

SqlDataAdapter data_adapter = new SqlDataAdapter(sql_command); 

sql_command.Connection.Open(); 

data_adapter.Fill(my_dataset); 

sql_command.Connection.Close(); 

Ошибки я получаю:

транзакций (Process ID 269) была тупикового на ресурсах блокировки с другим процессом и была выбраны в качестве тупиковой жертвы. Повторите транзакцию .

Как я понимаю, просто заполнение DataSet с помощью команды ADO.Net .Fill() не должно создавать блокировку в базе данных. И, как видно из сообщения об ошибке, блокировка принадлежит другому процессу. В представлении «Просмотр» я имею запросы только для выбора, но он объединяет несколько таблиц.

  • Может ли вид, на который распространяется действие выбора, зависит от заблокированных записей?
  • Может ли ADO.Net .Fill() заблокировать записи?
  • Предполагая, что мне нужно заполнить DataSet, есть ли способ сделать это, чтобы избежать возможных блокировок данных?

SQL Server 2005 (9.0.4035)

ответ

2

Выбор запроса с помощью соединений может действительно вызвать тупик. Один из способов справиться с этим - выполнить запрос в SqlTransaction с использованием изоляции моментальных снимков.

using(SqlTransaction sqlTran = connection.BeginTransaction(IsolationLevel.Snapshot)) 
{ 
    // Query goes here. 
} 

Заключительный процесс может произойти из-за блокировки каждой таблицы, соединяющейся одна за другой, прежде чем выполнять соединение. Если в другом запросе есть блокировка таблицы, которую должен блокировать другой запрос, и наоборот, существует мертвая блокировка. С Snapshot Isolation запросами, которые только что прочитанные из таблиц не блокируют их. Целостность поддерживается, потому что чтение фактически выполняется из моментального снимка данных во время начала транзакции.

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

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

+0

Не могли бы вы расширить информацию об этом дальше? Меня бы очень интересовали любые пояснительные документы или ссылки о том, как и почему это поведение происходит. – 0xCAFEBABE

+0

@TME. Я добавил дополнительную информацию. – YWE

+0

ADO «Classic» имеет разные уровни блокировки ... Мне сейчас интересно, каков уровень блокировки по умолчанию для ADO.NET? Является ли метод выше, как я буду «настраивать» само соединение? У меня все еще есть блокировка чтения, если я установил IsolationLevel в Snapshot или ReadUncommited? –

0

Это может быть далеко и не решение вашей проблемы, проверьте другие решения первой - но у нас была аналогичная проблема (отборное, который блокирует записи!), что после значительных усилий мы отслеживали уровень файла/SMB. Казалось, что при большой нагрузке считывание файлов с сетевого диска (SAN) задерживается, создавая блокировку чтения в реальных файлах базы данных. Это выражается как блокировка записанных записей.

Но это было состояние гонки и не воспроизводимо без нагрузки на приводы. О, и это был SQL Server 2005.

Вы должны быть способны определить с помощью инструментов SQL Server, которые транзакции блокируют друг друга.

1

Вы можете попробовать это:

  • Нижний уровень транзакции для этого запроса (например, IsolationLevel.ReadUncommited).
  • Используйте подсказку NOLOCK по вашему запросу.