SqlException: тупик - PullRequest
       19

SqlException: тупик

11 голосов
/ 30 ноября 2010

Я получаю эти два исключения, когда пытаюсь получить данные из базы данных SQL в C #:

System.Data.SqlClient.SqlException: транзакция (ID процесса 97) заблокирована для ресурсов блокировки другого процесса и была выбрана в качестве жертвы тупика.

ИЛИ

System.Data.SqlClient.SqlException: транзакция (ID процесса 62) заблокирована для ресурсов блокировки другого процесса и была выбрана в качестве жертвы тупика.

OR

System.Data.SqlClient.SqlException: транзакция (ID процесса 54) была заблокирована для ресурсов блокировки с другим процессом и была выбрана в качестве жертвы тупика. Перезапустите транзакцию.

это код:

 using (SqlConnection con = new SqlConnection(datasource))
 {
    SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con);
    cmd.CommandTimeout = 300;
    con.Open();
    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    adapter.Fill(ds);
    con.Close();
    return ds.Tables[0];
 }

Это происходило каждый раз.

Есть идеи, как их можно решить?

Ответы [ 3 ]

19 голосов
/ 30 ноября 2010

Есть несколько вещей, которые вы можете сделать, чтобы уменьшить количество взаимоблокировок, которые вы получаете, и некоторые вещи, которые вы можете сделать, чтобы полностью устранить их.

Прежде всего, запустите SQL Server Profiler и попросите его датьвы график тупиков .Запустив эту трассировку, вы получите запрос other , который конфликтует с вашим.Ваш запрос довольно прост, хотя я серьезно сомневаюсь, что у вас есть SELECT * запрос из таблицы MyTable в вашей системе ...

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

Другие вещи, которые вы можете сделать:

  • Ускорить ваши запросы, в частности, применяя к ним правильные индексы.
  • Включить изоляцию моментальных снимков в базе данныхи используйте SET TRANSACTION ISOLATION LEVEL SNAPSHOT в ваших транзакциях, где это необходимо.Также включите чтение зафиксировано с версионированием строки .Во многих случаях этого достаточно для полного устранения большинства тупиковых ситуаций.Читайте об уровнях изоляции транзакций. Поймите что вы делаете.
8 голосов
/ 30 ноября 2010

Не то чтобы это помогло решить проблему тупика, но вы должны утилизировать другие IDisposable объекты так же, как вы утилизируете свой SqlConnection как таковой:

    using (SqlConnection con = new SqlConnection(datasource))
    using (SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con))
    {
        cmd.CommandTimeout = 300;
        con.Open();
        using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
        using (DataSet ds = new DataSet())
        {
            adapter.Fill(ds);
            return ds.Tables[0];
        }
    }

Возможно, вам удастся избежать блокировки с помощью подсказки блокировки в вашем запросе, таким образом:

Select * from MyTable with (nolock) Where ID='1'

Надеюсь, это поможет.

3 голосов
/ 30 ноября 2010

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

...