Диагностирование мертвых блокировок в SQL Server 2005

df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})
df[df['A']=='foo']

OUTPUT:
   A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14
82
задан NullUserException 6 December 2011 в 23:55
поделиться

22 ответа

Согласно MSDN:

http://msdn.microsoft.com/en-us/library/ms191242.aspx

, Когда любой параметры базы данных READ COMMITTED SNAPSHOT или ALLOW SNAPSHOT ISOLATION идет, логические копии (версии) сохраняются для всех модификаций данных, выполненных в базе данных. Каждый раз, когда строка изменяется определенной транзакцией, экземпляр Механизма базы данных хранит версию ранее зафиксированного изображения строки в tempdb. Каждая версия отмечена с порядковым номером транзакции транзакции, которая внесла изменение. Версии измененных строк объединяются в цепочку с помощью списка ссылок. Новейшее значение строки всегда хранится в текущей базе данных и объединяется в цепочку к имеющим версию строкам, сохраненным в tempdb.

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

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

установка Try эта опция и УДАЛЯЮТ весь NOLOCKs из запросов кода если it’s действительно необходимый. NOLOCKs или использующий глобальные методы в обработчике контекстов базы данных для борьбы с уровнями изоляции транзакции базы данных являются Лейкопластыри к проблеме. NOLOCKS замаскирует основные проблемы с нашим слоем данных и возможно приведет к выбору ненадежных данных, где автоматический выбор / управление версиями строки обновления, кажется, решение.

ALTER Database [StackOverflow.Beta] SET READ_COMMITTED_SNAPSHOT ON
44
ответ дан Jeff Atwood 24 November 2019 в 09:10
поделиться

Имел ту же проблему и не может использовать "IsolationLevel = IsolationLevel. ReadUncommitted" на TransactionScope, потому что серверу не включили DTS (!).

Thats, что я сделал с дополнительным методом:

public static void SetNoLock(this MyDataContext myDS)
{
    myDS.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}

Так, для выборов, кто использует критические таблицы параллелизма, мы включаем "nolock" как это:

using (MyDataContext myDS = new MyDataContext())
{
   myDS.SetNoLock();

   //  var query = from ...my dirty querys here...
}

Sugestions приветствуются!

0
ответ дан 24 November 2019 в 09:10
поделиться

Это меня устраивает, если мой профиль является даже несколькими устаревшими минутами.

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

При реализации "ЧТЕНИЯ, НЕЗАФИКСИРОВАННОГО", не решает проблему, тогда трудно помочь, не зная намного больше об обработке. Может быть некоторая другая настраивающая опция, которая помогла бы этому поведению. Если некоторый гуру MSSQL не приходит на помощь, я рекомендую отправить проблему поставщику.

0
ответ дан bruceatk 24 November 2019 в 09:10
поделиться

Я продолжил бы настраивать все; то, как дисковая подсистема, работает? Какова средняя дисковая длина очереди? Если ввод-вывод создает резервную копию, настоящей проблемой не могли бы быть эти два запроса, которые заходят в тупик, это мог бы быть другой запрос, который является сужением трубы система; Вы упомянули запрос, занимающий 20 секунд, который был настроен, там другие?

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

0
ответ дан SqlACID 24 November 2019 в 09:10
поделиться

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

мне было бы интересно знать, Jeff, как установка его на уровне базы данных будет влиять на запрос, такой как следующее:

Begin Tran
Insert into Table (Columns) Values (Values)
Select Max(ID) From Table
Commit Tran
0
ответ дан GateKiller 24 November 2019 в 09:10
поделиться

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

Вот шаблон, который мы использовали для Видео. Покажите ( ссылка на исходное представление в CodePlex):

using System.Configuration;
namespace VideoShow.Data
{
  public class DataContextFactory
  {
    public static VideoShowDataContext DataContext()
    {
        return new VideoShowDataContext(ConfigurationManager.ConnectionStrings["VideoShowConnectionString"].ConnectionString);
    }
    public static VideoShowDataContext DataContext(string connectionString)
    {
        return new VideoShowDataContext(connectionString);
    }
  }
}

Тогда на уровне обслуживания (или еще более детализированный, для обновлений):

private VideoShowDataContext dataContext = DataContextFactory.DataContext();

public VideoSearchResult GetVideos(int pageSize, int pageNumber, string sortType)
{
  var videos =
  from video in DataContext.Videos
  where video.StatusId == (int)VideoServices.VideoStatus.Complete
  orderby video.DatePublished descending
  select video;
  return GetSearchResult(videos, pageSize, pageNumber);
}
1
ответ дан Rajesh 24 November 2019 в 09:10
поделиться

Необходимо реализовать грязные чтения.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

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

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

Мы не выполняем банковский сайт сюда, нам не нужна идеальная точность каждый раз

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

, Без которого, мы должны были бы обернуть каждый вызов LINQ, который мы выполняем (хорошо, простые чтения, который является подавляющим большинством их) в блоке кода транзакции строки 3-4, который является ужасен

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

1
ответ дан Seibar 24 November 2019 в 09:10
поделиться

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

