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
FROM #Event AS e INNER LOOP JOIN EFT.AssetState AS ast
, können Sie auch einen Abfragehinweis verwenden OPTION (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ände if exists (select .. some criteria = true) then update else do nothing
zusammen mit Stapelaktualisierungen überprüfen .
OPTION (MERGE JOIN, HASH JOIN)
gleichzeitig? Hast du es versucht OPTION (LOOP JOIN, QUERYTRACEON 8649, QUERYTRACEON 4199);
?
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 :-)