2008-11-25 4 views
6

Ich habe eine Tabelle mit fast 800.000 Datensätze und ich verwende derzeit dynamische SQL, um die Abfrage auf dem Back-End zu generieren. Das Frontend ist eine Suchseite, die ungefähr 20 Parameter benötigt und abhängig davon, ob ein Parameter ausgewählt wurde, fügt sie der Basisabfrage ein "AND ..." hinzu. Ich bin gespannt, ob dynamic sql der richtige Weg ist (scheint nicht so, weil es langsam läuft). Ich überlege mir gerade, eine denormalisierte Tabelle mit all meinen Daten zu erstellen. Ist das eine gute Idee oder sollte ich nur die Abfrage alle zusammen bauen, anstatt es Stück für Stück mit dem dynamischen SQL zu bauen. Letzte Sache, gibt es eine Möglichkeit, dynamische SQL zu beschleunigen?Ist eine dynamische gespeicherte SQL-Prozedur eine schlechte Sache für viele Datensätze?

+0

Wenn Sie Ihre endgültige Lösung kommen, lassen Sie es uns wissen, und ich werde meine Antwort aktualisieren, um sicherzustellen, die Techniken/Fehlersuche wir haben besprochen, dass gearbeitet wird klar gemacht. –

Antwort

10

Es ist wahrscheinlicher, dass Ihre Indizierung (oder deren Fehlen) die Langsamkeit verursacht als die dynamische SQL.

Wie sieht der Ausführungsplan aus? Ist dieselbe Abfrage langsam, wenn sie in SSMS ausgeführt wird? Was ist, wenn es in einer gespeicherten Prozedur ist? Wenn Ihre Tabelle ein nicht indizierter Heap ist, wird sie mit zunehmender Anzahl von Datensätzen nicht ordnungsgemäß ausgeführt. Dies ist unabhängig von der Abfrage. Eine dynamische Abfrage kann tatsächlich bessere Ergebnisse liefern, wenn sich die Tabellennatur ändert, weil eine dynamische Abfrage wahrscheinlicher ist wenn der Abfrageplan erneut ausgewertet wird, wenn er nicht im Cache ist. Dies ist normalerweise kein Problem (und ich würde es nicht als einen Konstruktionsvorteil dynamischer Abfragen klassifizieren), außer in den frühen Phasen eines Systems, wenn SPs nicht neu kompiliert wurden, aber Statistiken und Abfragepläne veraltet sind, aber das Volumen von Daten haben sich gerade drastisch geändert.

Nicht die statische noch. Ich habe mit der dynamischen Abfrage, aber es gibt keine Optimierungen. Wenn ich es mit der statischen Abfrage ausführen würde und Vorschläge machen würde, würde sich ihre Anwendung auf die dynamische Abfrage auswirken? - Xaisoft (vor 41 Minuten)

Ja, die dynamische Abfrage (EXEC (@sql)) wird wahrscheinlich erst analysiert, wenn Sie eine Auslastungsdatei analysiert haben. - Cade Roux (vor 33 Minuten)

Wenn Sie eine Suchanfrage über mehrere verknüpfte Tabellen haben, müssen die Spalten mit Indizes sowohl die Suchspalten als auch die Primärschlüssel-/Fremdschlüsselspalten sein - aber es hängt davon ab die Kardinalität der verschiedenen Tabellen. Der Tuning-Analysator sollte dies zeigen. - Cade Roux (22 Minuten vorbei)

+0

Dynamische Abfrage in dem gespeicherten Proc scheint tatsächlich schneller als eine nicht dynamische Abfrage in dem gespeicherten Proc auszuführen. Der Ausführungsplan für beide sieht gleich aus. – Xaisoft

+0

Verwendet es irgendwelche Indizes? Was sind Ihre Kriterien für die Bestimmung der Langsamkeit - im Vergleich zu was? –

+0

Ja, alles was Spalten hat, an denen ich mich beteilige, hat Indizes. Ich führe nur den statischen proc und den dynamischen proc in ssms aus und prüfe die Zeit, die es brauchte, um alle Ergebnisse zurückzugeben (23 Sekunden für die dynamische und 45 Sekunden für die statische) – Xaisoft

2

Wenn die Parameter optional sind, ein Trick, der oft benutzt, um ist, ein Verfahren wie diese zu erstellen:

