Die effizienteste Methode in SQL Server, um Datum von Datum + Uhrzeit abzurufen?


74

Was ist in MS SQL 2000 und 2005 bei einer Datumszeit wie "2008-09-25 12:34:56" der effizienteste Weg, eine Datumszeit zu erhalten, die nur "2008-09-25" enthält?

Duplizierte hier .


4
Ich bin sehr erfreut, dass die ersten drei Antworten alle unterschiedlich sind, es bedeutet also, dass es keine dumme Frage ist! :)
Matt Howells

Antworten:


113

Ich muss zugeben, dass ich den von Matt gezeigten Floor-Float-Umbau noch nie gesehen hatte. Ich musste das testen.

Ich habe eine reine Auswahl getestet (die Datum und Uhrzeit zurückgibt und nicht das ist, was wir wollen), die hier herrschende Lösung (Floor-Float), eine hier erwähnte "naive" (Stringconvert) und die hier erwähnte, die ich war mit (wie ich dachte, es war das schnellste).

Ich habe die Abfragen auf einem Testserver MS SQL Server 2005 getestet, der auf einem Win 2003 SP2-Server mit einer Xeon 3-GHz-CPU mit maximalem Speicher (32 Bit, also ca. 3,5 GB) ausgeführt wird. Es ist Nacht, in der ich bin, also läuft die Maschine fast ohne Last im Leerlauf. Ich habe alles für mich.

Hier ist das Protokoll aus meinem Testlauf, das aus einer großen Tabelle mit Zeitstempeln ausgewählt wurde, die bis zur Millisekunden-Ebene variieren. Dieser spezielle Datensatz enthält Daten über 2,5 Jahre. Die Tabelle selbst hat über 130 Millionen Zeilen, deshalb beschränke ich mich auf die oberste Million.

SELECT TOP 1000000 CRETS FROM tblMeasureLogv2 
SELECT TOP 1000000 CAST(FLOOR(CAST(CRETS AS FLOAT)) AS DATETIME) FROM tblMeasureLogv2
SELECT TOP 1000000 CONVERT(DATETIME, CONVERT(VARCHAR(10), CRETS, 120) , 120) FROM tblMeasureLogv2 
SELECT TOP 1000000 DATEADD(DAY, DATEDIFF(DAY, 0, CRETS), 0) FROM tblMeasureLogv2

SQL Server-Analyse- und Kompilierungszeit: CPU-Zeit = 0 ms, verstrichene Zeit = 1 ms.

(1000000 Zeile (n) betroffen) Tabelle 'tblMeasureLogv2'. Scananzahl 1, logische Lesevorgänge 4752, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.

SQL Server-Ausführungszeiten: CPU-Zeit = 422 ms, verstrichene Zeit = 33803 ms.

(1000000 Zeile (n) betroffen) Tabelle 'tblMeasureLogv2'. Scananzahl 1, logische Lesevorgänge 4752, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.

SQL Server-Ausführungszeiten: CPU-Zeit = 625 ms, verstrichene Zeit = 33545 ms.

(1000000 Zeile (n) betroffen) Tabelle 'tblMeasureLogv2'. Scananzahl 1, logische Lesevorgänge 4752, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.

SQL Server-Ausführungszeiten: CPU-Zeit = 1953 ms, verstrichene Zeit = 33843 ms.

(1000000 Zeile (n) betroffen) Tabelle 'tblMeasureLogv2'. Scananzahl 1, logische Lesevorgänge 4752, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.

SQL Server-Ausführungszeiten: CPU-Zeit = 531 ms, verstrichene Zeit = 33440 ms. SQL Server-Analyse- und Kompilierungszeit: CPU-Zeit = 0 ms, verstrichene Zeit = 1 ms.

SQL Server-Ausführungszeiten: CPU-Zeit = 0 ms, verstrichene Zeit = 1 ms.

Was sehen wir hier?

Konzentrieren wir uns auf die CPU-Zeit (wir betrachten die Konvertierung) und sehen, dass wir die folgenden Zahlen haben:

Pure-Select:  422
Floor-cast:   625
String-conv: 1953
DateAdd:      531  

Aus diesem Grund sieht es für mich so aus, als ob die DateAdd (zumindest in diesem speziellen Fall) etwas schneller ist als die Bodengussmethode.

Bevor Sie dorthin gehen, habe ich diesen Test mehrmals ausgeführt, wobei die Reihenfolge der Abfragen geändert wurde und die gleichen Ergebnisse erzielt wurden.

Ist das etwas Seltsames auf meinem Server oder was?


5
Es ist überhaupt nicht seltsam. Erstens ist meiner Meinung nach die Umstellung auf Float eine schlechte Praxis, da eine Umstellung auf Datum / Uhrzeit nicht zuverlässig ist. Zweitens finden Sie in diesem Beitrag weitere Leistungstests der verschiedenen Methoden .
ErikE

24
Select DateAdd(Day, DateDiff(Day, 0, GetDate()), 0)

