Этот экземпляр размещает базы данных SharePoint 2007 (SP). Мы сталкивались с многочисленными взаимоблокировками SELECT / INSERT с одной интенсивно используемой таблицей в базе данных контента SP. Я сузил задействованные ресурсы, оба процесса требуют блокировки некластеризованного индекса.
Для INSERT требуется блокировка IX для ресурса SELECT, а для SELECT требуется блокировка S для ресурса INSERT. График взаимоблокировки показывает и три ресурса: 1.) два из SELECT (параллельные потоки производителя / потребителя) и 2.) INSERT.
Я приложил график взаимоблокировки для вашего обзора. Поскольку это код Microsoft и структура таблиц, мы не можем вносить никаких изменений.
Однако на сайте MSFT SP я прочитал, что они рекомендуют установить для параметра конфигурации уровня экземпляра MAXDOP значение 1. Поскольку этот экземпляр является общим для многих других баз данных / приложений, этот параметр нельзя отключить.
Поэтому я решил попытаться предотвратить параллельное выполнение этих операторов SELECT. Я знаю, что это не решение, а скорее временная модификация, чтобы помочь с устранением неполадок. Поэтому я увеличил «Пороговое значение стоимости для параллелизма» с наших стандартных 25 до 40 после этого, даже несмотря на то, что рабочая нагрузка не изменилась (SELECT / INSERT происходит часто), мертвые блокировки исчезли. У меня вопрос почему?
SPID 356 INSERT имеет блокировку IX на странице, принадлежащей некластеризованному индексу.
SPID 690 SELECT ID выполнения 0 имеет блокировку S на странице, принадлежащей тому же некластеризованному индексу.
Сейчас же
SPID 356 хочет получить блокировку IX для ресурса SPID 690, но не может ее получить, поскольку SPID 690 блокируется идентификатором выполнения SPID 690 0 S-блокировка
SPID 690 Идентификатор выполнения 1 требует блокировки S для ресурса SPID 356, но не может получить его, поскольку идентификатор выполнения SPID 690 1 блокируется SPID 356, и теперь у нас есть тупик.
План выполнения можно найти на моем SkyDrive
Полная информация о тупике может быть найдена здесь
Если кто-то может помочь мне понять, почему я был бы очень признателен.
Таблица EventReceivers.
Идентификатор UniqueIdentifier № 16
Названия NVARCHAR нет 512
SiteId UniqueIdentifier нет 16
WEBID UniqueIdentifier нет 16
HOSTID UniqueIdentifier нет 16
HostType Int № 4
ItemId Int № 4
DIRNAME NVARCHAR нет 512
LeafName NVARCHAR № 256
Типа INT № 4
SequenceNumber INT № 4
Сборки NVARCHAR нет 512
Класса NVARCHAR нет 512
данных nvarchar № 512
фильтра nvarchar № 512
SourceId tContentTypeId нет 512
SourceType int нет 4
Credential int нет 4
ContextType varbinary № 16
ContextEventType varbinary № 16
ContextId varbinary № 16
ContextObjectId varbinary № 16
ContextCollectionId varbinary № 16
index_name index_description index_keys
EventReceivers_ByContextCollectionId некластеризованным расположен на PRIMARY SiteId, ContextCollectionId
EventReceivers_ByContextObjectId NONCLUSTERED расположен на PRIMARY SiteId, ContextObjectId
EventReceivers_ById NONCLUSTERED, уникальный , расположенный на PRIMARY SiteId, Id
EventReceivers_ByTarget кластерный, уникальный , расположенный на PRIMARY SiteId, WEBID, НомерУзла, HostType, тип, ContextCollectionId, ContextObjectId, ContextId, ContextType, ContextEventType, SequenceNumber, Assembly, Class
EventReceivers_IdUnique некластеризованный, уникальный, уникальный ключ, расположенный на PRIMARY Id
источник
proc_InsertEventReceiver
иproc_InsertContextEventReceiver
что мы не можем видеть в XDL? Кроме того, чтобы уменьшить параллелизм, почему бы просто не воздействовать на эти операторы напрямую (используя MAXDOP 1) вместо того, чтобы использовать настройки для всего сервера?Ответы:
На первый взгляд, это выглядит как классический тупик поиска . Основными составляющими этого тупикового паттерна являются:
SELECT
запрос , который использует , не покрывающий некластерный индекс с ключом LookupINSERT
запрос , который модифицирует кластерный индекс , а затем некластеризованный индексSELECT
Обращается к некластеризованный индекс, а затем кластерный индекс.INSERT
Доступ кластерного индекса первый, то некластеризованный индекс. Доступ к одним и тем же ресурсам в другом порядке с получением несовместимых блокировок - это, конечно, отличный способ «зайти» в тупик.В этом случае
SELECT
запрос:... и
INSERT
запрос:Обратите внимание на поддержание некластеризованных индексов, выделенных зеленым цветом.
Нам нужно было бы увидеть серийную версию
SELECT
плана, если она сильно отличается от параллельной версии, но, как отмечает Джонатан Кехайяс в своем руководстве по работе с блокировками , этот конкретный шаблон блокировки очень чувствителен к деталям синхронизации и реализации внутренних запросов. Этот тип тупика часто приходит и уходит без очевидной внешней причины.Учитывая доступ к соответствующей системе и соответствующие разрешения, я уверен, что в конечном итоге мы сможем точно выяснить, почему возникает тупик с параллельным планом, а не с последовательным (принимая ту же общую форму). Потенциальные направления исследований включают проверку для оптимизации вложенных циклов и / или предварительной выборки - оба из которых могут внутренне перерасти уровень изоляции в
REPEATABLE READ
течение срока действия заявления. Также возможно, что некоторая особенность параллельного назначения диапазона поиска индекса вносит свой вклад в проблему. Если серийный план станет доступным, я мог бы потратить некоторое время на изучение деталей, поскольку это потенциально интересно.Обычным решением для этого типа взаимоблокировки является создание покрытия индекса, хотя количество столбцов в этом случае может сделать это нецелесообразным (и, как мне сказали, мы не должны связываться с такими вещами в SharePoint). В конечном счете, рекомендация в отношении планов только для серийных номеров при использовании SharePoint существует по какой-то причине (хотя и не обязательно является хорошей, когда дело доходит до нее). Если изменение порога стоимости для параллелизма решает проблему на данный момент, это хорошо. В более долгосрочной перспективе я бы, вероятно, хотел бы разделить рабочие нагрузки, возможно, с помощью регулятора ресурсов, чтобы внутренние запросы SharePoint получали желаемое
MAXDOP 1
поведение, а другое приложение могло использовать параллелизм.Вопрос об обменах, появляющихся в тупиковом следе, кажется мне красной селедкой; просто следствие независимых потоков, владеющих ресурсами, которые технически должны появиться в дереве. Я не вижу ничего, что могло бы предположить, что сами биржи вносят непосредственный вклад в проблему взаимоблокировки.
источник
Если это был классический тупик поиска , список ресурсов будет включать как Кластерный индекс, так и Некластерный индекс. Как правило, SELECT удерживает блокировку SHARED на индексе NC и ожидает блокировку SHARED на CI, в то время как INSERT получает блокировку EXCLUSIVE на CI и ожидает блокировку EXCLUSIVE на NC. В этом случае список ресурсов в взаимоблокировке xml перечислит оба этих объекта.
Поскольку график взаимоблокировки включает только индекс NC, мы можем исключить эту опцию.
Кроме того, если это была мертвая блокировка из-за Nested Loop Join с UNORDERED PREFETCH , план выполнения сообщит нам, используется ли алгоритм UNORDERED PREFETCH, что опять-таки не так (см. Обновление ниже).
Это оставляет нас предполагать, что это тупик из-за параллельного плана.
График взаимоблокировки не отображается должным образом, но если вы посмотрите на XML взаимоблокировки, вы увидите, что два потока из инструкции SELECT (SPID 690) участвуют в взаимоблокировке. Поток потребителя удерживает блокировку SHARED на странице 1219645 и ожидает производителя на порту 801f8ed0 (e_waitPipeGetRow). Поток производителя ожидает общей блокировки на странице 1155940.
Оператор INSERT удерживает блокировку IX на странице 1155940 и ожидает блокировки IX на странице 1219645, что приводит к тупику.
Я полагаю, что при использовании последовательного плана для оператора SELECT будет предотвращена тупиковая ситуация, поскольку ни в коем случае не требуется блокировка SHARED для нескольких страниц. Я также думаю, что последовательный план будет почти таким же, как параллельный план (без оператора параллелизма).
[ОБНОВЛЕНО на основании комментария Павла]
Видимо, план использует алгоритм OPTIMIZED Nested Loop
Это объясняет, почему SHARED-блокировки удерживаются до конца оператора. REPEATABLE READ в сочетании с параллельным планом является более уязвимым для взаимоблокировки, чем последовательный план, потому что параллельный план может получать и сохранять блокировки от различных диапазонов индекса, тогда как последовательный план получает блокировки более последовательным способом.
источник