Conclusione : l'aggiunta di criteri alla WHERE
clausola e la suddivisione della query in quattro query separate, una per ciascun campo ha consentito a SQL Server di fornire un piano parallelo e ha reso la query eseguita 4 volte più veloce rispetto a prima senza il test aggiuntivo nella WHERE
clausola. Dividere le query in quattro senza il test non lo ha fatto. Né ha aggiunto il test senza dividere le query. L'ottimizzazione del test ha ridotto il tempo di esecuzione totale a 3 minuti (dalle 3 ore originali).
Il mio UDF originale ha impiegato 3 ore e 16 minuti per elaborare 1.174.731 righe, con 1.216 GB di dati nvarchar testati. Utilizzando il CLR fornito da Martin Smith nella sua risposta, il piano di esecuzione non era ancora parallelo e l'attività ha richiesto 3 ore e 5 minuti.
Dopo aver letto che i WHERE
criteri potrebbero aiutare a spingere UPDATE
in parallelo, ho fatto quanto segue. Ho aggiunto una funzione al modulo CLR per vedere se il campo aveva una corrispondenza con il regex:
[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());
}
e, in internal class ReplaceSpecification
, ho aggiunto il codice per eseguire il test contro il regex
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Se tutti i campi sono testati in una singola istruzione, il server SQL non parallelizza il lavoro
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);
Tempo di esecuzione oltre 4 1/2 ore e ancora in esecuzione. Progetto esecutivo:
Tuttavia, se i campi sono separati in istruzioni separate, viene utilizzato un piano di lavoro parallelo e il mio utilizzo della CPU passa dal 12% con i piani seriali al 100% con i piani paralleli (8 core).
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;
Tempo di esecuzione 46 minuti. Le statistiche di riga hanno mostrato che circa lo 0,5% dei record presentava almeno una corrispondenza regex. Progetto esecutivo:
Ora, la principale resistenza in tempo era la WHERE
clausola. Ho quindi sostituito il test regex nella WHERE
clausola con l' algoritmo Aho-Corasick implementato come CLR. Ciò ha ridotto il tempo totale a 3 minuti e 6 secondi.
Ciò ha richiesto le seguenti modifiche. Carica l'assemblaggio e le funzioni per l'algoritmo Aho-Corasick. Cambia la WHERE
clausola in
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
E aggiungi quanto segue prima del primo 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
costruzione non è garantita per funzionare come previsto. Esempio di elemento Connect (vedere la risposta di Microsoft). Quindi, passare a SQLCLR ha l'ulteriore vantaggio di garantire risultati corretti, il che è sempre bello.