views:

353

answers:

4

This query is taking long time when endDate is null (i think that its about case statement, before case statement it was fast)

SELECT * 
FROM HastaKurumlari
WHERE CONVERT(SMALLDATETIME,'21-05-2009',103) 
BETWEEN startDate 
    AND (CASE WHEN endDate IS NULL THEN GETDATE() ELSE endDate END)

What should i use, when endDate is null to make it faster ?

+1  A: 

You could try the coalesce function:

select * 
from HastaKurumlari
where convert(smalldatetime, '21-05-2009', 103) 
    between startDate and coalesce(endDate, getdate());

The only way to be certain is to try any alternatives and view the execution plan generated for each query.

Andrew Hare
The second doesn't work exactly the same way when the given date is prior to the current date and endDate is null. The first would include the record and the second would omit it.
tvanfosson
Ah, you are right! Second example removed...
Andrew Hare
Yes you are right and thank you Andrew for your answer.
uzay95
Do you have any idea about which one faster?(COALESCE and ISNULL)
uzay95
+1 good answer, I wonder if the performance issue is in comparing smalldatimetime with the datetime from getdate(). Maybe endDate and startDate have the type datimetime as well.
Andomar
+1  A: 

If it is performance critical, then perhaps just don't use null for the open end-date - use the maximum supported datetime instead (probably lots of 9s).

I'd also do the conversion separately:

DECLARE @when datetime
SET @when = CONVERT(SMALLDATETIME,'21-05-2009',103) 

SELECT * 
  FROM HastaKurumlari
WHERE @when
BETWEEN startDate AND endDate

There is still something a bit different in the above and your original; if you can explain the intent of the GETDATE() check I might be able to tidy (read:fix) it a bit.

Marc Gravell
I thought that SQL Server was smart enough to notice the "in-query" conversion and only do that once, prior to any table or index scans.
Andrew Hare
GETDATE() is good to set endDate. But if i query to past, i will need to set endDate to when or DateAdd(d,1,@When). But still this query can't run.Because our endDate still NULL.
uzay95
@Andrew - I find it easier to make it explicit; fewer things to remember...
Marc Gravell
+1  A: 

Here's the query without CONVERT or CASE:

SELECT * 
FROM HastaKurumlari
WHERE '21-05-2009' between startDate and IsNull(endDate,getdate())

To make sure Sql Server doens't evaluate getdate() for every row, you could cache it, although I'm pretty sure Sql Server is smart enough by default:

declare @now datetime
set @now = getdate()

SELECT * 
FROM HastaKurumlari
WHERE '21-05-2009' between startDate and IsNull(endDate,@now)

Posting the query plan could help explain why the query is slow:

SET SHOWPLAN_TEXT ON
go
SELECT * 
FROM HastaKurumlari
WHERE CONVERT(SMALLDATETIME,'21-05-2009',103) 
BETWEEN startDate 
    AND (CASE WHEN endDate IS NULL THEN GETDATE() ELSE endDate END)
Andomar
This is easier than coalesce function and faster than before. But coalesce also usefull function.
uzay95
The only difference between Coalesce and IsNUll is that Coalesce can take more than two arguments. Coalesce(null,null,3) would return 3, for example.
Andomar
@Andomar: not quite right: the semantics are slightly different e.g. COALESCE promotes to the 'highest' data type, whereas ISNULL uses the first found. Also, COALESCE, being Standard SQL, is more portable. Speaking of which, I prefer CURRENT_TIMESTAMP over getdate().
onedaywhen
@onedaywhen: Interesting! Found a nice example here: http://haacked.com/archive/2005/01/21/difference-between-isnull-and-coalesce.aspx
Andomar
+1  A: 

As a starting point, factor out GETDATE() so that its called just once, and you should see an improvement in speed.

The way you've written it you are asking for GETDATE() to be evaluated every time enddate is null.

Since GETDATE() is a non-deterministic function the query cannot be optimised and will tend to under perform.

Ed Guiness
Just did a query that used getdate() on more than a milion rows, and it was just as fast as one that used a cached date.
Andomar
@Andomar post the code you used?
Ed Guiness