Vra

Hier is wat ek gebruik:

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

Ek dink daar kan 'n beter en meer elegante manier wees.

Vereistes:

  • Dit moet so vinnig as moontlik (die minder giet, hoe beter) wees.
  • Die finale uitslag het 'n tipe datetime, nie 'n string wees.
Was dit nuttig?

Oplossing

SQL Server 2008 en up

In SQL Server 2008 en up, natuurlik die vinnigste manier is Convert(date, @date). Dit kan terug gegooi word om 'n datetime of datetime2 indien nodig.

Wat is regtig Beste In SQL Server 2005 en ouer?

Ek het strydig eise oor wat vinnigste vir die tyd truncating vanaf 'n datum in SQL Server gesien, en 'n paar mense het selfs gesê hulle het die toets, maar my ervaring was anders. So kom ons doen 'n paar meer streng toets en laat almal het die script so as ek maak enige foute wat mense kan my reg te stel.

Float Doelskoppe nie akkuraat

In die eerste plek sou ek weg te bly van die omskakeling van datetime om float, omdat dit nie korrek om te skakel. Jy kan wegkom met die doen van die tyd-verwydering ding akkuraat te kry, maar ek dink dit is 'n slegte idee om dit te gebruik, want dit implisiet kommunikeer aan ontwikkelaars dat dit 'n veilige werking en dit is nie . Neem 'n blik:

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

Dit is nie iets wat ons moet leer mense in ons kode of in ons voorbeelde aanlyn.

Dit is ook nie eens die vinnigste manier!

Bewys - Prestasietoetsing

As jy wil 'n paar toetse jouself om te sien hoe die verskillende metodes regtig stapel te voer, dan sal jy hierdie opstelling script moet die toetse verder laat afloop:

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

Let asseblief daarop dat dit skep 'n 427,57 MB tabel in jou databasis en sal so iets 15-30 minute neem om te hardloop. As jou databasis is klein en ingestel op 10% groei dit sal langer as wanneer jy grootte neem groot genoeg eerste.

Nou vir die werklike prestasie toets script. Neem asseblief kennis dat dit is doelgerig om nie rye terug te keer na die kliënt as dit is mal duur op 26 miljoen rye en sal die prestasie verskille tussen die metodes om weg te steek.

Performance Resultate

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;

Sommige Rambling Ontleding

Kort bespreking van hierdie. In die eerste plek, as net die uitvoering van 'n GROEP DEUR of 'n vergelyking, is daar geen behoefte om terug te skakel na datetime. Sodat jy kan 'n paar CPU red deur te vermy dat, tensy jy die finale waarde vir mekaar doeleindes nodig. Jy kan selfs GROUP BY die onbekeerde waarde en sit die omskakeling net in die SELECT klousule:

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

Ook, sien hoe die numeriese doelskoppe slegs effens meer tyd om terug te skakel na datetime, maar die varchar omskakeling byna verdubbel? Dit blyk dat die gedeelte van die CPU wat word gewy aan datum berekening in die navrae. Daar is dele van die CPU gebruik wat nie op datum berekening betrek, en dit lyk of iets naby aan 19.875 Me in die bogenoemde vrae wees. Toe neem die omskakeling 'n paar ekstra bedrag, so as daar twee doelskoppe, daardie bedrag opgebruik ongeveer twee keer.

Meer ondersoek toon dat in vergelyking met Convert(, 112), die Convert(, 101) navraag het 'n paar ekstra CPU koste (aangesien dit gebruik 'n langer varchar?), Omdat die tweede bekering terug na date nie soveel kos as die aanvanklike sukses te varchar, maar met Convert(, 112) dit is nader aan dieselfde 20000 ms CPU basiskoste.

Hier is die berekeninge op die CPU tyd wat ek gebruik vir die bogenoemde analise:

     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
  • ronde is die CPU tyd vir 'n ronde trip terug na datetime.

  • enkele is CPU tyd vir 'n enkele omskakeling na die alternatiewe tipe data (die een wat die newe-effek van die verwydering van die tyd gedeelte het).

  • basis is die berekening van die aftrekking van single die verskil tussen die twee aanroepingen: single - (round - single). Dit is 'n ball figuur wat die omskakeling veronderstel om en by daardie tipe data en datetime is apbenaderd dieselfde in enige rigting. Dit wil voorkom of hierdie aanname is nie volmaak nie, maar is naby, want die waardes is almal naby aan 20.000 Me met net een uitsondering.

Nog 'n interessante ding is dat die basiskoste is byna gelyk aan die enkele Convert(date) metode (wat byna 0 koste wees, as die bediener intern die heelgetal dag gedeelte kan onttrek reg uit die eerste vier grepe van die datetime data tipe).

Gevolgtrekking

So hoe dit lyk, is dat die enkel-rigting varchar omskakeling metode neem ongeveer 1.8 μs en die enkel-rigting DateDiff metode neem ongeveer 0.18 μs. Ek is dit baseer op die mees konserwatiewe "basis CPU" tyd in my toets van 18458 ms totale vir 25.920.000 rye, so 23.218 Me / 25920000 = 0.18 μs. Die oënskynlike 10x verbetering lyk soos 'n baie, maar dit is eerlik mooi klein totdat jy te doen het met honderde duisende rye (617k rye = 1 sekonde spaar).

Selfs gegee hierdie klein absolute verbetering, in my mening, die DateAdd metode wen, want dit is die beste kombinasie van prestasie en duidelikheid. Die antwoord wat 'n "magic number" van 0.50000004 vereis gaan byt iemand eendag (vyf nulle of ses ???), plus dit is moeiliker om te verstaan.

Bykomende notas

Wanneer ek kry 'n paar keer gaan ek 0.50000004 verander na '12:00:00.003' en sien hoe dit werk. Dit is omgeskakel na dieselfde datetime waarde en ek vind dit baie makliker om te onthou.

Vir diegene wat belangstel, is die bogenoemde toetse uit te voer op 'n bediener waar @@ weergawe gee die volgende in:

  

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

Ander wenke

SQL Server 2008 het 'n nuwe datum tipe data en dit vereenvoudig hierdie probleem aan:

SELECT CAST(CAST(GETDATE() AS date) AS datetime)

Itzik Ben-Gan in DATETIME berekeninge, Deel 1 (SQL Server Magazine, Februarie 2007) toon drie metodes van die uitvoering van so 'n omskakeling ( stadigste om vinnigste , die verskil tussen die tweede en derde metode is klein):

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)

Jou tegniek (beslissende om float ) word voorgestel deur 'n leser in die April-uitgawe van die tydskrif. Volgens hom is dit 'prestasie vergelykbaar met dié van die tweede tegniek hierbo aangebied.

Jou CAST-FLOOR-CAST lyk reeds na die optimale manier wees, ten minste op MS SQL Server 2005.

Sommige ander oplossings wat ek gesien het 'n string-omskakeling, soos Select Convert(varchar(11), getdate(),101) in hulle, wat stadiger met 'n faktor van 10.

Probeer asseblief:

SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]

SQL2005: Ek beveel gooi in plaas van dateadd. Byvoorbeeld,

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

gemiddeld sowat 10% vinniger op my dataset, as

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

(en beslissende in smalldatetime was vinniger steeds)

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top