CREATE PROCEDURE GetArticlesByAuthor (
    @AuthorId int, 
    @EarliestDate datetime = Null) 
AS 
    SELECT * --not in production code! 
    FROM Articles 
    WHERE AuthorId = @AuthorId 
    AND (@EarliestDate is Null OR PublishedDate < @EarliestDate) 
+0

Alle Parameter sind optional. Wie hilft das bei der Optimierung? – Xaisoft

3

Der einzige Unterschied zwischen „dynamisch“ und „statisch“ SQL ist die Parsing/Optimierungsphase. Sobald diese abgeschlossen sind, wird die Abfrage identisch ausgeführt.

Für einfache Abfragen stellt diese Parsing-Phase zusammen mit dem Netzwerkverkehr einen erheblichen Prozentsatz der gesamten Transaktionszeit dar. Es empfiehlt sich daher, diese Zeiten zu reduzieren.

Bei großen, komplizierten Abfragen ist diese Verarbeitung jedoch insgesamt unbedeutend im Vergleich zum tatsächlichen vom Optimierer gewählten Pfad.

Ich würde mich auf die Optimierung der Abfrage selbst konzentrieren, einschließlich der Denormalisierung, wenn Sie das Gefühl haben, dass es angemessen ist, obwohl ich das nicht auf Anhieb machen würde.

Manchmal kann die Denormalisierung zu "Laufzeit" in der Anwendung durchgeführt werden, indem beispielsweise zwischengespeicherte Nachschlagetabellen verwendet werden, anstatt diese Datenbank beizubehalten.

4

Als vorherige Antwort, überprüfen Sie Ihre Indizes und planen.

Die Frage ist, ob Sie eine gespeicherte Prozedur verwenden. Es ist nicht offensichtlich aus der Art, wie du es formuliert hast. Eine gespeicherte Prozedur erstellt bei der Ausführung einen Abfrageplan und behält diesen bis zur Neukompilierung bei. Mit variierendem SQL sind Sie möglicherweise mit einem fehlerhaften Abfrageplan festgefahren. Sie könnten verschiedene Dinge tun:

1) Fügen Sie WITH RECOMPILE zur SP-Definition hinzu, wodurch bei jeder Ausführung ein neuer Plan generiert wird. Dies beinhaltet einige Gemeinkosten, die akzeptabel sein können.

2) Verwenden Sie separate SPs, abhängig von den zur Verfügung gestellten Parametern. Dies ermöglicht eine bessere Zwischenspeicherung des Abfrageplans

3) Verwenden Sie vom Client generierte SQL. Dies erstellt jedes Mal einen Abfrageplan. Wenn Sie parametrisierte Abfragen verwenden, können Sie möglicherweise zwischengespeicherte Abfragepläne verwenden.

1

Wie bereits erwähnt, wenn Sie eine massive Abfrage tun, sind Indizes der erste Engpass zu betrachten. Stellen Sie sicher, dass stark abgefragte Spalten indiziert sind. Stellen Sie außerdem sicher, dass Ihre Abfrage alle indizierten Parameter überprüft, bevor sie nicht indizierte Parameter überprüft. Dadurch wird sichergestellt, dass die Ergebnisse zuerst mithilfe von Indizes gefiltert werden und die langsame lineare Suche nur dann ausgeführt wird, wenn dies erforderlich ist. Also, wenn col2 indiziert ist aber col1 ist nicht, es sollte wie folgt aussehen:

WHERE col2 = @col2 AND col1 = @col1 

Sie könnten versucht sein, mit Indizes über Bord zu gehen als gut, aber bedenken Sie, dass zu viele Indizes können langsam schreiben und massive Scheibe verursachen Nutzung, also geh nicht zu verrückt.

Ich vermeide dynamische Abfragen, wenn ich aus zwei Gründen kann. Erstens speichern sie den Abfrageplan nicht, daher wird die Anweisung jedes Mal kompiliert. Der andere ist, dass sie schwer zu manipulieren, zu testen und zu beheben sind. (Sie sehen nur hässlich aus).

Ich mag Dave Kemp's answer oben.

5

Ich würde nur, dass darauf hinweisen, wenn Sie diese Art der optionalen Parameter verwenden:

AND (@EarliestDate is Null OR PublishedDate < @EarliestDate) 