не Будет, по крайней мере, некоторые из других опций представлять потери производительности, которые взяты все время, когда система повторной попытки будет редко умирать?

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

1
ответ дан John Dyer 24 November 2019 в 09:10
поделиться

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

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

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

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

1
ответ дан RobertTheGrey 24 November 2019 в 09:10
поделиться

Вы будете заботиться, является ли Ваш профиль пользователя несколькими устаревшими секундами?

Несколько секунд определенно были бы приемлемы. Не кажется, что случалось бы так, что долго, так или иначе, если огромное количество людей не отправляют ответы одновременно.

1
ответ дан a_hardin 24 November 2019 в 09:10
поделиться

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

таким образом, если обновления запроса в порядке Table1, Table2 и различном запросе обновляет его в порядке Table2, Table1 тогда, Вы могли бы видеть мертвые блокировки.

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

2
ответ дан Michael Sharek 24 November 2019 в 09:10
поделиться

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

Вот то, что необходимо сделать: используйте выгоду попытки (в T-SQL) для обнаружения условия мертвой блокировки. Когда это произойдет, просто повторно выполните запрос. Это - стандартная практика программирования базы данных.

существуют хорошие примеры этой техники в Paul Nielson Библия SQL-сервера 2005 года .

Вот быстрый шаблон, который я использую:

-- Deadlock retry template

declare @lastError int;
declare @numErrors int;

set @numErrors = 0;

LockTimeoutRetry:

begin try;

-- The query goes here

return; -- this is the normal end of the procedure

end try begin catch
    set @lastError=@@error
    if @lastError = 1222 or @lastError = 1205 -- Lock timeout or deadlock
    begin;
        if @numErrors >= 3 -- We hit the retry limit
        begin;
            raiserror('Could not get a lock after 3 attempts', 16, 1);
            return -100;
        end;

        -- Wait and then try the transaction again
        waitfor delay '00:00:00.25';
        set @numErrors = @numErrors + 1;
        goto LockTimeoutRetry;

    end;

    -- Some other error occurred
    declare @errorMessage nvarchar(4000), @errorSeverity int
    select    @errorMessage = error_message(),
            @errorSeverity = error_severity()

    raiserror(@errorMessage, @errorSeverity, 1)

    return -100
end catch;    
3
ответ дан Eric Z Beard 24 November 2019 в 09:10
поделиться

Q. Почему Вы храните AnswerCount в Posts таблица во-первых?

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

Да, это будет означать выполнение дополнительного запроса:

SELECT COUNT(*) FROM Answers WHERE post_id = @id

или более обычно (если Вы отображаете это для домашней страницы):

SELECT p.post_id, 
     p.<additional post fields>,
     a.AnswerCount
FROM Posts p
    INNER JOIN AnswersCount_view a
    ON <join criteria>
WHERE <home page criteria>

, но это обычно приводит к INDEX SCAN и может быть более эффективным в использовании ресурсов, чем использование READ ISOLATION.

существует больше чем один способ освежевать кошку. Преждевременная de-нормализация схемы базы данных может представить проблемы масштабируемости.

3
ответ дан Guy 24 November 2019 в 09:10
поделиться

@Jeff - я - определенно не эксперт по этому, но у меня были хорошие результаты с инстанцированием нового контекста почти на каждом вызове. Я думаю, что это подобно созданию нового объекта Соединения на каждом вызове с ADO. Издержки не так плохи, как Вы думали бы, так как организация пула подключений будет все еще использоваться так или иначе.

я просто использую глобального статического помощника как это:

public static class AppData
{
    /// <summary>
    /// Gets a new database context
    /// </summary>
    public static CoreDataContext DB
    {
        get
        {
            var dataContext = new CoreDataContext
            {
                DeferredLoadingEnabled = true
            };
            return dataContext;
        }
    }
}

и затем я делаю что-то вроде этого:

var db = AppData.DB;

var results = from p in db.Posts where p.ID = id select p;

И я сделал бы то же самое для обновлений. Так или иначе у меня нет почти такого же трафика как Вы, но я определенно получал некоторую блокировку, когда я использовал общий DataContext вначале только с горсткой пользователей. Никакие гарантии, но могло бы стоить дать попытку.

Обновление : С другой стороны, смотря на Ваш код, Вы только совместно используете контекст данных в течение времени жизни того конкретного экземпляра контроллера, который в основном кажется прекрасным, если это так или иначе не привыкает одновременно вызовами mutiple в контроллере. В потоке по теме заявил ScottGu:

Контроллеры только живут для единственного запроса - так в конце обработки запроса, они собраны "мусор" (что означает, что DataContext собран)...

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

3
ответ дан jeremcc 24 November 2019 в 09:10
поделиться

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

Помнят, что мертвая блокировка требует (по крайней мере) 2 блокировок. Соединение 1 имеет Блокировку A, хочет Блокировку B - и наоборот для Соединения 2. Это - неразрешимая ситуация, и кто-то должен дать.

то, Что Вы показали до сих пор, решено простой блокировкой, которую SQL-сервер рад сделать целый день.

