2016-08-16 30 views
5

Mam procedura składowana, która może uzyskać dane z 2 różnych źródeł w zależności od tego, czy użytkownik żąda danych z jednego zamkniętego okresu (zarchiwizowane w tabeli hurtowni danych) lub z okresu otwartego (dane z transakcji tabele).SQL IF Wydanie wydajności ELSE

Jeśli przekazuję parametry, które ograniczają wybór do tabeli hurtowni danych (podając rok i okres dla okresu zamkniętego), procedura zwraca bardzo dużo czasu, chyba że skomentuję kod ELSE BEGIN .... Żadne dane nie pochodzą z części kodu ELSE, ale nadal spowalnia procedurę. Jeśli skomentuję część kodu ELSE, jest ona bardzo szybka.

Próbowałem OPTION (RECOMPILE) i używam zmiennych lokalnych, aby uniknąć sniffing parametru, ale to nie pomaga. Czy istnieje sposób na obejście tego? Poniżej jest przykład tego, co robię, że działa wolno:

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 

Gdybym wyklucza instrukcja else biegnie bardzo szybko:

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

Nie jest to odpowiedź, ale interesujący i powiązany (nie duplikat) post http://dba.stackexchange.com/questions/9835/using-if-in-t-sql-weakens-or-breaks-execution-plan- buforowanie – scsimon

+0

co, jeśli dodasz TOP 1 przed "PerClosedTimestamp" lub użyjesz EXISTS. Spróbuj również zmienić warunki na IF Rok = 0 lub Okres = 0 lub (wybierz ...) jest pusty, następnie wykonaj drugi blok, ELSE wykonaj pierwszy. Spróbuj również umieścić "WHERE Year = 0 or Period = 0" (przez powielenie warunku) w drugim bloku. – Anton

+2

Byłoby miło zobaczyć plany zapytań dla powolnych i szybkich egzekucji. –

Odpowiedz

0

Czy @Year i @Period bezpośrednio z wejście procedury składowanej? jak w twojej definicji sprocera, czy pisałeś w ten sposób?

create proc USP_name @Year int, @Period int as 
begin 
    ... 
end 

Możesz spróbować użyć zmiennej lokalnej, zgodnie z moim doświadczeniem w wielu takich przypadkach, zmienne lokalne bardzo pomóc.

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

Dziękuję wszystkim za sugestie. W efekcie powstały dwie osobne funkcje do zwracania danych z tabeli hurtowni danych lub tabel transakcji. Wybieram funkcje z instrukcji IF THEN ELSE i wydaje się, że rozwiązałem mój problem. – gcresse

1

Jak wspomniano w komentarzach, ostateczna odpowiedź na dlaczego jest tak powolny zawsze można znaleźć w planie zapytania.

W tym przypadku pojawienie się w procedurze trantable przesuwa optymalizator zapytania w sposób, który nie odpowiada datawhse. Byłbym skłonny do przynajmniej spróbować UNION ALL zamiast IF/THEN, coś wzdłuż linii

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 

Byłoby interesujące zobaczyć, jak plany zapytań porównać.

0

Dziękuję wszystkim za sugestie. W efekcie powstały dwie osobne funkcje do zwracania danych z tabeli hurtowni danych lub tabel transakcji. Wybieram funkcje z instrukcji IF THEN ELSE i wydaje się, że rozwiązałem mój problem.