Benutzer mit den meisten Antworten
IF EXISTS hohe laufzeit

Frage
-
Hallo Zusammen,
ich hoffe Ihr könnt mir weiterhelfen, denn ich bin mit meinem Latein bei folgendem Problem am Ende...
Hintergrund:
ich übertrage zum archivieren Sätze von einer DB in eine andere, auf physikalisch unterschiedlichen Systemen. Damit im Fehlerfall der Vorgang relativ einfachzurückgefahren werden kann benutze ich im ersten Schritt eine leere Tabelle (tmptbl1) und fülle sie mit zu archivierenden Sätzen. Im Anschluss prüfe ich ob bereits Sätze in der Archivtabelle (tbl1) mit dem gleichen PK vorhanden sind und wähle anhand des Ergebniss das auszuführende SELECT Statement aus, also entweder füge alle ein, oder füge nur die ein die noch nicht da sind.
Da es sich um eine ArchivDB handelt die sich nicht im Userzugriff befindet habe ich keine Indizes oder Ähnliches auf den Tabellen.
Beide Server sind mit SQL 2005 64 BIT Standard Edition ausgestattet.
Statement:
IF NOT EXISTS (SELECT * FROM tmptbl1 INNER JOIN tbl1 ON tmptbl1.PK = tbl1.PK)
BEGIN
INSERT INTO tbl1 SELECT * FROM tmptbl1
END
ELSE
BEGIN
INSERT INTO tbl1 SELECT * FROM tbltbl1 LEFT JOIN tbl1 ON tmptbl1.PK = tbl1.PK WHERE tbl1.PK IS NULL
END
Dieses Statement funktioniert einwandfrei nur bei einem Kunden habe ich jetzt das Problem, dass die Prüfung nicht ausgeführt wird, bzw. nicht zum Ende kommt. Das SELECT selber hat eine Antwortzeit von unter einer Sekunde, solbald aber das IF EXISTS davor steht bekomme ich auch nach einer halben Stunde kein Ergebniss.
Das es an der IF EXISTS Klausel liegt habe ich dadurch verifiziert, dass ich die INSERT Statements durch PRINTS ersetzt habe.
Wärend ich das Statement ausgeführt habe konnte ich keinen IOs auf den HDDs über den Perfmon feststellen nur die Auslastung einer CPU von insgesamt acht geht nach oben.
Was habe ich bereits getan:
1. habe ich nach Locks und ähnlichem geschaut, konnte hier aber nichts feststellen, sicherheitshalber habe ich auch alle Verbindungen getrennt und etwaiige Prozesse geschlossen
2. dann habe ich vermutet, dass es an den Parallelismen liegen könnte, also das ein Statement von mehreren CPUs gleichzeitig abgearbeitet wird die sich dann gegenseitig blockieren, deshalb habe ich serverweit die Option "Max. Grad an Parallelität" von 0 auf 1 gesetzt
4. habe ich den Kompatibilitäts modus von 80 auf 90 umgestellt
5. ein DBCC CheckDB hat auch keine Fehler geliefert
6. dann habe ich das automatische Erstellen und aktualisieren der Statistiken deaktiviert
7. anschliessend aktiviert und die Option asynchrones Aktualisieren der Statistiken dazu genommen.
8. habe ich einen Wartungsplan Optimierungs Task erstellt und laufen lassen mit den Tasks (DB Intigrität prüfen, Indizes neu erstellen und Statistiken aktualisieren)
--> das alles hat keine Besserung gebracht
Natürlich habe ich auch das Statement etwas angepasst z. B.
- über ein TOP 1, was keine Verbesserung brachte
- ein count Verwendet und geprüft ob dieser > 1 ist, was sehr gut funktioniert hat
jedoch möchte ich wenn möglich vermeiden, das Statement anzupassen, da ich das bei einigen Kundenservern nachführen müsste und es ja bisher tadellos funktioniert hat.
Ich hoffe sehr, dassIhr mir weiterhelfen könnt.
Viele Grüsse
Pichel
- Bearbeitet Michel Slotwinski Montag, 18. Mai 2009 17:34 Rechtschreibfehler
Antworten
-
Hallo Zusammen,
das Problem konnte ich folgendermassen lösen: Ich habe die entsprechenden Spalten als PK definiert, was vorher nicht der Fall war. Zwar erklärt dies noch nicht, warum die gleiche SQL unterschiedlich (Ausführungsplan) ausgeführt wurde, aber jetzt läuft es ;-)
Vielen Dank für eure Unterstützung.
Grüsse
Pichel- Bearbeitet Michel Slotwinski Freitag, 29. Mai 2009 08:30 Rechtschreibung
- Als Antwort markiert Michel Slotwinski Freitag, 29. Mai 2009 08:31
Alle Antworten
-
Ueber welche Anzahl von Zeilen in der Archivtabelle reden wir hier? Sollte diese Zahl in die Millionen gehen, kann das bei einer Tabelle ohne Indizes schon mal dauern. Dennoch erscheint mir 30 Minuten deutlich zu lange.
Was war denn dein Ergebnis, als du die INSERTs durch PRINTs ersetzt hast? Wie hast du denn die Locks und Prozesse kontrolliert?
Was ich aber nicht wirklich verstehe, ist deine EXISTS Logik:
IF NOT EXISTS (SELECT * FROM tmptbl1 INNER JOIN tbl1 ON tmptbl1.PK = tbl1.PK) BEGIN INSERT INTO tbl1 SELECT * FROM tmptbl1 END ELSE BEGIN INSERT INTO tbl1 SELECT * FROM tbltbl1 LEFT JOIN tbl1 ON tmptbl1.PK = tbl1.PK WHERE tbl1.PK IS NULL END
Falls keine Uebereinstimmung existiert, füge alles ein, ansonsten nur die, die noch nicht existieren. Warum machst du das nicht gleich so in einem einzigen kombinierten Statement?
INSERT INTO tbl1 SELECT * FROM tbltbl1 LEFT JOIN tbl1 ON tmptbl1.PK = tbl1.PK WHERE tbl1.PK IS NULL
erfüllt genau diesen Zweck. Oder:
INSERT INTO tbl1 SELECT T.* FROM dbo.tmptbl1 T WHERE NOT EXISTS (SELECT 1 FROM dbo.tbl1 T2 WHERE T.PK = T2.PK);
-- Frank Kalis Microsoft SQL Server MVP Webmaster: http://www.insidesql.org- Bearbeitet Frank Kalis Dienstag, 19. Mai 2009 06:48 Layout, die 2.te
-
Hi Frank,
Vielen Dank für Deine Antwort. Die Anzahl der Sätze beläuft sich im Schnitt auf 20000. Ein Ergebniss habe ich keines erhalten, da ich das Statement vorher abgebrochen habe. Im Aktivitätsmonitor kann ich wärend der Ausführung nicht viel erkennen, die Tabelle tbl1 wird gelockt, dazu noch interne Objekte, jedoch kann ich nicht erkennen, dass auch die Tabelle tmptbl1 gelockt wird, was meines Erachtens eigentlich geschehen sollte.
Der springende Punkt ist, dass das SELECT was zur Prüfung herangezogen wird allein ausgeführt eine Antwortzeit von weniger als einer Sekunde hat und das obwohl keine Indizes vorhanden sind. Sobald ich aber ein IF EXISTS oder ein IF NOT EXISTS davor setze scheint es so, dass kein Ausführungsplan erstellt wird.
zur Logik: ein INSERT INTO sollte eigentlich ohne WHERE Klausel deutlich schneller sein, gerade wenn keine Indizes vorhanden sind und in 90 % der Fälle ist es auch der Fall, dass ich diesen verwenden kann. In den übrigen 10 % der Fälle dürfen nur die Sätze eingefügt werden die noch nicht vorhanden sind, damit Redundanzen vermieden werden.
Grüsse
Pichel -
Bei gerade mal 20.000 Zeilen sollte das eigentlich binnen kürzester Zeit abgearbeitet sein. Die einzigen Locks die auch tmptbl1 zu sehen sein sollten, sind Shared Locks, da von dieser Tabelle nur gelesen wird. Kannst du mal den "Estimated Execution Plan" posten?
-- Frank Kalis Microsoft SQL Server MVP Webmaster: http://www.insidesql.org -
Das mit dem File kann ich Dir leider auch nicht sagen, aber Du kannst auch den Ausführungsplan in Textform ausgeben lassen und den dann (evtl. als Codeblock) posten.
Welchen ServicePack-Stand hat eigentlich die Datenbank ?
Einen schönen Tag noch, Christoph Muthmann SQLServer MVP -
Hallo Zusammen,
das Problem konnte ich folgendermassen lösen: Ich habe die entsprechenden Spalten als PK definiert, was vorher nicht der Fall war. Zwar erklärt dies noch nicht, warum die gleiche SQL unterschiedlich (Ausführungsplan) ausgeführt wurde, aber jetzt läuft es ;-)
Vielen Dank für eure Unterstützung.
Grüsse
Pichel- Bearbeitet Michel Slotwinski Freitag, 29. Mai 2009 08:30 Rechtschreibung
- Als Antwort markiert Michel Slotwinski Freitag, 29. Mai 2009 08:31
-
Hallo Zusammen,
das Problem konnte ich folgendermassen lösen: Ich habe die entsprechenden Spalten als PK definiert, was vorher nicht der Fall war. Zwar erklärt dies noch nicht, warum die gleiche SQL unterschiedlich (Ausführungsplan) ausgeführt wurde, aber jetzt läuft es ;-)
Vielen Dank für eure Unterstützung.
Grüsse
Pichel
Doch, genau das ist die Erklärung!
Viele Grüße
Christoph