Nutzung von Gesamtsummen für Aggregate zur Verbesserung der Leistung
-
16-10-2019 - |
Frage
Ich habe zwei Tabellen: Details und Summen dieser Details.
Einzelheiten (Langsame Lösung):
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
group by r.OrderId
Summen (Schnelle Lösung):
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
Manchmal werden Summen ungültig (ein Job muss veränderte Gesamtsummen neu berechnen, aber es verzögert). Wie Sie verstehen, ist die zweite Abfrage schneller und die Anzahl der gültigen Summen mehr als ungültige. Ich suche also nach einer kombinierten Abfrage, die gültige Gesamtzahl aus der zweiten Tabelle (Gesamtsummen) zurückgibt und mit der ersten langsamen Abfrage dynamisch neu berechnet wird. Mein Ziel wird also erreicht: Alle Summen sind gültig und die Zeit für die Reaktion ist schneller als die vollständige Neuberechnung.
Hier ist mein Versuch (Hybridlösung):
with fast_static(OrderId, TotalQty, TotalGrossConsid, IsValid)
as
(
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
)
, slow_dynamic(OrderId, TotalQty, TotalGrossConsid)
(
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
)
select
OrderId, TotalQty, TotalGrossConsid
from fast_static
where IsValid = 1
union all
select
OrderId, TotalQty, TotalGrossConsid
from slow_dynamic s
--inner join fast_static ff
--on ff.OrderId = s.OrderId
where --ff.Valid = 0 -- too slow!!!
s.OrderId in (select OrderId from fast_static f where f.Valid = 0)
Ich habe die schnelle und hybride Lösung verglichen, ich habe 32% bis 68% (relative Abfragekosten). Wenn Sie eine kommentierte Variante sehen können, entspricht sie 1% bis 99% (schade). Ist es möglich, diese Abfrage zu verbessern?
HINZUGEFÜGT
@gbn:
Valid = case when i.OrderId is null then 1 else 0 end
...
dbo.OrderTotal t left join dbo.InvalidOrders i
Ja, ich habe einen Job, um die Summen neu zu berechnen, und dieser Prozess wird nicht mit Abfragebestimmungen synchronisiert. InvalidOrters -Tabellen sind ein wenig, das Datensätze speichern, um zu wissen, dass die Summen ungültig sind (um neu berechnet zu werden)
LÖSUNG
Indexierte Ansichten sind die beste Wahl. Beachten Sie auf SQL Server Edition (Noexpand Hinweis für nicht eingebildete Ausgaben) und bereit sein Erstellen Sie einige Datenbankobjekte neu (SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON
) Um mit indizierten Ansichten auf der Client -Seite zu beginnen.
Lösung
Ich kann nicht verstehen, warum Sie nicht im Laufe der Fliege aggregieren können und warum es so langsam ist. Ist die "gültige" Idee eine Problemumgehung, die sich mit der Verzögerung der Auftragsabrechnungen oder eines Geschäftsprozesses befasst
Beide Ideen verwerfen die Tabelle Invalid Order, die eine Problemumgehung für die schlechte Indexierung darstellt.
- Vorschlag 1:
Erstellen Sie eine berechnete Spalte
ALTER TABLE dbo.Order ADD PriceXQuantity AS Price * Quantity PERSISTED
Fügen Sie einen Index hinzu
CREATE INDEX IX_Totals ON dbo.Order (OrderID) INCLUDE Quantity, PriceXQuantity)
Schau was passiert
- Vorschlag 2:
Verwenden Sie eine indizierte Ansicht
CREATE VIEW OrderTotals
WITH SCHEMABINDING
AS
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
, COUNT_BIG(*) AS Dummy
from dbo.Order r
group by r.OrderId
GO
CREATE UNIQUE CLUSTERED INDEX IXCU_OrderTotals ON OrderTotals (OrderId9
GO
Sie können auch hier die Computerspalte verwenden
Andere Tipps
Wenn die Kosten nicht zu hoch wären, könnten Sie in Betracht ziehen, das zu bewegen IsValid
Flagge in die Detail
Tabelle und Index es? Dies würde Ihre Transaktionen verlangsamen, aber die Abfrageleistung als (vermutlich) groß verbessern Detail
Tisch würde in einem großen zugreifen range scan