3 Stimmen

Kumulative Tages-Summe für denselben Tag oder vor dem aktuellen Datensatz im Datumfeld in SQL

Wichtig: Ich benötige, dass dies mit SQL Server 2000 kompatibel ist.

Ich brauche eine kumulative Summe, aber basierend auf dem aktuellen Datum, eine Update-Abfrage wie die, die ich derzeit verwende, funktioniert, aber sie ist furchtbar langsam (hässlicher impliziter RBAR-Dreiecksjoin):

UPDATE #RPT 
SET DailySumAccum = 
      (SELECT SUM(COALESCE(CTACTE2.Amount,0))
       FROM #RPT_CTACTE CTACTE2
       WHERE CTACTE2.IsAvailable = #RPT_CTACTE.IsAvailable 
         AND CTACTE2.CodCustomer = #RPT_CTACTE.CodCustomer  
         AND CTACTE2.ItemType = #RPT_CTACTE.ItemType  
         AND CTACTE2.CodItem = #RPT_CTACTE.CodItem 
         AND EsCtaCorrienteMon = -1 
         AND DATEDIFF(day, CTACTE2.OrderDate, #RPT_CTACTE.OrderDate) >= 0) 
WHERE #RPT_CTACTE.EsSaldoAnterior = 0
  AND EsCtaCorrienteMon = -1

Ich habe auch versucht, die Methode mit dem Cursor für kumulative Summen zu verwenden, aber ich kann das RBAR-Problem nicht lösen, die Datumsvergleiche sind immer noch da und es ist immer noch furchtbar langsam:

-- das ist im Cursor

IF (@EsCtaCorrienteMon = -1)
BEGIN
    SELECT @NetoDiarioAcum = SUM(COALESCE(Amount,0))
    FROM #RPT_CTACTE
    WHERE IsAvailable = @IsAvailable
          AND CodCustomer = @CodCustomer
          AND ItemType = @ItemType
          AND CodItem = @CodItem
          AND EsCtaCorrienteMon = -1
          AND DATEDIFF(day, OrderDate, @OrderDate) >= 0
END IF

Das Problem bei dieser kumulativen Summe ist der Datumsvergleich, der die Abfrage sehr langsam macht (nachdem der Code 10 Minuten lang ausgeführt wurde, dauert es nur 3 Sekunden, wenn ich das Update des Cursors auskommentiere), die Anzahl der Zeilen, die ich getestet habe, beträgt 28K, es scheint, dass die benötigte Zeit exponentiell ansteigt, wenn die Anzahl der Datensätze zunimmt, daher gehe ich davon aus, dass hier ein RBAR-Prozess stattfindet (was "Row-By-Agonizing-Row" bedeutet).

EDIT: Nach einigen Tests sieht es so aus, als ob das Datum nicht das einzige Problem ist, gibt es eine Möglichkeit, diese laufende Summe nur zu berechnen, indem man eine Variable innerhalb eines Cursors addiert oder so etwas?

EDIT2: Ich suche derzeit nach einer Möglichkeit, das zu tun, was das erste Update macht (eine laufende Summe basierend auf 4 Feldern und Datum), aber schneller, gestern war ich nah dran, die Logik manuell in einen Cursor einzufügen, aber der Cursor wurde zu groß und schwer zu pflegen, welche Laufende-Summen-Technik ist in diesem Fall am besten (schneller)? Und wie würden Sie diese Technik hier implementieren? Es handelt sich nicht um eine einfache laufende Summe, Schnitte sollten gemacht werden, wenn sich eines dieser Felder ändert. Das Feld EsSaldoAnterior kann nur 0 oder -1 sein, das Update betrifft nur die äußere Tabelle, wenn dieses Feld 0 ist, aber die inneren laufenden Summen summieren sich auch, wenn dieses Feld -1 ist. EsSaldoAnterior bedeutet so etwas wie "Sein Vorheriger Betrag" und es bedeutet, dass die laufenden Summen nicht bei null beginnen sollten, sie sollten diese Beträge zuerst summieren (wenn sie existieren), dies ist die Reihenfolge bei Verwendung von ORDER BY:

ORDER BY IsAvailable, CodCustomer, ItemType, CodItem, OrderDate, EsSaldoAnterior

3voto

valex Punkte 23916

Versuchen Sie, zu ändern

UND DATEDIFF(Tag, CTACTE2.Bestelldatum, #RPT_CTACTE.Bestelldatum) >= 0) 

zu

CTACTE2.Bestelldatum


oder

    CTACTE2.Bestelldatum

``

In diesem Fall sollte die Unterabfrage den Index auf `CTACTE2.Bestelldatum` verwenden

`` ```

1voto

Daniel B Punkte 797

Um die innere Subselect schnell zu machen, müssen Sie einen Index auf den Spalten hinzufügen, die verwendet werden, um die innere Abfrage mit der Temp-Tabelle zu verknüpfen:

CodCustomer
ItemType
CodItem
EsCtaCorrienteMon
IsAvailable
OrderDate

Fügen Sie die Spalten mit den unterschiedlichsten Werten zuerst hinzu - haben Sie nicht IsAvailable zuerst, da es nur zwei verschiedene Werte hat.

Behalten Sie die OrderDate-Spalte zuletzt im Index, um schnelle Bereichssuchen innerhalb der Gruppe zu ermöglichen und den Vergleich von Daten effizient zu machen. Wenn es nur wenige Termine pro Gruppe gibt, sollte dieses Vergleichen kein Problem sein.

Versuchen Sie, diesen Index als Clustered Index zu erstellen, damit die Subselect ihre Zeilen in der Nähe der äußeren Temp-Tabelle findet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X