web-dev-qa-db-fra.com

Comment empêcher les blocages de magasin de colonnes partitionnés sur SELECT

J'ai trois tables d'index de colonnes en cluster (CCI) dans SQL Server 2016. Toutes ces CCI sont dans le même schéma de partitionnement, basé sur l'ID du locataire. Dernièrement, et de manière incohérente, je reçois des blocages sur les instructions de sélection simples des jointures à ces tables. Exemple de requête bloquant:

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

Message d'erreur:

La transaction (ID de processus 56) a été bloquée sur des ressources d'objet en attente génériques avec un autre processus et a été choisie comme victime de blocage. Relancez la transaction.

Des indices:

  • Si la requête utilise un autre index en plus de la CCI, elle ne se bloque pas.
  • Si je supprime deux des trois filtres tenantid, cela n'entraîne pas d'interblocage.
  • Si je sélectionne les 32 premiers ou inférieurs, cela n'entraîne pas de blocage.
  • Si j'ajoute OPTION (MAXDOP 1), cela ne bloque pas.
  • Je peux le reprocher dans ma réplique PROD brouillée, PROD READ-ONLY Secondary et PROD lui-même.
  • Je ne peux pas reprocher ce comportement dans DEV ou INT.
  • Il se bloque toujours si j'ajoute WITH (NOLOCK) aux 3 jointures de table
  • La requête se bloque d'elle-même. Il se bloquera lorsqu'il n'y a aucun autre processus actif.
  • Les plans de requête sans parallélisme ne bloquent pas

Deadlock xml ici

Notre version PROD:

Microsoft SQL Server 2016 (SP2-CU5) (KB4475776) - 13.0.5264.1 (X64) 10 janvier 2019 18:51:38 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) sur Windows Server 2012 R2 Standard 6.3 (Build 9600 :) (Hyperviseur)

Comment empêcher les blocages sur cette requête?

10
Cyndi Baker

Puisque vous êtes sur SQL Server 2016, il convient de mentionner qu'il existe au moins un correctif de bogue public pour les blocages parallèles impliquant des index columnstore:

CORRECTIF: Un blocage se produit lorsque vous exécutez une requête parallèle sur un index columnstore en cluster dans SQL Server 2016 et 2017

(merci à Denis Rubashkin pour avoir fourni le lien initialement)

Cela a été publié dans le cadre du SP1 CU7. Si vous n'êtes pas à la hauteur de ce CU, vous devriez essayer. Ce correctif serait également inclus dans SP2 (l'un des CU).

En général, les deux approches pour corriger les blocages de parallélisme intra-requête:

  • éviter le parallélisme (en ajustant la requête pour qu'elle ne soit pas parallèle, en utilisant un indice MAXDOP, etc.) - ceci est couvert dans le autre réponse par Thomas Costers
  • appliquer le dernier service pack/mises à jour cumulatives à SQL Server
8
Josh Darnell

Avez-vous vérifié le blog suivant sur Deadlocks de threads parallèles intra-requête

La ressource SyncPoint indique l'utilisation d'un événement d'échange si je ne me trompe pas.
En regardant les participants de votre impasse, vous pouvez voir qu'ils proviennent tous du même spid (55) et du même lot (0), mais utilisent des threads différents. Cela indique qu'ils font tous partie de la même requête parallèle et est confirmé par le fait que vous ne recevez aucun blocage à chaque fois que vous exécutez la requête avec MAXDOP 1. Dans le cas des interblocages de threads parallèles intra-requête, les threads d'une seule requête finiront par se bloquer entre eux en attendant des objets de synchronisation, SyncPoints dans votre cas.

La dernière fois que j'ai été témoin de ce type de comportement, j'ai pu optimiser davantage la requête et empêcher ainsi la requête d'utiliser un plan d'exécution parallèle. Je soupçonne que vous avez fait la même chose en limitant votre jeu de résultats à 32 enregistrements ou en utilisant un index différent.
Une autre option serait d'ajouter MAXDOP 1 à votre requête, mais pas un grand fan de cette option.

Mais avant de jouer avec ces deux options, vérifiez d'abord si vous êtes sur le dernier SP/CU.

2
Thomas Costers