2012-04-10 20 views
5

In Scaling Up Your Data Warehouse with SQL Server 2008 R2, l'autore consiglia di utilizzare una chiave data intera nel formato di AAAAMMGG come indice cluster nelle tabelle dei fatti per ottimizzare la velocità della query.TSQL DateTime to DateKey Int

Qual è il modo migliore per convertire il campo della data chiave nella chiave della data? Sento il seguente avrebbe funzionato, ma è un po 'sciatto:

select Replace(CONVERT(varchar,GETDATE(),102),'.','') 

Chiaramente, non sto usando getdate, ma piuttosto una colonna di data nella tabella che verrà utilizzato nei miei aggregazioni.

Per prima cosa, come suggeriresti di realizzare questa conversione? La mia idea è accettabile?

In secondo luogo, qualcuno ha avuto molto successo utilizzando la chiave di data come indice cluster?

risposta

8

ISO lunga (112) farebbe il trucco:

SELECT CONVERT(INT, CONVERT(VARCHAR(8), GETDATE(), 112)) 

Casting getdate() direttamente a int ISO 112 dà 41008 per qualche ragione, ma passare attraverso un VARCHAR sembra funzionare - io aggiornare se penso a un cast più veloce.

EDIT: Per quanto riguarda l'int unica vs dibattito varchar, qui ci sono i miei risultati (ripetibile sul mio banco di prova & server di produzione) Metodo Varchar utilizza meno tempo di CPU per mezzo milione di calchi, ma una frazione più lento nel complesso - trascurabili a meno che il trattare con miliardi di righe

EDIT 2: test case Revised svuotare la cache e le date differnt

DBCC FREEPROCCACHE; 
DBCC DROPCLEANBUFFERS; 
SET STATISTICS TIME ON; 
WITH RawDates ([Date]) 
      AS (SELECT TOP 500000 
         DATEADD(DAY, N, GETDATE()) 
       FROM  TALLY 
      ) 
    SELECT YEAR([Date]) * 10000 + MONTH([Date]) * 100 + DAY([Date]) 
    FROM RawDates 
SET STATISTICS TIME OFF 

(500000 row(s) affected) 

SQL Server Execution Times: 
    CPU time = 218 ms, elapsed time = 255ms.  
DBCC FREEPROCCACHE; 
DBCC DROPCLEANBUFFERS; 
SET STATISTICS TIME ON; 
WITH RawDates ([Date]) 
      AS (SELECT TOP 500000 
         DATEADD(DAY, N, GETDATE()) 
       FROM  TALLY 
      ) 
    SELECT CONVERT(INT, CONVERT(VARCHAR(8), [Date], 112)) 
    FROM RawDates 
SET STATISTICS TIME OFF 

(500000 row(s) affected) 

SQL Server Execution Times: 
    CPU time = 266 ms, elapsed time = 602ms 
+1

conversione getdate() direttamente a INT con IS 112 dà 41008 perché è il numero di giorni dalla data 0. È possibile convalidare confrontando tale risultato con il risultato di DATEDIFF tra 0 e GETDATE(). 'SELEZIONA CONVERT (INT, GETDATE(), 112), DATEDIFF (giorno, 0, GETDATE())' –

+0

@AdamPorad +1 Cheers per chiarire che – HeavenCore

+1

Penso che il test sia difettoso. La differenza nel tempo trascorso è il risultato della visualizzazione della lunga lista di valori sullo schermo.Inoltre, si sta utilizzando GetDate() in modo che SQL Server lo riconosca come costante e in realtà non esegua il calcolo per ogni riga. Devi usare una colonna dalla tabella attuale. Infine, per testare accuratamente le prestazioni, è necessario eliminare i buffer puliti e liberare la cache delle procedure. Non dovresti farlo su un server di produzione. –

2

conversione in stringhe e viceversa può essere sorprendentemente lenta . Invece, si potrebbe trattare interamente con numeri interi, in questo modo:

Select Year(GetDate()) * 10000 + Month(GetDate()) * 100 + Day(GetDate()) 

Nel mio breve test, questo è un po 'più veloce di conversione in corda e poi in int. La funzione Anno, Mese e Giorno restituisce un numero intero, quindi le prestazioni sono leggermente migliori.

4

Invece di creare un DateKey utilizzando il formato AAAAMMGG, è possibile utilizzare la funzione DATEDIFF per ottenere il numero di giorni compreso tra 0 (ad esempio "la data rappresentata da 0") e la data per cui si sta facendo DateKey.

SELECT DATEDIFF(day,0,GETDATE()) 

Lo svantaggio è che non si può guardare facilmente il valore e determinare la data, ma è possibile utilizzare la funzione DATEADD per calcolare la data originale (Ho visto anche questo trucco usato troncare la parte di tempo di un datetime).

SELECT DATEADD(day, 41007, 0) 

(Nota: 41007 è il risultato della funzione DATEDIFF sopra quando mi sono imbattuto su 2012/04/10.)