2016-08-11 3 views
0

Wir haben eine langsame Abfrage in unserem Altsystem gefunden. Was ich in der Abfrage sehe, ist ein doppeltes Fragment. Hier ist die vollständige Abfrage:Abfrageoptimierung. Doppelte Unterabfragen

DECLARE @SellerId INT; 
DECLARE @DateFrom DATETIME; 
DECLARE @DateTo DATETIME; 

SET @SellerId = 5396884; 
SET @DateFrom = '2016-01-05'; 
SET @DateTo = '2016-10-08'; 

DECLARE @CurrentDate DATETIME; 
SET @CurrentDate = GETDATE(); 



CREATE TABLE #ReportDate (codes INT, dates DATETIME); 
DECLARE @dif as INT; 
DECLARE @cont as INT; 
DECLARE @currdate as DATETIME; 
SET @dif = DATEDIFF(day, @DateFrom, @DateTo); 
SET @cont = 1; 
SET @currdate = @DateFrom - 1; 
WHILE (@cont <= @dif + 1) 
BEGIN 
    SET @currdate = DATEADD(DAY, 1, @currdate); 
    INSERT INTO #ReportDate VALUES (@cont, @currdate); 
    SET @cont = @cont + 1; 
END 


/* HOW TO OPTIMIZE THIS ONE? */ 
SELECT 
     #ReportDate.dates as valid_date, 
     (
      SELECT 

      COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives 

      FROM  
       (

        SELECT * 

        FROM salesView 

        WHERE 

         salesView.sell_id NOT IN 
          (
           SELECT sell_id 

           FROM salesStates 

           WHERE 
            salesStates.aborted = 1 
          ) 

       ) nonCancelledSales 

      WHERE 
       nonCancelledSales.seller_id = @SellerId AND 
       nonCancelledSales.cancelled = 0 AND 
       nonCancelledSales.void = 0 AND 
       nonCancelledSales.hasDiscount = 0 AND 
       nonCancelledSales.dateOfSale <= #ReportDate.dates AND 
       nonCancelledSales.currentState = (SELECT MAX(hveest.date) 

               FROM salesStates hveest 

               WHERE 
                hveest.sell_id = nonCancelledSales.sell_id AND 
                hveest.date <= #ReportDate.dates) AND 
       nonCancelledSales.lastProductDate = (SELECT  MAX(hvepro.date) 

               FROM productHistory hvepro 

               WHERE 
                hvepro.sell_id = nonCancelledSales.sell_id AND 
                hvepro.date <= #ReportDate.dates) 

     ) total_actives, 

     (
      SELECT 

      ISNULL(SUM(nonCancelledSales.paymentValue),0) as active 

      FROM  
       (

        SELECT * 

        FROM salesView 

        WHERE 

         salesView.sell_id NOT IN 
          (
           SELECT sell_id 

           FROM salesStates 

           WHERE 
            salesStates.aborted = 1 
          ) 

       ) nonCancelledSales 

      WHERE 
       nonCancelledSales.seller_id = @SellerId AND 
       nonCancelledSales.cancelled = 0 AND 
       nonCancelledSales.void = 0 AND 
       nonCancelledSales.hasDiscount = 0 AND 
       nonCancelledSales.dateOfSale <= #ReportDate.dates AND 
       nonCancelledSales.currentState = (SELECT MAX(hveest.date) 

               FROM salesStates hveest 

               WHERE 
                hveest.sell_id = nonCancelledSales.sell_id AND 
                hveest.date <= #ReportDate.dates) AND 
       nonCancelledSales.lastProductDate = (SELECT  MAX(hvepro.date) 

               FROM productHistory hvepro 

               WHERE 
                hvepro.sell_id = nonCancelledSales.sell_id AND 
                hvepro.date <= #ReportDate.dates)    
     ) active 
FROM 
     #ReportDate 
GROUP BY 
     #ReportDate.dates 



DROP TABLE #ReportDate 

Hier sind die beiden duplizierten Fragmente ich sehe:

(
      SELECT 

      COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives 

      FROM  
       (

        SELECT * 

        FROM salesView 

        WHERE 

         salesView.sell_id NOT IN 
          (
           SELECT sell_id 

           FROM salesStates 

           WHERE 
            salesStates.aborted = 1 
          ) 

       ) nonCancelledSales 

      WHERE 
       nonCancelledSales.seller_id = @SellerId AND 
       nonCancelledSales.cancelled = 0 AND 
       nonCancelledSales.void = 0 AND 
       nonCancelledSales.hasDiscount = 0 AND 
       nonCancelledSales.dateOfSale <= #ReportDate.dates AND 
       nonCancelledSales.currentState = (SELECT MAX(hveest.date) 

               FROM salesStates hveest 

               WHERE 
                hveest.sell_id = nonCancelledSales.sell_id AND 
                hveest.date <= #ReportDate.dates) AND 
       nonCancelledSales.lastProductDate = (SELECT  MAX(hvepro.date) 

               FROM productHistory hvepro 

               WHERE 
                hvepro.sell_id = nonCancelledSales.sell_id AND 
                hvepro.date <= #ReportDate.dates) 

     ) total_actives, 

     (
      SELECT 

      ISNULL(SUM(nonCancelledSales.paymentValue),0) as active 

      FROM  
       (

        SELECT * 

        FROM salesView 

        WHERE 

         salesView.sell_id NOT IN 
          (
           SELECT sell_id 

           FROM salesStates 

           WHERE 
            salesStates.aborted = 1 
          ) 

       ) nonCancelledSales 

      WHERE 
       nonCancelledSales.seller_id = @SellerId AND 
       nonCancelledSales.cancelled = 0 AND 
       nonCancelledSales.void = 0 AND 
       nonCancelledSales.hasDiscount = 0 AND 
       nonCancelledSales.dateOfSale <= #ReportDate.dates AND 
       nonCancelledSales.currentState = (SELECT MAX(hveest.date) 

               FROM salesStates hveest 

               WHERE 
                hveest.sell_id = nonCancelledSales.sell_id AND 
                hveest.date <= #ReportDate.dates) AND 
       nonCancelledSales.lastProductDate = (SELECT  MAX(hvepro.date) 

               FROM productHistory hvepro 

               WHERE 
                hvepro.sell_id = nonCancelledSales.sell_id AND 
                hvepro.date <= #ReportDate.dates)    
     ) active 

Ist es völlig notwendig, um die Abfrage zu duplizieren? Er ist in dem ersten bekommen:

COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives 

auf dem zweiten:

ISNULL(SUM(nonCancelledSales.paymentValue),0) as active 

Ich nehme an, es hat eine Möglichkeit, um die Abfrage neu zu schreiben, aber ich bin nicht sicher, wie.

+0

sieht aus wie es war eine einzige Abfrage auf einmal, die würde erklären die 'GROUP BY # ReportDate.dates' – JamieD77

+0

Sie könnten auch beschleunigen, indem Sie diese Schleife und stattdessen eine Tally-Tabelle verwenden, um Ihre Liste der Daten zu füllen. Dies ist wahrscheinlich nicht der schlechteste Teil der Leistung, aber es ist super einfach, dieses Set basierend auf einer Schleife zu erstellen. Hier ist ein großer Artikel, der Tally-Tabellen erklärt und wie sie Loops ersetzen können. http://www.sqlservercentral.com/articles/T-SQL/62867/ –

+0

@ JamieD77 sagst du die Gruppe von ist überflüssig? –

Antwort

0

Sie können diese kombinieren, wenn Sie OUTER APPLY verwenden.

Die Idee ist:

SELECT . . ., x.actives, x.active 
FROM #ReportDate OUTER APPLY 
    (SELECT COUNT(DISTINCT(nonCancelledSales.num_remito)) as actives, 
      COALESCE(SUM(nonCancelledSales.paymentValue), 0) as active 
     . . . -- rest of query here 
    ) x; 

In diesem Fall OUTER APPLY ist ein viel wie eine korrelierte Unterabfrage in der FROM Klausel, die mehrere Zeilen zurückgeben kann.

+0

Verwenden OUTER APPLY ist also die einzige und beste Möglichkeit, diese Abfrage neu zu schreiben? Ich dachte, äußere Anwendung war für Tabellenwerte Funktionen –

+0

@ StephenH.Anderson. . . Es ist der naheliegendste Weg, die Logik zu schreiben. Eine Unterabfrage kann nur einen Wert zurückgeben, sodass dieses Problem umgangen wird. Ich verstehe die Logik nicht, also könnte es einen Weg geben, es einfacher zu schreiben. Aber "APPLY" implementiert einen sogenannten "lateralen Join". Tabellenwertefunktionen sind nur eine Anwendung. –