я подозреваю, что Вы (или LINQ) запускаете транзакцию с того оператора UPDATE в нем и ВЫБИРАЕТЕ некоторую другую часть информации перед рукой. Но, действительно необходимо отследить в обратном порядке через график мертвой блокировки, чтобы найти, что блокировки содержали каждым потоком, и затем отследите в обратном порядке через Профилировщика для нахождения операторов, которые заставили те блокировки быть предоставленными.

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

10
ответ дан Mark Brackett 24 November 2019 в 09:10
поделиться

Вы будете заботиться, является ли Ваш профиль пользователя несколькими устаревшими секундами?

Нет - это совершенно приемлемо. Установка основного уровня изоляции транзакции является, вероятно, лучшим/самым чистым способом пойти.

7
ответ дан Greg Hurlman 24 November 2019 в 09:10
поделиться

Вы инстанцируете нового LINQ к объекту SQL DataContext для каждой операции, или Вы, возможно, совместно используете тот же статический контекст для всех своих вызовов? Я первоначально попробовал последний подход, и от того, что я помню, он вызвал нежелательную привязку DB. Я теперь создаю новый контекст для каждой атомарной операции.

14
ответ дан jeremcc 24 November 2019 в 09:10
поделиться

Мне довольно неудобно из-за этого вопроса и ответов оператора. Существует большая "попытка эта волшебная пыль! Никакая та волшебная пыль!"

я не вижу нигде, что у Вас есть anaylzed блокировки, которые взяты и определены, какой точный тип блокировок заведены в тупик.

Все, на что Вы указали, - то, что некоторые блокировки происходят - не, что заходит в тупик.

В SQL 2005 можно получить больше информации о том, при помощи чего вынимаются блокировки:

DBCC TRACEON (1222, -1)

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

18
ответ дан Mitch Wheat 24 November 2019 в 09:10
поделиться

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

Это - вероятно, связанная с индексом проблема. Например, позволяет, говорят, что таблица Posts имеет некластерный индекс X, который содержит ParentID и один (или больше) обновляемого поля (полей) (AnswerCount, LastActivityDate, LastActivityUserId).

мертвая блокировка А произошла бы, если ВЫБОР cmd делает считанный общим образом, соединяют индекс X для поиска ParentId и затем должен сделать, считанный общим образом соединяет кластерный индекс для получения остальных столбцов, в то время как ОБНОВЛЕНИЕ cmd делает монопольную блокировку записи на кластерном индексе и должно заставить монопольную блокировку записи на индексе X обновлять его.

у Вас теперь есть ситуация, где заблокированный X и пытается получить Y, тогда как B заблокировал Y и пытается добраться X.

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

25
ответ дан MrB 24 November 2019 в 09:10
поделиться

NOLOCK и ЧТЕНИЕ ОТМЕНИЛО ФИКСАЦИЮ , скользкий путь. Вы никогда не должны использовать их, если Вы не понимаете, почему мертвая блокировка происходит сначала. Меня волновало бы, что Вы говорите, "Добавили мы с (nolock) ко всем SQL-запросам". Быть необходимостью для добавления С NOLOCK везде является верным признаком, что у Вас есть проблемы в Вашем слое данных.

сам оператор обновления выглядит немного проблематичным. Вы определяете количество ранее в транзакции, или просто вытягиваете его от объекта? AnswerCount = AnswerCount+1 то, когда вопрос добавляется, является, вероятно, лучшим способом обработать это. Тогда Вам не нужна транзакция для получения корректного количества, и Вы не должны волноваться по поводу проблемы параллелизма, что потенциально представляете себя.

Один простой способ обойти этот тип проблемы мертвой блокировки без большой работы и не включая грязные чтения состоит в том, чтобы использовать "Snapshot Isolation Mode" (новый в SQL 2005), который будет всегда давать Вам чистое чтение последних неизмененных данных. Можно также поймать и повторить заведенные в тупик операторы довольно легко, если Вы хотите обработать их корректно.

37
ответ дан Nadeem_MK 24 November 2019 в 09:10
поделиться

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

ПОЛЬЗОВАТЕЛЬСКИЙ Набор Обновления FirstName = 'foobar';//решают спать в течение года.

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

3
ответ дан aquinas 24 November 2019 в 09:10
поделиться

Типичная взаимоблокировка чтения / записи возникает из-за доступа к порядку индекса. Чтение (T1) находит строку по индексу A, а затем ищет спроецированный столбец по индексу B (обычно кластеризованный). Запись (T2) изменяет индекс B (кластер), а затем должен обновить индекс A. T1 имеет S-Lck на A, хочет S-Lck на B, T2 имеет X-Lck на B, хочет U-Lck на A. Тупик , затяжка. T1 убит. Это распространено в средах с интенсивным OLTP-трафиком и слишком большим количеством индексов :). Решение состоит в том, чтобы либо при чтении не переходить от A к B (т.е. включенный столбец в A, либо удалять столбец из спроецированного списка), либо T2 не должен переходить от B к A (не обновлять индексированный столбец). К сожалению, linq здесь вам не друг ...

5
ответ дан 24 November 2019 в 09:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: