Fazit : Durch Hinzufügen von Kriterien zur WHERE
Klausel und Aufteilen der Abfrage in vier separate Abfragen konnte SQL Server mit einem für jedes Feld einen parallelen Plan erstellen und die Abfrage ohne den zusätzlichen Test in der WHERE
Klausel 4-mal so schnell ausführen wie zuvor . Das Aufteilen der Abfragen in vier ohne den Test hat das nicht getan. Der Test wurde auch nicht hinzugefügt, ohne die Abfragen aufzuteilen. Durch die Optimierung des Tests wurde die Gesamtlaufzeit auf 3 Minuten reduziert (von den ursprünglichen 3 Stunden).
Mein ursprünglicher UDF benötigte 3 Stunden und 16 Minuten, um 1.174.731 Zeilen zu verarbeiten, wobei 1.216 GB nvarchar-Daten getestet wurden. Unter Verwendung der von Martin Smith in seiner Antwort angegebenen CLR war der Ausführungsplan immer noch nicht parallel und die Aufgabe dauerte 3 Stunden und 5 Minuten.
Nachdem ich gelesen hatte, dass WHERE
Kriterien helfen könnten, eine UPDATE
Parallele zu schaffen, tat ich Folgendes. Ich habe dem CLR-Modul eine Funktion hinzugefügt, um festzustellen, ob das Feld mit dem regulären Ausdruck übereinstimmt:
[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());
}
und in habe internal class ReplaceSpecification
ich den Code hinzugefügt, um den Test gegen den regulären Ausdruck auszuführen
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Wenn alle Felder in einer einzigen Anweisung getestet werden, wird die Arbeit von SQL Server nicht parallelisiert
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);
Ausführungszeit über 4 1/2 Stunden und läuft noch. Ausführungsplan:
Wenn die Felder jedoch in separate Anweisungen unterteilt sind, wird ein paralleler Arbeitsplan verwendet, und meine CPU-Auslastung reicht von 12% bei seriellen Plänen bis 100% bei parallelen Plänen (8 Kerne).
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;
Ausführungszeit 46 Minuten. Die Zeilenstatistik ergab, dass etwa 0,5% der Datensätze mindestens eine Regex-Übereinstimmung aufwiesen. Ausführungsplan:
Jetzt war der wichtigste Nachteil die WHERE
Klausel. Ich habe dann den Regex-Test in der WHERE
Klausel durch den Aho-Corasick-Algorithmus ersetzt als CLR implementierten . Dadurch wurde die Gesamtzeit auf 3 Minuten und 6 Sekunden reduziert.
Dies erforderte die folgenden Änderungen. Laden Sie die Assembly und Funktionen für den Aho-Corasick-Algorithmus. Ändern Sie die WHERE
Klausel in
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
Fügen Sie vor dem ersten Folgendes hinzu 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
wird nicht garantiert, dass die Konstruktion so funktioniert, wie Sie es erwarten. Beispiel für ein Verbindungselement (siehe Antwort von Microsoft). Die Umstellung auf SQLCLR hat den zusätzlichen Vorteil, dass korrekte Ergebnisse garantiert werden. Das ist immer schön.