Ich hätte gerne einen Beitrag zu einem Problem, das ich habe. Wir haben einen Codeabschnitt, den wir in unseren gespeicherten Prozeduren wiederholen, und jedes Mal, wenn die Verarbeitung einige Zeit in Anspruch nimmt, beträgt die Anzahl der Lesevorgänge in Kombination mit Hunderttausenden von Elementen Hunderte von Millionen. Grundsätzlich haben wir Artikel, und Artikel können bis zu 12 Maschinen mit jeweils eigenem Status haben.
Dies sind die (vereinfachten) Tabellenstrukturen:
CREATE TABLE dbo.ItemMachineState
(
[itemID] [int],
[machineID] [int],
[stateID] [int]
)
CREATE TABLE dbo.Transition
(
[machineID] [int] NOT NULL,
[eventID] [int] NOT NULL,
[stateID] [int] NOT NULL,
[nextStateID] [int] NOT NULL
)
Während der Verarbeitung erstellen wir eine # temp-Tabelle, gegen die wir arbeiten, und sie hat schließlich eine eventID pro Element. Diese temporäre Tabelle wird dann wie folgt wieder mit ItemState und Transition verknüpft:
UPDATE dbo.ItemState
SET stateID = tr.nextStateID
FROM #temp t
JOIN dbo.ItemMachineState ist ON ist.itemID = t.itemID
JOIN Transition tr ON tr.stateID = ist.stateID AND
tr.machineID = ist.machineID AND
tr.eventID = t.eventID
Die von uns berechnete Ereignis-ID bestimmt also, was mit den Maschinen eines bestimmten Gegenstands passiert, je nachdem, in welchem Zustand sie sich befinden. Das Problem ist, dass ein Ereignis null oder mehr Maschinenzustände in einer Bewegung manipulieren kann, wenn dieses Ereignis relevant ist zu dieser besonderen Kombination von Zustand und Maschine.
Hier ist ein Beispiel für eine dieser Zustandsverschiebungen:
ItemID 3468489 sieht zuerst in ItemMachineState so aus ...
itemID machineID stateID
----------- ----------- -----------
3468489 12 4
3468489 14 113
3468489 15 157
3468489 16 165
3468489 18 169
3468489 19 165
3468489 20 157
3468489 21 165
3468489 23 173
3468489 24 173
3468489 26 9
3468489 36 9
Wir arbeiten und haben schließlich eine # temp-Tabelle mit einer ItemID und einer EventID ...
itemID eventID
----------- -----------
3468489 64
Dann verbinden wir diese beiden Tabellen mit Transition, was für diese bestimmte Ereignis-ID folgendermaßen aussieht:
machineID eventID stateID nextStateID
----------- ----------- ----------- -----------
13 64 73 79
13 64 74 79
13 64 75 79
13 64 76 79
13 64 77 79
13 64 78 79
13 64 187 79
13 64 188 79
13 64 189 79
13 64 190 79
13 64 191 79
36 64 9 79
36 64 194 79
36 64 196 79
36 64 208 79
36 64 210 79
36 64 213 79
36 64 218 79
46 64 73 79
47 64 73 79
70 64 73 79
70 64 75 79
70 64 76 79
70 64 77 79
70 64 78 79
Alles zusammen:
SELECT t.itemID, t.eventID, ist.machineID, ist.stateID, tr.nextStateID
FROM #temp t
JOIN dbo.ItemMachineState ist ON ist.itemID = t.itemID
JOIN Transition tr ON tr.stateID = ist.stateID AND
tr.machineID = ist.machineID AND
tr.eventID = t.eventID
itemID eventID machineID stateID nextStateID
----------- ----------- ----------- ----------- -----------
3468489 64 36 9 79
In diesem Beispiel war dieses Ereignis nur für eine Maschine für diesen Artikel relevant. Die stateID wird auf machineID 36 von 9 auf 79 aktualisiert, und alles andere bleibt für dieses Element gleich.
Ich hätte gerne Vorschläge, wie ich das anders angehen kann. Wir können uns nicht von der Tabellenstruktur entfernen, aber wir können ändern, wie wir bei Übergängen / Ereignissen stateID auf nextStateID setzen. Wie Sie oben sehen können, funktioniert dies durch Eliminierung; Wir brauchen den aktuellen Zustand und die Maschine, um herauszufinden, wie der nächste Zustand für diese Maschine und dieses Ereignis aussieht. In einigen Fällen wird dadurch nichts aktualisiert, in anderen Fällen werden mehrere Computer gleichzeitig aktualisiert, und diese Funktion gefällt uns. Ich denke nicht, dass die schlankste Lösung für dieses Problem durch einfaches Ändern von Indizes oder Hinzufügen von Abfragehinweisen gefunden werden kann und dass wir einen neuen Ansatz benötigen, der die Anzahl der Lesevorgänge und die Verarbeitungszeit begrenzt, uns aber die gleiche Funktionalität bietet.
Ich wollte vermeiden, Indizes und dergleichen in diese Diskussion einzubeziehen, da ich dann echte Beispiele verwenden müsste, die die Essenz dessen, was ich hier zu fragen versuche, verschmutzen. Ich habe den Namen von Spalten und Tabellen geändert, um meine Frage zu vereinfachen. Auf jeden Fall geht es los:
Abfrageplan http://pastebin.com/xhPa4t8d , Erstellen und Indizieren von Skripten http://pastebin.com/sp70QuEJ
Beachten Sie, dass wir im Abfrageplan einen INNER LOOP JOIN erzwingen. Wenn die Abfrage einem einfachen JOIN überlassen wird, dauert die Verarbeitung exponentiell länger.
Verwenden des @ wBob UNIQUE CLUSTERED-Index vor:
Die Verwendung OPTION (MERGE JOIN, HASH JOIN)
führte zu diesem Ausführungsplan und den Ergebnissen:
Wird in Kürze mit anderen Informationen aktualisiert
dbo.ItemState
ddl und einigen Daten aktualisieren ? Sie können sqlfiddle.com verwenden, um einen Repro einzurichten. Gibt es in diesen Tabellen auch Indizes, FKs und Trigger? Sie können einen tatsächlichen Ausführungsplan-XML-Code veröffentlichen (Pastebin verwenden und hier verlinken). Das wird dir helfen, bessere und schnellere Antworten zu bekommen :-)FROM #Event AS e INNER LOOP JOIN EFT.AssetState AS ast
, können Sie auch einen Abfragehinweis verwendenOPTION (LOOP JOIN, QUERYTRACEON 8649, QUERYTRACEON 4199);
. Was ist der Gesamtspeicher auf dem Server und der maximale Speicher sowie die maximale Dop-Einstellung? Sie können auch bestimmte Zuständeif exists (select .. some criteria = true) then update else do nothing
zusammen mit Stapelaktualisierungen überprüfen .OPTION (MERGE JOIN, HASH JOIN)
gleichzeitig? Hast du es versuchtOPTION (LOOP JOIN, QUERYTRACEON 8649, QUERYTRACEON 4199);
?Antworten:
Ich würde in Betracht ziehen, nicht alle Zeilen gleichzeitig zu aktualisieren und stattdessen mehrere Computer zu durchlaufen, damit das Datensatzvolumen pro Aktualisierung abnimmt. Sie können den gleichen Code behalten, indem Sie ihn einfach stapeln.
quelle
Ich habe eine 50% ige Leistungssteigerung in meinem Prüfstand um durch eine zweite temporäre Tabelle mit einem eindeutigen Clustered - Index erstellt auf
assetID
undeventID
und den AbwurfLOOP
Hinweis. Dies sollte Ihre Abfrageergebnisse nicht semantisch ändern. Versuche dies:Lass mich wissen, wie es dir geht. Wenn es funktioniert, sollten Sie Ihre ursprüngliche # Event-Tabelle anpassen - es sind keine zwei temporären Tabellen erforderlich, dies war nur für die Perfektion. Übung abstimmen.
Wenn es nicht funktioniert, können wir versuchen, den Prüfstand zu verbessern, um Ihr Setup genauer wiederzugeben. Ich habe einige Experimente mit weniger oder keinen nicht gruppierten Indizes durchgeführt und auch einige gute Ergebnisse erzielt, obwohl sie offensichtlich von anderen Abfragen verwendet werden könnten.
Prüfstand
Update 1: Meinen Sie 22 Millionen Datensätze, die nicht gelesen wurden? Sie haben keine
WHERE
Klauseln, also werden Sie Scans bekommen. Möglicherweise werden Sie nach der äußeren Tabelle eines Joins mit verschachtelten Schleifen suchen, aber die kleinere Tabelle befindet sich zu Recht oben. Ich wäre versucht zu versuchenOPTION ( MERGE JOIN, HASH JOIN )
, verschachtelte Schleifen hier grundsätzlich auszuschließen. Sehen Sie, wie Sie vorankommen. Diese Methode hat auch den zusätzlichen Vorteil, dass die Verknüpfungsreihenfolge nicht erzwungen wird. Ich schlage dies vor, um Informationen zu sammeln, die nicht unbedingt eine Lösung für die Produktion darstellen. Irgendwelche Vorschläge zur Verbesserung des Prüfstands, um Ihr Setup genauer widerzuspiegeln?Wie lange dauern die beiden Abfragen? Sie könnten versuchen, sie durch etwas wie Plan Explorer (kostenlose Version) zu führen, da ich denke, dass dies aufschlussreich sein wird. Ich habe festgestellt, dass in meinem Prüfstand ein Fehler aufgetreten ist, bei dem ich die Indexerstellungszeit in das Timing für den zweiten Prüfstand einbeziehe. Bitte schließen Sie dies aus. Für meine Ergebnisse erhalte ich eine ursprüngliche Abfrage von 15 Sekunden und eine überarbeitete Abfrage von 7 Sekunden:
Update 2: Arbeitete mit OP zusammen, um nicht geclusterte Indizes zu entfernen, Schleifenverbindungshinweise zu entfernen und der temporären Tabelle einen eindeutigen Index hinzuzufügen, um eine Verbesserung von 75 +% zu erzielen. Fantastischer Input und Dank an @PaulWhite.
quelle