Der Abfrageoptimierer keine Ahnung, ob der Parameter gibt es haben wird oder nicht, wenn es um den Plan Abfrage erstellt. Ich habe Fälle gesehen, in denen der Optimierer in diesen Fällen schlechte Entscheidungen trifft. Eine bessere Lösung ist das Erstellen der SQL, die nur die Parameter verwendet, die Sie benötigen. Der Optimierer wird in diesen Fällen den effizientesten Ausführungsplan erstellen. Stellen Sie sicher, dass Sie parametrisierte Abfragen verwenden, damit sie im Plancache wiederverwendbar sind.

3

Ich bin kein Fan von dynamischen Sql, aber wenn Sie mit ihm stecken, sollten Sie wahrscheinlich diesen Artikel lesen: http://www.sommarskog.se/dynamic_sql.html Er geht wirklich in die Tiefe zu den besten Möglichkeiten dynamische SQL und die isues zu verwenden, indem es schaffen können.

Wie andere gesagt haben, ist Indexierung der wahrscheinlichste Schuldige. Bei der Indexierung vergessen die Leute oft, die FK-Felder zu indexieren. Da ein PK automatisch einen Index erstellt, gehen viele davon aus, dass dies auch ein FK sein wird. Leider erzeugt das Erstellen eines FK keinen Index. Stellen Sie daher sicher, dass alle Felder, an denen Sie teilnehmen, indiziert sind.

Möglicherweise gibt es bessere Möglichkeiten, um Ihr dynamisches SQL zu erstellen, aber ohne den Code zu sehen, ist es schwer zu sagen. Ich würde zumindest sehen, ob es Unterabfragen verwendet und sie stattdessen durch abgeleitete Tabellenjoins ersetzt. Auch jede dynamische SQl, die einen Cursor verwendet, muss langsam sein.

0

ich einen gewissen Erfolg gehabt haben (in einer begrenzten Anzahl von Fällen) mit der folgenden Logik:

CREATE PROCEDURE GetArticlesByAuthor ( 
    @AuthorId int,  
    @EarliestDate datetime = Null 
    ) AS 

SELECT SomeColumn 
FROM Articles 
WHERE AuthorId = @AuthorId 
AND @EarliestDate is Null 
UNION 
SELECT SomeColumn 
FROM Articles 
WHERE AuthorId = @AuthorId 
AND PublishedDate < @EarliestDate 
+0

Welche Frage beantworten Sie? – Dave

+0

Ich verwende dies, um dynamische SQL zu eliminieren und 2 Abfragepläne auf Anweisungsebene zu verwenden. Wie bereits erwähnt, kann das Ausführen von "UND (@EarliestDate ist Null OR PublishedDate <@EarliestDate)" SQL Server verwechseln und einen nicht optimalen Plan generieren. Mithilfe einer Union kann SQL einen geeigneten Plan für jede Bedingung auswählen, ohne OPTION (RECOMPILE) zu verwenden. – Jeremy

0

Wenn Sie unter den 1s Bereich zu optimieren versuchen, kann es wichtig sein, zu beurteilen, wie etwa lange es dauert, zu analysieren und den dynamischen SQL-in Bezug auf die tatsächliche Abfrageausführungszeit zu kompilieren:

SET STATISTICS TIME ON; 

und führen sie dann die dynamische SQL-Zeichenfolge „statisch“ und überprüfen sie die Register „Nachrichten“. Ich wurde von diesen Ergebnissen überrascht für eine ~ 10 Linie dynamische SQL-Abfrage, die zwei Zeilen aus einer 1M Reihe Tabelle zurück:

SQL Server parse and compile time: 
    CPU time = 199 ms, elapsed time = 199 ms. 

(2 row(s) affected) 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 4 ms. 

Index Optimierung wird mißtrauisch die 199ms Barriere bewegen viel (außer vielleicht aufgrund einiger analyzation/Optimierung einbezogen innerhalb der Kompilierzeit).

Wenn jedoch das dynamische SQL Parameter verwendet oder sich wiederholt, können die Kompilierungsergebnisse nach folgendem Code zwischengespeichert werden: See Caching Query Plans, wodurch die Kompilierzeit entfallen würde. Wäre interessant zu wissen, wie lange Cache-Einträge leben, Größe, geteilt zwischen Sitzungen usw.

Verwandte Themen