Jak usunąć część czasu wartości datetime (SQL Server)?

głosy
77

Oto, czego używam:

SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)

Myślę, że nie może być lepiej i bardziej elegancki sposób.

wymagania:

  • To musi być tak szybko jak to możliwe (w mniejszym casting, tym lepiej).
  • Wynik końcowy musi być datetimetyp, a nie ciąg.
Utwórz 05/08/2008 o 21:08
źródło użytkownik
W innych językach...                            


6 odpowiedzi

głosy
11

Twoja CAST- FLOOR- CASTjuż wydaje się być optymalny sposób, przynajmniej na MS SQL Server 2005.

Niektóre inne rozwiązania widziałem mieć ciąg konwersję, jak Select Convert(varchar(11), getdate(),101)w nich, który jest wolniejszy o współczynnik 10.

Odpowiedział 05/08/2008 o 21:12
źródło użytkownik

głosy
27

SQL Server 2008 ma nową datę typ danych i upraszcza ten problem:

SELECT CAST(CAST(GETDATE() AS date) AS datetime)
Odpowiedział 06/08/2008 o 07:44
źródło użytkownik

głosy
16

Itzik Ben-Gan w Obliczenia datetime, część 1 (SQL Server Magazine, luty 2007) pokazuje trzy sposoby wykonywania takiej konwersji ( najwolniej do najszybciej ; różnica pomiędzy drugim a trzecim sposobem jest mała):

SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime)

SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)

SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime)

Twoja technika (rzucając się unosić ) jest sugerowane przez czytnik w kwietniowym numerze magazynu. Według niego, ma wydajność porównywalną z drugiej technice przedstawionej powyżej.

Odpowiedział 06/08/2008 o 09:06
źródło użytkownik

głosy
106

SQL Server 2008 iw górę

W SQL Server 2008 iw górę, oczywiście najszybszym sposobem jest Convert(date, @date). To może być rzucony z powrotem do datetimelub datetime2w razie potrzeby.

Co jest naprawdę Best In SQL Server 2005 i starszych?

Widziałem sprzecznych twierdzeń o tym, co jest najszybszym na skrócenie czasu od dnia, w SQL Server, a niektórzy ludzie nawet powiedział zrobili badania, ale moje doświadczenie było inaczej. Więc zróbmy trochę bardziej rygorystyczne testy i niech każdy ma skrypt więc jeśli popełnię żadnych błędów ludzie mogą mnie poprawić.

Konwersje pływak Are Not Ścisła

Po pierwsze, chciałbym zatrzymać się z dala od przekształcania datetimesię float, ponieważ nie konwertuje poprawnie. Możesz uciec z robieniem rzeczy w czasie usuwania dokładnie, ale myślę, że to zły pomysł, aby użyć go, ponieważ pośrednio komunikuje się deweloperom, że jest to bezpieczne działanie i nie jest . Spójrz:

declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
-- result: 2010-09-12 00:00:00.000 -- oops

To nie jest coś, co powinno być nauczanie ludzi w naszym kodzie lub w naszych przykładach Internecie.

Ponadto, nie jest nawet najszybszy sposób!

Dowód - Testowanie wydajności

Jeśli chcesz wykonać kilka testów samemu zobaczyć, jak różne metody naprawdę nie kumulują się, a potem trzeba ten skrypt instalacyjny, aby uruchomić testy niżej:

create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED);
declare @d datetime;
set @d = DateDiff(Day, 0, GetDate());
insert AllDay select @d;
while @@ROWCOUNT != 0
   insert AllDay
   select * from (
      select Tm =
         DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm)
      from AllDay
   ) X
   where Tm < DateAdd(Day, 1, @d);
exec sp_spaceused AllDay;  -- 25,920,000 rows

Należy pamiętać, że tworzy tabelę 427,57 MB w swojej bazie danych i weźmie coś jak 15-30 minut, aby uruchomić. Jeśli baza danych jest mała i ustawiona na 10% wzrostu potrwa dłużej niż jeśli rozmiar wystarczająco duży pierwszy.

Teraz do rzeczywistego scenariusza testowania wydajności. Należy pamiętać, że jest to celowe, aby nie zwracać wierszy z powrotem do klienta, jak to jest szalenie drogo na 26 milionów wierszy i byłoby ukryć różnice w wynikach pomiędzy metodami.

Wyniki skuteczności

set statistics time on;
-- (All queries are the same on io: logical reads 54712)
GO
declare
    @dd date,
    @d datetime,
    @di int,
    @df float,
    @dv varchar(10);

-- Round trip back to datetime
select @d = CONVERT(date, Tm) from AllDay; -- CPU time = 21234 ms,  elapsed time = 22301 ms.
select @d = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 23031 ms, elapsed = 24091 ms.
select @d = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23782 ms, elapsed = 24818 ms.
select @d = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 36891 ms, elapsed = 38414 ms.
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 102984 ms, elapsed = 109897 ms.
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 103390 ms,  elapsed = 108236 ms.
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 123375 ms, elapsed = 135179 ms.

