2016-08-16 2 views
5

Ich habe eine gespeicherte Prozedur, die Daten aus 2 verschiedenen Quellen abrufen kann, abhängig davon, ob der Benutzer Daten aus einem einzelnen geschlossenen Zeitraum (archiviert in eine Data Warehouse-Tabelle) oder aus einem offenen Zeitraum (Daten aus der Transaktion) anfordert Tabellen).SQL IF ELSE Leistungsproblem

Wenn ich Parameter übergebe, die die Auswahl auf die Data-Warehouse-Tabelle beschränken (ein Jahr und einen Zeitraum für eine geschlossene Periode), dauert die Prozedur sehr lange, bis der ELSE BEGIN ...-Code auskommentiert wird. Es kommen keine Daten aus dem ELSE-Teil des Codes, aber es verlangsamt immer noch die Prozedur. Wenn ich den ELSE-Teil des Codes ausdekomme, ist es sehr schnell.

Ich habe versucht OPTION (RECOMPILE) und ich benutze lokale Variablen, um zu vermeiden, Parameter Sniffing, aber es hilft nicht. Gibt es eine Möglichkeit, dies zu umgehen? Das Folgende ist ein Beispiel dafür, was ich so langsam läuft tun:

IF @Year <> 0 AND @Period <> 0 AND (SELECT PerClosedTimestamp 
            FROM Period 
            WHERE 
             PerCompanyID = @CompanyID AND 
             PerYear = @Year AND 
             PerPeriod = @Period) IS NOT NULL 
BEGIN 
    SELECT 
     datawhse.column1, datawhse.column2, etc … 
    FROM  
     datawhse   
END 
ELSE 
BEGIN 
    SELECT 
     trantable.column1, trantable.column2, etc… 
    FROM  
     trantable  
END 

Wenn ich die ELSE-Anweisung es läuft sehr schnell ausschließen:

IF @Year <> 0 
    AND @Period <> 0 
    AND (SELECT PerClosedTimestamp 
     FROM Period 
     WHERE PerCompanyID = @CompanyID 
      AND PerYear = @Year 
      AND PerPeriod = @Period) IS NOT NULL 
BEGIN 
    SELECT datawhse.column1 
      ,datawhse.column2, etc … 
    FROM datawhse   
END 
+0

Keine Antwort, aber eine interessante und verwandte (nicht doppelte) Post http://dba.stackexchange.com/questions/9835/using-if-in-t-sql-weakens-oder-breaks-execution-plan- Caching – scsimon

+0

Was passiert, wenn Sie TOP 1 vor "PerClosedTimestamp" hinzufügen oder EXISTS verwenden? Versuchen Sie auch, die Bedingungen zu ändern, wenn Jahr = 0 oder Periode = 0 oder (wählen Sie ...) Null ist, dann machen Sie den zweiten Block, ELSE macht den ersten. Versuchen Sie auch, "WHERE Year = 0 oder Period = 0" (durch Dublierbedingung) in den zweiten Block zu schreiben. – Anton

+2

Es wäre nett, Abfragepläne für langsame und schnelle Ausführungen zu sehen. –

Antwort

0

Sind @year und @Period von der direkt Eingabe der gespeicherten Prozedur? Wie hast du in deiner Sproc-Definition auf diese Weise geschrieben?

Sie können versuchen, lokale Variable verwenden, nach meiner Erfahrung in vielen Fällen wie diese, lokale Variablen helfen sehr.

create proc USP_name @Year int, @Period int as 
begin 
    declare @Year_local int, @Period_local int 
    set @Year_local = @Year, @Period_local = @period 

    if @Year_local <> 0 AND @Period_local <> 0 AND ... 
    .... 
end 
+0

Vielen Dank für Ihre Anregungen. Am Ende habe ich zwei separate Funktionen erstellt, um Daten aus der Data-Warehouse-Tabelle oder den Transaktionstabellen zurückzugeben. Ich wähle aus den Funktionen in der IF THEN ELSE-Anweisung und das scheint mein Problem gelöst zu haben. – gcresse

1

Wie in den Kommentaren erwähnt, ist die endgültige Antwort auf warum es langsam immer in der Abfrage-Plan werden soll, gefunden.

Bei einer Schätzung das Aussehen von trantable in der Prozedur den Abfrageoptimierer auf eine Weise vorbelastet, die datawhse nicht favorisiert. Ich würde zumindest zu versuchen versucht UNION ALL statt IF/THEN, etwas entlang der Linien von

SELECT 
    datawhse.column1, datawhse.column2, etc … 
FROM  
    datawhse 
WHERE @Year <> 0 AND @Period <> 0 AND (SELECT PerClosedTimestamp 
           FROM Period 
           WHERE 
            PerCompanyID = @CompanyID AND 
            PerYear = @Year AND 
            PerPeriod = @Period) IS NOT NULL 
UNION ALL 
SELECT 
    trantable.column1, trantable.column2, etc… 
FROM  
    trantable  
WHERE @Year = 0 OR @Period = 0 OR (SELECT PerClosedTimestamp 
           FROM Period 
           WHERE 
            PerCompanyID = @CompanyID AND 
            PerYear = @Year AND 
            PerPeriod = @Period) IS NULL 

Es wäre interessant zu sehen, wie die Abfragepläne vergleichen.

0

Vielen Dank für Ihre Vorschläge. Am Ende habe ich zwei separate Funktionen erstellt, um Daten aus der Data-Warehouse-Tabelle oder den Transaktionstabellen zurückzugeben. Ich wähle aus den Funktionen in der IF THEN ELSE-Anweisung und das scheint mein Problem gelöst zu haben.