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 la WHERE
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 à pousser UPDATE
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:
[SqlFunction(IsDeterministic = true,
IsPrecise = true,
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
{
string s = replacementSpec.Value;
ReplaceSpecification rs;
if (!cachedSpecs.TryGetValue(s, out rs))
{
var doc = new XmlDocument();
doc.LoadXml(s);
rs = new ReplaceSpecification(doc);
cachedSpecs[s] = rs;
}
return rs.IsMatch(inputString.ToString());
}
et, dans internal class ReplaceSpecification
, j'ai ajouté le code pour exécuter le test contre l'expression régulière
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Si tous les champs sont testés dans une seule instruction, SQL Server ne parallélise pas le travail
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND (dbo.CanReplaceMultiWord(IndexedXml, @X) = 1
OR DE15 = dbo.ReplaceMultiWord(DE15, @X)
OR dbo.CanReplaceMultiWord(DE87, @X) = 1
OR dbo.CanReplaceMultiWord(DE15, @X) = 1);
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).
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(IndexedXml, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE461 = dbo.ReplaceMultiWord(DE461, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE461, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE87 = dbo.ReplaceMultiWord(DE87, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE87, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE15, @X) = 1;
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'expression WHERE
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 par
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
Et ajoutez ce qui suit avant le premier UPDATE
DECLARE @ac NVARCHAR(32);
SET @ac = dbo.CreateAhoCorasick(
(SELECT NAMES FROM dbo.NamesMultiWord FOR XML RAW, root('root')),
'en-us:i'
);
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.