-- Only to another type but not back
select @dd = Tm from AllDay; -- CPU time = 19891 ms,  elapsed time = 20937 ms.
select @di = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 21453 ms, elapsed = 23079 ms.
select @di = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23218 ms, elapsed = 24700 ms
select @df = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 29312 ms, elapsed = 31101 ms.
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 64016 ms, elapsed = 67815 ms.
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 64297 ms,  elapsed = 67987 ms.
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 65609 ms, elapsed = 68173 ms.
GO
set statistics time off;

Niektóre Rambling Analiza

Kilka uwag na ten temat. Przede wszystkim, jeśli tylko wykonując GROUP BY lub porównania, nie ma potrzeby, aby przekształcić z powrotem datetime. Dzięki czemu można zaoszczędzić trochę CPU poprzez unikanie, że chyba trzeba ostateczną wartość dla celów wyświetlania. Nawet GROUP BY wartości nieprzetworzonego i można umieścić konwersję tylko w klauzuli SELECT:

select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)

Także, zobaczyć jak konwersje numeryczne wziąć tylko nieco więcej czasu na powrót do konwersji datetime, ale varcharkonwersja prawie podwaja? To odsłania część procesora, który jest poświęcony obliczania dat w zapytaniami. Istnieją części użycia procesora, które nie wiążą się obliczenie daty, a to wydaje się być coś podobnego do 19875 ms w powyższych zapytaniami. Następnie konwersja wymaga pewnej dodatkowej kwoty, więc jeśli istnieją dwie konwersje, że kwota ta jest wykorzystana w przybliżeniu dwukrotnie.

Więcej badanie ujawnia, że w porównaniu do Convert(, 112)The Convert(, 101)kwerenda ma pewne dodatkowe koszty procesora (ponieważ wykorzystuje już varchar?), Ponieważ drugi z powrotem do konwersji datenie kosztuje tyle, ile konwersji do początkowej varchar, ale z Convert(, 112)nim jest bliżej samo 20000 koszt baza ms CPU.

Oto te obliczenia dotyczące czasu procesora, który kiedyś dla powyższej analizy:

     method   round  single   base
-----------  ------  ------  -----
       date   21324   19891  18458
        int   23031   21453  19875
   datediff   23782   23218  22654
      float   36891   29312  21733
varchar-112  102984   64016  25048
varchar-101  123375   65609   7843
  • runda jest czas CPU za podróż w obie strony z powrotem datetime.

  • pojedynczy czas procesora w jednym przejściu na inny rodzaj danych (ten, który powoduje usunięcie z boku część czasu).

  • Podstawa jest obliczenie odjęcie od singleróżnicy pomiędzy dwoma wywołaniami: single - (round - single). Jest to postać stadiony, które zakłada, że do konwersji i z tego rodzaju danych, oraz datetimejest w przybliżeniu taka sama w obu kierunkach. Wydaje się, że założenie to nie jest idealne, ale jest blisko, ponieważ wartości są blisko 20000 ms z jednym tylko wyjątkiem.

Jednym z bardziej interesujące jest to, że koszt podstawy jest prawie równa jednej Convert(date)metody (która musi być prawie 0 kosztami, ponieważ serwer może wewnętrznie wyodrębnić fragment dzień całkowitą wprost pierwszych czterech bajtów datetimedanych typu).

Wniosek

Tak to wygląda, że jest jednokierunkowym varcharmetoda konwersji trwa około 1,8 mikrosekund i jednokierunkowym DateDiffmetoda trwa około 0,18 mikrosekund. Ja opieram się w tym na najbardziej konserwatywnej „baza” czas procesora w moim testowania 18458 ms sumie przez 25,920,000 wierszy, więc 23218 ms / 25920000 = 0,18 ms. Widoczna poprawa 10x wydaje się dużo, ale szczerze dość małe, aż do czynienia z setkami tysięcy wierszy (617k wierszy = 1 sekunda oszczędności).

Nawet biorąc pod uwagę to mała bezwzględna poprawa, moim zdaniem, DateAddmetoda wygrywa, ponieważ jest to najlepsze połączenie wydajności i przejrzystości. Odpowiedź, która wymaga „magiczna liczba” od 0.50000004zamierza gryźć kogoś pewnego dnia (pięć zer lub sześć ???), plus to trudniejsze do zrozumienia.

Uwagi dodatkowe

Kiedy trochę czasu mam zamiar zmienić 0.50000004się '12:00:00.003'i zobaczyć, jak to robi. Jest konwertowany do tej samej datetimewartości i uważam, że to znacznie łatwiejsze do zapamiętania.

Dla zainteresowanych, powyższe testy zostały przeprowadzone na serwerze gdzie @@ Version zwraca następujący:

Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 09 lipca 2008 14:43:34 Copyright (c) 1988-2008 Microsoft Corporation Standard Edition w systemie Windows NT 5.2 (Build 3790: Service Pack 2)

Odpowiedział 12/09/2010 o 23:57
źródło użytkownik

głosy
3

Proszę spróbować:

SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]
Odpowiedział 29/06/2013 o 10:49
źródło użytkownik

głosy
0

SQL2005: Polecam rzucić zamiast DateAdd. Na przykład,

select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)

średnio około 10% szybciej na moim zbiorze, niż

select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)

(I odlewanie w smalldatetime to jeszcze szybciej)

Odpowiedział 05/11/2014 o 04:26
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more