Quando si utilizza una sottoquery per trovare il conteggio totale di tutti i record precedenti con un campo corrispondente, le prestazioni sono terribili su una tabella con un minimo di 50.000 record. Senza la subquery, la query viene eseguita in pochi millisecondi. Con la subquery, il tempo di esecuzione è superiore a un minuto.
Per questa query, il risultato deve:
- Includi solo quei record in un determinato intervallo di date.
- Includi un conteggio di tutti i record precedenti, escluso il record corrente, indipendentemente dall'intervallo di date.
Schema di tabella di base
Activity
======================
Id int Identifier
Address varchar(25)
ActionDate datetime2
Process varchar(50)
-- 7 other columns
Dati di esempio
Id Address ActionDate (Time part excluded for simplicity)
===========================
99 000 2017-05-30
98 111 2017-05-30
97 000 2017-05-29
96 000 2017-05-28
95 111 2017-05-19
94 222 2017-05-30
risultati aspettati
Per l'intervallo di date di 2017-05-29
a2017-05-30
Id Address ActionDate PriorCount
=========================================
99 000 2017-05-30 2 (3 total, 2 prior to ActionDate)
98 111 2017-05-30 1 (2 total, 1 prior to ActionDate)
94 222 2017-05-30 0 (1 total, 0 prior to ActionDate)
97 000 2017-05-29 1 (3 total, 1 prior to ActionDate)
I record 96 e 95 sono esclusi dal risultato, ma sono inclusi nella PriorCount
sottoquery
Query corrente
select
*.a
, ( select count(*)
from Activity
where
Activity.Address = a.Address
and Activity.ActionDate < a.ActionDate
) as PriorCount
from Activity a
where a.ActionDate between '2017-05-29' and '2017-05-30'
order by a.ActionDate desc
Indice attuale
CREATE NONCLUSTERED INDEX [IDX_my_nme] ON [dbo].[Activity]
(
[ActionDate] ASC
)
INCLUDE ([Address]) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
)
Domanda
- Quali strategie potrebbero essere utilizzate per migliorare le prestazioni di questa query?
Modifica 1
In risposta alla domanda su cosa posso modificare sul DB: posso modificare gli indici, ma non la struttura della tabella.
Modifica 2
Ora ho aggiunto un indice di base sulla Address
colonna, ma questo non sembra migliorare molto. Attualmente sto trovando prestazioni molto migliori con la creazione di una tabella temporanea e l'inserimento dei valori senza PriorCount
e quindi l'aggiornamento di ogni riga con i loro conteggi specifici.
Modifica 3
Il problema è stato riscontrato dall'indice Joe Obbish (risposta accettata). Dopo aver aggiunto una nuova nonclustered index [xyz] on [Activity] (Address) include (ActionDate)
, i tempi delle query sono scesi da un minuto verso l'alto a meno di un secondo senza utilizzare una tabella temporanea (vedi modifica 2).
nonclustered index [xyz] on [Activity] (Address) include (ActionDate)
, i tempi di interrogazione sono scesi da un minuto a meno di un secondo. +10 se potessi. Grazie!