Ich habe eine Abfrage, deren Ausführung auf unserem Server ungefähr 3 Stunden dauert - und die Parallelverarbeitung wird nicht ausgenutzt. (ungefähr 1,15 Millionen Datensätze in dbo.Deidentified
, 300 Datensätze in dbo.NamesMultiWord
). Der Server hat Zugriff auf 8 Kerne.
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;
und ReplaceMultiword
ist eine Prozedur definiert als:
SELECT @body = REPLACE(@body,Names,Replacement)
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
RETURN @body --NVARCHAR(MAX)
Ist die Forderung, ReplaceMultiword
die Bildung eines Parallelplans zu verhindern? Gibt es eine Möglichkeit, dies umzuschreiben, um Parallelität zu ermöglichen?
ReplaceMultiword
wird in absteigender Reihenfolge ausgeführt, da einige der Ersetzungen kurze Versionen anderer sind und ich möchte, dass die längste Übereinstimmung erfolgreich ist.
Zum Beispiel kann es "George Washington University" und eine andere von der "Washington University" geben. Wenn das Match der Washington University das erste wäre, würde George zurückbleiben.
Technisch kann ich CLR verwenden, ich bin nur nicht vertraut damit.
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.Antworten:
Die UDF verhindert Parallelität. Es verursacht auch diese Spule.
Sie können CLR und einen kompilierten regulären Ausdruck verwenden, um zu suchen und zu ersetzen. Sie blockiert die Parallelität nicht, solange die erforderlichen Attribute vorhanden sind, und ist wahrscheinlich wesentlich schneller als die Ausführung von 300 TSQL
REPLACE
Operationen pro Funktionsaufruf.Beispielcode ist unten.
Dies hängt von der Existenz einer CLR-UDF wie
DataAccessKind.None
folgt ab (dies sollte bedeuten, dass die Spule nicht mehr angezeigt wird, da sie für den Halloween-Schutz vorgesehen ist und nicht benötigt wird, da sie nicht auf die Zieltabelle zugreift).quelle
where
Klausel hinzuzufügen , die einen Test für die Übereinstimmung mit dem regulären Ausdruck verwendet, da die meisten Schreibvorgänge unnötig sind - die Dichte der Treffer sollte niedrig sein, meine C # -Fähigkeiten (ich bin ein C ++ - Typ) jedoch nicht Bring mich hin. Ich dachte an eine Prozedurpublic static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
, die zurückgeben würde,return Regex.IsMatch(inputString.ToString());
aber ich erhalte Fehler in dieser return-Anweisung, wie `System.Text.RegularExpressions.Regex ist ein Typ, der aber wie eine Variable verwendet wird.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 derWHERE
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, eineUPDATE
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:und in habe
internal class ReplaceSpecification
ich den Code hinzugefügt, um den Test gegen den regulären Ausdruck auszuführenWenn alle Felder in einer einzigen Anweisung getestet werden, wird die Arbeit von SQL Server nicht parallelisiert
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).
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 derWHERE
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 inFügen Sie vor dem ersten Folgendes hinzu
UPDATE
quelle