DateDiff (Tag, 0, GetDate ()) ist dasselbe wie DateDiff (Tag, '1900-01-01', GetDate ())

Da DateDiff eine Ganzzahl zurückgibt, erhalten Sie die Anzahl der Tage, die seit dem 1. Januar 1900 vergangen sind. Anschließend fügen Sie diese Ganzzahl die Anzahl der Tage zum 1. Januar 1900 hinzu. Der Nettoeffekt ist das Entfernen der Zeitkomponente.

Ich sollte auch erwähnen, dass diese Methode für jeden Datums- / Zeitabschnitt funktioniert (wie Jahr, Quartal, Monat, Tag, Stunde, Minute und Sekunde).

Select  DateAdd(Year, DateDiff(Year, 0, GetDate()), 0)
Select  DateAdd(Quarter, DateDiff(Quarter, 0, GetDate()), 0)
Select  DateAdd(Month, DateDiff(Month, 0, GetDate()), 0)
Select  DateAdd(Day, DateDiff(Day, 0, GetDate()), 0)
Select  DateAdd(Hour, DateDiff(Hour, 0, GetDate()), 0)
Select  DateAdd(Second, DateDiff(Second, '20000101', GetDate()), '20000101')

Der letzte für Sekunden erfordert eine spezielle Behandlung. Wenn Sie den 1. Januar 1900 verwenden, wird eine Fehlermeldung angezeigt.

Der Unterschied zwischen zwei Datetime-Spalten verursachte zur Laufzeit einen Überlauf.

Sie können diesen Fehler umgehen, indem Sie ein anderes Referenzdatum verwenden (z. B. 1. Januar 2000).


Sind Sie sicher, dass dies die effizienteste Methode ist?
Matt Howells

Meine Tests zeigen, dass Matts Methode etwas schneller ist. Ich finde es auch besser lesbar.
Darrel Miller

2
@Dar Meiner Meinung nach ist die Konvertierung in Float eine schlechte Praxis, da eine Roundtrip-Konvertierung in datetime nicht zuverlässig ist. Bitte lesen Sie diesen Beitrag für weitere Details .
ErikE

12
select cast(floor(cast(@datetime as float)) as datetime)

Funktioniert, weil das Umwandeln einer Datumszeit in Float die Anzahl der Tage (einschließlich Bruchteile eines Tages) seit dem 1. Januar 1900 angibt. Durch das Bodenbelag werden die gebrochenen Tage entfernt und die Anzahl der ganzen Tage belassen, die dann auf eine Datumszeit zurückgesetzt werden können.


Ich habe die gleiche Methode angewendet und es hat großartig funktioniert. Soweit ich mich erinnere, wird die DATETIME tatsächlich physisch als FLOAT gespeichert, so dass diese Methode sehr effizient ist. Ich erinnere mich auch, dass ich irgendwo gelesen habe, dass es intern von Microsoft verwendet wurde. Ich bin
mir

4
SQL2008 verfügt über stark verbesserte (und dringend benötigte) Datumsverarbeitungsfunktionen. Es wäre so einfach, die Datums- und Uhrzeitangabe in den neuen Datumstyp umzuwandeln.
Matt Howells

3
@kristof datetime wird nicht physisch als Float gespeichert. Es sind zwei 4-Byte-Ganzzahlen, wobei die erste die Anzahl der Tage seit 1900-1-1 und die zweite die Anzahl der 1/300 Sekunde seit Mitternacht ist. Schließlich ist meiner Meinung nach die Umstellung auf Float eine schlechte Praxis, da eine Umstellung auf Datum / Uhrzeit nicht zuverlässig ist. Bitte lesen Sie diesen Beitrag für weitere Details .
ErikE

Klingt so, als wäre es als fester Punkt gespeichert, nicht als Gleitkomma intern.
Umgekehrter Ingenieur

7

in SQL Server 2012 verwenden

select cast(getdate() as date)

2
Während dies zutrifft, handelt es sich um die älteren Versionen von MS SQL 2000 und 2005, denen der dateDatentyp fehlt .
JPW


0

Verwenden Sie: JJJJ-MM-TT:

select convert(varchar(10), getdate(), 120)

Edit: Ups, er möchte eine DateTime anstelle einer Zeichenfolge. Das Äquivalent von TRUNC () in Oracle. Sie können das, was ich gepostet habe, auf eine DateTime zurückführen:

select convert(datetime, convert(varchar(10), getdate(), 120) , 120)

2
Bitte beachten Sie, dass die Konvertierung in varchar langsamer ist. Weitere Informationen finden Sie in diesem Beitrag .
ErikE




-1

Was ist mit SELECT CAST(CASt(GETDATE() AS int) AS DATETIME)?


1
Weil OP nicht darum gebeten hat ..?
mbinette

Ich versuchte es; es kann aufrunden, was zu einem falschen Ergebnis führt.
Pete Alvin

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.