Utilizzando i totali su aggregati per migliorare le prestazioni
-
16-10-2019 - |
Domanda
Ho due tabelle: i dettagli e totali di questi dettagli.
Dettagli ( soluzione lento ):
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
group by r.OrderId
Totali ( soluzione rapida ):
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
A volte i totali diventare valido (qualche lavoro deve ricalcolare i totali cambiato, ma ritarda). Come si capisce la seconda query è più veloce e il numero dei totali validi è più che quelli non validi. Così sto cercando una query combinata che restituisce totali valide della seconda tabella (totali) e ritorna ricalcolati in modo dinamico i totali utilizzando la prima query lenta. Quindi il mio obiettivo sarà raggiunto:. Tutti i totali sono validi e il tempo di risposta è più veloce quindi piena ricalcolo
Ecco il mio tentativo ( soluzione ibrida ):
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)
Ho confrontato la soluzione rapida e un sistema ibrido, ho ottenuto 32% al 68% (costi di query relative). Se si può vedere commentato variante è uguale a 1% a 99% (peccato). E 'possibile migliorare questa ricerca?
AGGIUNTO
@gbn:
Valid = case when i.OrderId is null then 1 else 0 end
...
dbo.OrderTotal t left join dbo.InvalidOrders i
Sì, ho un lavoro per ricalcolare i totali e questo processo non è sincronizzata con richieste di query. InvalidOrders tabelle è un po 'quello che i record dei negozi di sapere che i totali non è valido (per essere ricalcolato)
SOLUTION
viste indicizzate sono la scelta migliore. Essere consapevoli sulla edizione di SQL Server ( NOEXPAND suggerimento edizioni non-impresa) ed essere pronti a ricreare alcuni oggetti di database (SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON
) per iniziare a utilizzare viste indicizzate sul lato client.
Soluzione
Non riesco a capire perché non si può aggregare al volo e perché è così lento. è l'idea "Valido" una soluzione per affrontare il ritardo di OrderTotals o di qualche processo di business
Entrambe queste idee scartare tabella InvalidOrder che è una soluzione per scarsa indicizzazione.
- Suggerimento 1:
Creare una colonna calcolata ??p>
ALTER TABLE dbo.Order ADD PriceXQuantity AS Price * Quantity PERSISTED
Aggiungi un indice
CREATE INDEX IX_Totals ON dbo.Order (OrderID) INCLUDE Quantity, PriceXQuantity)
vedere cosa succede
- Suggerimento 2:
Usa una vista indicizzata ??p>
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
È possibile utilizzare la colonna calcolata anche qui
Altri suggerimenti
Se il costo non sarebbe troppo alto, si potrebbe prevedere il passaggio della bandiera IsValid
nella tabella Detail
e indicizzarlo? Ciò rallenterebbe le transazioni, ma migliorare le prestazioni delle query come (presumibilmente) grande tavolo Detail
sarebbe possibile accedere in un unico grande range scan