SQL Server 2008 Ottimizzare PIENA JOIN con dichiarazioni ISNULL
-
26-09-2019 - |
Domanda
Ciao a tutti
Speravo che qualcuno potrebbe aiutarmi a migliorare una query devo eseguire periodicamente. Al momento ci vuole più di 40 minuti per eseguire. Esso utilizza la memoria allocata in pieno in questo periodo, ma l'utilizzo della CPU per lo più meandri al 2% -. 5%, di tanto in tanto il salto al 40% per alcuni secondi
Ho questa tabella (esempio semplificato):
CREATE TABLE [dbo].[dataTable]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[dteEffectiveDate] [date] NULL,
[dtePrevious] [date] NULL,
[dteNext] [date] NULL,
[Age] [int] NULL,
[Count] [int] NULL
) ON [PRIMARY]
GO
Ecco alcuni valori di input:
INSERT INTO [YourDB].[dbo].[dataTable]
([dteEffectiveDate]
,[dtePrevious]
,[dteNext]
,[Age]
,[Count])
VALUES
('2009-01-01',NULL,'2010-01-01',40,300),
('2010-01-01','2009-01-01', NULL,40,200),
('2009-01-01',NULL, '2010-01-01',20,100),
('2010-01-01','2009-01-01', NULL,20,50),
('2009-01-01',NULL,'2010-01-01',30,10)
GO
Ogni voce ha un campo dteEffectiveDate. Inoltre, ognuno ha una dtePrevious e dteNext, che riflette le date della precedente data di vicino / successiva efficace. Ora quello che voglio è una query che calcola la metà del valore sui campi di conteggio tra i periodi successivi, all'interno di una determinata età.
Così, per esempio, nei dati di cui sopra, per 40 anni abbiamo 300 a 2009/01/01 e 2010/01/01 200 al modo la query dovrebbe produrre 250.
Si noti che i 30 anni ha un solo ingresso, 10. Questo è al 2009/01/01. Non v'è alcuna voce al 2010/01/01, ma sappiamo che i dati sono stati catturati a questo punto, quindi il fatto che non v'è nulla che significa 30 è 0 a tale data. Da qui l'interrogazione dovrebbe produrre 5.
Al fine di raggiungere questo io uso un join completa della tabella su se stessa, e l'uso ISNULL per selezionare i valori. Ecco il mio codice:
SELECT
ISNULL(T1.dteEffectiveDate,T2.dtePrevious) as [Start Date]
,ISNULL(T1.dteNext,T2.dteEffectiveDate) as [End Date]
,ISNULL(T1.Age,T2.Age) as Age
,ISNULL(T1.[Count],0) as [Count Start]
,ISNULL(T2.[Count],0) as [Count End]
,(ISNULL(T1.[Count],0)+ISNULL(T2.[Count],0))/2 as [Mid Count]
FROM
[ExpDBClient].[dbo].[dataTable] as T1
FULL JOIN [ExpDBClient].[dbo].[dataTable] as T2
ON
T2.dteEffectiveDate = T1.dteNext
AND T2.Age = T1.Age
WHERE ISNULL(T1.dteEffectiveDate,T2.dtePrevious) is not null
AND ISNULL(T1.dteNext,T2.dteEffectiveDate) is not null
GO
quali uscite:
Start Date End Date Age Count Start Count End Mid Lives
2009-01-01 2010-01-01 40 300 200 250
2009-01-01 2010-01-01 20 100 50 75
2009-01-01 2010-01-01 30 10 0 5
Funziona perfettamente, ma quando ho eseguito questo sui dati reali, che è di circa 7 milioni di record, ci vuole dolorosamente tempo per l'esecuzione.
Qualcuno ha qualche suggerimento?
Grazie
Karl
Soluzione
E 'difficile fare un sacco di raccomandazioni.
Una cosa mi piacerebbe consiglio vivamente è indici su quelle colonne che si utilizza come chiavi esterne nelle vostre condizioni di partecipare, per esempio.
-
Age
-
dteEffectiveDate
-
dteNext
Crea un indice non cluster su ciascuno di tali colonne separatamente e misurare di nuovo. Con pochi righe di dati, non c'è alcun miglioramento misurabile -, ma con milioni di righe, si potrebbe fare la differenza
.