Как предотвратить блокировку секционированного Columnstore при SELECT

10

У меня есть три таблицы Clustered Columnstore Index (CCI) в SQL Server 2016. Все эти CCI находятся в одной схеме разделения, основанной на идентификаторе клиента. В последнее время и непоследовательно я получаю тупиковые ситуации для простых операторов выбора из соединений с этими таблицами. Пример запроса, который блокирует:

SELECT  TOP 33 r.tenantid
FROM    Table_r r
        INNER JOIN Table_cm cm ON r.MyKey=cm.MyKey 
        INNER JOIN Table_pe pe ON r.MyKey=pe.MyKey 
WHERE   r.TenantId = 69
        AND pe.TenantId = 69
        AND cm.TenantId = 69

Сообщение об ошибке:

Транзакция (ID процесса 56) была заблокирована на общих ресурсах ожидаемого объекта с другим процессом и была выбрана в качестве жертвы тупика. Перезапустите транзакцию.

Ключи:

  • Если запрос использует другой индекс, кроме CCI, он не блокируется.
  • Если я удаляю два из трех фильтров tenantid, он не блокируется.
  • Если я ВЫБИРАЮ верхнюю часть 32 или ниже, она не блокируется.
  • Если я добавлю OPTION (MAXDOP 1), он не заходит в тупик.
  • Я могу воспроизвести это в моей зашифрованной реплике PROD, только для чтения PROD-ONLY и самой PROD.
  • Я не могу воспроизвести это поведение в DEV или INT.
  • Он все еще блокируется, если я добавлю WITH (NOLOCK) во все 3 объединения таблицы
  • Запрос блокирует сам себя. Он блокируется, когда нет других активных процессов.
  • Планы запросов без параллелизма не зашли в тупик

Тупик xml тут

Наша версия PROD:

Microsoft SQL Server 2016 (SP2-CU5) (KB4475776) - 13.0.5264.1 (X64) 10 января 2019 г. 18:51:38 Авторское право (c) Выпуск Microsoft Corporation Enterprise (64-разрядный) на Windows Server 2012 R2 Standard 6.3 (сборка 9600) :) (Гипервизор)

Как я могу предотвратить взаимные блокировки в этом запросе?

Синди Бейкер
источник

Ответы:

8

Поскольку вы работаете на SQL Server 2016, стоит упомянуть, что существует по крайней мере одно общедоступное исправление ошибки параллельных взаимоблокировок с индексами columnstore:

ИСПРАВЛЕНИЕ: тупик возникает при выполнении параллельного запроса к кластерному индексу хранилища столбцов в SQL Server 2016 и 2017

(спасибо Денису Рубашкину за предоставленную ссылку изначально)

Это было выпущено как часть SP1 CU7. Если вы не до этого CU, вы должны дать этому шанс. Это исправление также будет включено в SP2 (любой из CU).

В общем, два подхода для устранения взаимных блокировок параллелизма внутри запроса:

  • избегать параллелизма (путем настройки запроса так , что он не идет параллельно, используя MAXDOPподсказку и т.д.) - это рассматривается в другом ответе по Томас Costers
  • применить последние обновления пакета / накопительные обновления для SQL Server
Джош Дарнелл
источник
2

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

SyncPointРесурс указывает на использование обменной случае , если я не ошибаюсь.
Глядя на участников вашего тупика, вы видите, что они все приходят из одного и того же spid (55) и batch (0), но используют разные потоки. Это указывает на то, что все они являются частью одного параллельного запроса, и это подтверждается тем фактом, что вы не получаете никаких взаимоблокировок при каждом выполнении запроса с MAXDOP 1. В случае взаимных блокировок внутри-запросов параллельных потоков потоки одного запроса заканчивают взаимной блокировкой друг друга в ожидании объектов синхронизации, в данном случае SyncPoints.

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

Но прежде чем возиться с этими двумя вариантами, сначала проверьте, используете ли вы последнюю версию SP / CU.

Томас Костерс
источник