J'ai une requête qui prend environ 3 heures pour s'exécuter sur notre serveur - et elle ne tire pas parti du traitement parallèle. (environ 1,15 million d'enregistrements en dbo.Deidentified
, 300 enregistrements en dbo.NamesMultiWord
). Le serveur a accès à 8 cœurs.
UPDATE dbo.Deidentified
WITH (TABLOCK)
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml),
DE461 = dbo.ReplaceMultiWord(DE461),
DE87 = dbo.ReplaceMultiWord(DE87),
DE15 = dbo.ReplaceMultiWord(DE15)
WHERE InProcess = 1;
et ReplaceMultiword
est une procédure définie comme:
SELECT @body = REPLACE(@body,Names,Replacement)
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
RETURN @body --NVARCHAR(MAX)
Faut-il ReplaceMultiword
empêcher la formation d'un plan parallèle? Existe-t-il un moyen de réécrire cela pour permettre le parallélisme?
ReplaceMultiword
s'exécute dans l'ordre décroissant car certains des remplacements sont des versions courtes d'autres, et je veux que la correspondance la plus longue réussisse.
Par exemple, il peut y avoir «George Washington University» et un autre de «Washington University». Si le match «Washington University» était le premier, alors «George» serait laissé pour compte.
Techniquement, je peux utiliser CLR, je ne sais pas comment le faire.
SELECT @var = REPLACE ... ORDER BY
construction n'est pas garantie de fonctionner comme prévu. Exemple d'élément Connect (voir la réponse de Microsoft). Ainsi, le passage à SQLCLR a l'avantage supplémentaire de garantir des résultats corrects, ce qui est toujours agréable.Réponses:
L'UDF empêche le parallélisme. Il est également à l'origine de cette bobine.
Vous pouvez utiliser CLR et une expression régulière compilée pour effectuer votre recherche et remplacer. Il ne bloque pas le parallélisme tant que les attributs requis sont présents et sera probablement beaucoup plus rapide que d'effectuer 300
REPLACE
opérations TSQL par appel de fonction.Un exemple de code est ci-dessous.
Cela dépend de l'existence d'un UDF CLR comme ci-dessous (cela
DataAccessKind.None
devrait signifier que la bobine disparaît ainsi que celle qui est là pour la protection d'Halloween et n'est pas nécessaire car cela n'accède pas à la table cible).la source
where
clause en utilisant un test de correspondance avec l'expression régulière, car la plupart des écritures ne sont pas nécessaires - la densité des `` hits '' devrait être faible, mais mes compétences en C # (je suis un gars C ++) ne l'ont pas amenez-moi là. Je pensais dans le sens d'une procédurepublic static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
qui retourneraitreturn Regex.IsMatch(inputString.ToString());
mais j'obtiens des erreurs sur cette déclaration de retour, comme `System.Text.RegularExpressions.Regex est un type mais est utilisé comme une variable.Bottom line : L'ajout de critères à la
WHERE
clause et la division de la requête en quatre requêtes distinctes, une pour chaque champ, a permis au serveur SQL de fournir un plan parallèle et a rendu la requête exécutée 4X aussi vite qu'elle l'avait fait sans le test supplémentaire de laWHERE
clause. Diviser les requêtes en quatre sans le test n'a pas fait cela. Ni l'ajout du test sans fractionner les requêtes. L'optimisation du test a réduit le temps d'exécution total à 3 minutes (par rapport aux 3 heures d'origine).Mon UDF d'origine a pris 3 heures 16 minutes pour traiter 1 174 731 lignes, avec 1 216 Go de données nvarchar testées. En utilisant le CLR fourni par Martin Smith dans sa réponse, le plan d'exécution n'était toujours pas parallèle et la tâche a pris 3 heures et 5 minutes.
Après avoir lu ces
WHERE
critères pourrait aider à pousserUPDATE
en parallèle, j'ai fait ce qui suit. J'ai ajouté une fonction au module CLR pour voir si le champ avait une correspondance avec l'expression régulière:et, dans
internal class ReplaceSpecification
, j'ai ajouté le code pour exécuter le test contre l'expression régulièreSi tous les champs sont testés dans une seule instruction, SQL Server ne parallélise pas le travail
Temps d'exécution de plus de 4 1/2 heures et toujours en cours d'exécution. Plan d'exécution:
Cependant, si les champs sont séparés en déclarations distinctes, un plan de travail parallèle est utilisé, et mon utilisation du processeur passe de 12% avec les plans série à 100% avec les plans parallèles (8 cœurs).
Temps pour exécuter 46 minutes. Les statistiques sur les rangées ont montré qu'environ 0,5% des enregistrements avaient au moins une correspondance d'expression régulière. Plan d'exécution:
Maintenant, le principal frein au temps était la
WHERE
clause. J'ai ensuite remplacé le test d'expressionWHERE
régulière dans la clause par l' algorithme Aho-Corasick implémenté en tant que CLR. Cela a réduit le temps total à 3 minutes 6 secondes.Cela a nécessité les modifications suivantes. Chargez l'assemblage et les fonctions de l'algorithme Aho-Corasick. Remplacez la
WHERE
clause parEt ajoutez ce qui suit avant le premier
UPDATE
la source