2012-04-10 16 views
5

W dokumencie Scaling Up Your Data Warehouse with SQL Server 2008 R2 autor zaleca użycie klucza daty w formacie YYYYMMDD jako indeksu klastrowego w tabelach faktów, aby zoptymalizować prędkość zapytania.TSQL DataTime to DateKey Int

Jaki jest najlepszy sposób przekonwertowania pola klucza na klucz daty? Czuję się następujący będzie działać, ale jest nieco niechlujny:

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

Oczywiście, nie używam getdate, lecz data kolumna w tabeli, która będzie używana w moich agregacji.

Po pierwsze, jak zasugerowałbyś dokonanie tej konwersji? Czy mój pomysł jest do przyjęcia?

Po drugie, czy ktoś miał duży sukces, używając klucza daty jako indeksu klastrowego?

Odpowiedz

8

ISO długie (112) by rade:

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

Casting GetDate() prosto na int z ISO 112 daje 41008 z jakiegoś powodu, ale przechodząc przez VARCHAR wydaje się działać - będę aktualizować jeśli pomyślę o szybszej obsadzie.

EDIT: W odniesieniu do int tylko vs debaty varchar, tutaj są moje wnioski (powtarzalny na moim stanowisku badawczym & serwerze produkcyjnym) metoda Varchar zużywa mniej czasu procesora dla pół miliona odlewów ale ułamek wolniej ogólnej - pomijalne chyba, że ​​do czynienia z miliardów wierszy

EDIT 2: Revised przypadku testowego, aby wyczyścić pamięć podręczną i termin 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

konwersji getdate (INT) prosto z wynosi 112 daje 41008 ponieważ to liczba dni od daty 0. Możesz sprawdzić, porównując ten wynik z wynikiem DATEDIFF między 0 a GETDATE(). 'SELECT CONVERT (INT, GETDATE(), 112), DATEDIFF (dzień, 0, GETDATE())' –

+0

@AdamPorad +1 Wiwaty za wyjaśnienie, że – HeavenCore

+1

Myślę, że twój test jest wadliwy. Różnica w czasie, który upłynął, wynika z wyświetlania długiej listy wartości na ekranie.Ponadto używasz GetDate(), więc SQL Server rozpoznaje go jako stałą i nie wykonuje obliczeń dla każdego wiersza. Musisz użyć kolumny z rzeczywistego stołu. Na koniec, aby dokładnie przetestować wydajność, należy usunąć czyste bufory i zwolnić pamięć podręczną procedur. Nie powinieneś tego robić na serwerze produkcyjnym. –

2

Konwersja do ciągów iz powrotem może być zaskakująco wolno . Zamiast tego, można sobie całkowicie z liczb całkowitych, tak:

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

W moim krótkim testowania, to jest nieco szybciej niż konwersja na łańcuch, a potem do int. Funkcja Rok, Miesiąc i Dzień zwracają liczbę całkowitą, więc wydajność jest nieco lepsza.

4

Zamiast tworzenia DateKey w formacie RRRRMMDD, można użyć funkcji DATEDIFF aby uzyskać liczbę dni między 0 (czyli „daty reprezentowanej przez 0”) a dniem jesteś dokonującej DateKey dla.

SELECT DATEDIFF(day,0,GETDATE()) 

Wadą jest to, że nie można łatwo patrzeć na wartości i ustalić datę, ale można użyć funkcji DATEADD obliczyć pierwotną datę (ja też widziałem ten trik stosowany obciąć część czasu datetime).

SELECT DATEADD(day, 41007, 0) 

(Uwaga: 41007 jest wynikiem funkcji DATEDIFF powyżej, gdy dostał się na 4/10/2012).