views:

7890

answers:

8

Which method provides the best performance when removing the time portion from a datetime field in SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

or

b) select cast(convert(char(11), getdate(), 113) as datetime)

The second method does send a few more bytes either way but that might not be as important as the speed of the conversion.

Both also appear to be very fast, but there might be a difference in speed when dealing with hundreds-of-thousands or more rows?

Also, is it possible that there are even better methods to get rid of the time portion of a datetime in SQL?

+1  A: 

Strip time on inserts/updates in the first place. As for on-the-fly conversion, nothing can beat a user-defined function maintanability-wise:

select date_only(dd)

The implementation of date_only can be anything you like - now it's abstracted away and calling code is much much cleaner.

Anton Gogolev
I once devised a trigger to scrub times from selected columns. If the data can't be bad, you don't have to clean it.
Philip Kelley
There is a downside to the UDF approach, they're not SARGable. If used in JOINs or WHERE clauses, the optimiser can't use INDEXes to improve performance. Using the DATEADD/DATEDIFF approach, however, is SARGable and will be able to benefit from INDEXes. (Apparently the FLOAT method is SARGable too)
Dems
+2  A: 
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)
Gary McGill
See GBN's answer, many have investigated this. DATETIMEs are NOT stored as floats, and so using DATEADD/DATEDIFF avoids the mathmatical manipulation need to CAST between types.
Dems
I can accept that you might want to avoid a cast from DATETIME to FLOAT for the reason you describe, but in that case isn't the implicit conversion from zero in the OPs option (a) also a problem? Hmmm... I suppose in that case it's not a FLOAT and that the server is probably smart enough to discard the time info. OK, I concede :-)
Gary McGill
The 0 is indeed an implicit conversion from a numeric type (INT I would guess) to a DATETIME. Because it's a constant expression, however, the optimiser can do that at compile time for Stored Procedures and only needs to do it once for dynamically execute SQL. In short, there is a one time overhead for that, the FLOAT based query has the equivilent overhead for every Row.
Dems
A: 

Could always use / abuse the casted floating point representation of the date.

Select cast(floor(cast (getdate() as float )) as datetime)

Edit : As pointed out, the internal representation is not as simple as a floating point, but internally, it is 2, 4 byte integers. I've changed my text to say 'casted fp representation' to make that clearer.

Andrew
DateTimes are not represented as FLOATs. They are represented using two independant values. One for the Date part and one for the Time part. The Time part is the number of "time units", where for DATETIME the timeunit is 1/300th of a second.The CAST from DATETIME to FLOAT does require mathmatical manipulation, they really are stored differently. That's why DATEADD/DATEDIFF perform faster. (See GBN's answer)
Dems
Yes, float would be a simplification that was sufficient for the SQL to be understood. But I will adjust to the correct definition.
Andrew
A: 

I almost always use User Defined functions for this.

In fact, for most databases that I create, I add these UDF's in right near the start since I know there's a 99% chance I'm going to need them sooner or later.

I create one for "date only" & "time only" (although the "date only" one is by far the most used of the two).

Here's some links to a variety of date-related UDF's:

Essential SQL Server Date, Time and DateTime Functions
Get Date Only Function

That last link shows no less than 3 different ways to getting the date only part of a datetime field and mentions some pros and cons of each approach.

Of course, the absolute best approach is to use SQL Server 2008 and separate out your dates and times.

CraigTP
+12  A: 

Strictly, method a is the least resource intensive.

Proven less CPU intensive for same total duration a million rows by some one with way too much time on their hands: Most efficient way in SQL Server to get date from date+time?

I saw a similar test elsewhere with similar results too.

I prefer the DATEADD/DATEDIFF because:

  • varchar is subject to language/dateformat issues
  • float relies on internal storage
  • it extends to work out first day of month, tomorrow etc by changing "0" base
gbn
This is the only way to go ;)
Dems
+2  A: 

See this question:
http://stackoverflow.com/questions/923295/how-to-truncate-a-datetime-in-sql-server

Whatever you do, don't use the string method. That's about the worst way you could do it.

Joel Coehoorn
Thanks, I figured this had to have been asked before. Strange though that my experiments pointed out that the float method is actually slower by 3.5% on SQL Server 2008 than the dateadd(dd,0, datediff(dd,0, getDate())) method.I did run my tests many times for each method and the database server was unused for anything else at the time.
Stephen Perelson
Let's just say that I'm skeptical of benchmarks done by anyone who hasn't demonstrated that they do benchmarks regularly and in a very scientific way as part of their job. Even Thomas' benchmark in the link by gbn has some obvious problems when you look at it. That doesn't make it wrong necessarily, just not definitive. The cast/floor/cast method was the accepted fastest way for a very long time, and I suspect it was once indisputably true. That said, I am starting to reconsider it; especially for sql server 2008, where it's completely unnecessary anyway.
Joel Coehoorn
A: 

Here's yet another answer, from another duplicate question:

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

This magic number method performs slightly faster than the DATEADD method. (It looks like ~10%)

The CPU Time on several rounds of a million records:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

But note that these numbers are possibly irrelevant because they are already VERY fast. Unless I had record sets of 100,000 or more, I couldn't even get the CPU Time to read above zero.

Considering the fact that DateAdd is meant for this purpose and is more robust, I'd say use DateAdd.

Jeff Meatball Yang
A: 

Already answered but ill throw this out there too... this suposedly also preforms well but it works by throwing away the decimal (which stores time) from the float and returning only whole part (which is date)

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

second time I found this solution... i grabbed this code off

Carter Cole