Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
ThreePea
Yak Posting Veteran
83 Posts |
Posted - 2005-10-18 : 10:39:17
|
Ok, if you run the following simple piece of code:CREATE TABLE #Temp(Record_Date DATETIME)INSERT #Temp VALUES('2005-06-29 12:17:48.140')--CREATE INDEX [IX_Record_Date] ON #Temp (Record_Date) DECLARE @Begin_Time AS SMALLDATETIMEDECLARE @End_Time AS SMALLDATETIMESET @Begin_Time = '2005-06-29 12:18:00'SET @End_Time = '2005-06-29 12:18:00'SELECT *FROM #Temp AS T WHERE CAST(T.Record_Date AS SMALLDATETIME) BETWEEN @Begin_Time AND @End_TimeDROP TABLE #TempYou get a resultset with the one row, as expected. However, if you uncomment the CREATE INDEX line, which means the compiler will now use this index, the row does not appear! The absense or presence of an index should not dictate the final results of a query, should it?I even tried a derived table, which to my surprise still did not work:SELECT d.Small_DateFROM(SELECT CAST(T.Record_Date AS SMALLDATETIME) AS 'Small_Date'FROM #Temp AS T ) AS dWHERE d.Small_Date BETWEEN @Begin_Time AND @End_Time If you comment out the WHERE clause you will see that d.Small_Date is exactly what you expect, but it still is not in the result set.Finally, if you do use the date values directly in the query instead of the @Begin/End_Time variables, it works as expected.I tested this on 2000 sp3, 2000 sp4, and 2005 September CTP, and the behavior is identical on all. Any ideas? As you can probably guess, this is actually happening on live production data - in one particular sproc if a certain index is chosen, rows disappear from the result set, much to the customer's frustration (and ours). We had to hardcode an index hint to prevent the offending index from screwing the results.Thanks.3P |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-10-18 : 10:51:37
|
| Presumably the INDEX plan is CASTing the @Begin_Time to DATETIME (i.e. NOT the "small" version) and then the Record_Date is actually earlier than the @Begin_Time.Here's the SHOWPLANStmtText |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1001], [Expr1002], [Expr1003])) |--Compute Scalar(DEFINE:([Expr1001]=Convert([@Begin_Time]), [Expr1002]=Convert([@End_Time]), [Expr1003]=If (Convert([@Begin_Time])=NULL) then 0 else 22|If (Convert([@End_Time])=NULL) then 0 else 42)) | |--Constant Scan |--Index Seek(OBJECT:([tempdb].[dbo].[#Temp__000000001AB4].[IX_Record_Date] AS [T]), SEEK:([T].[Record_Date] > [Expr1001] AND [T].[Record_Date] < [Expr1002]), WHERE:(Convert([T].[Record_Date])<=[@End_Time] AND Convert([T].[Record_Date])>=[@Begin_Time]) ORDERED FORWARD)This looks like trouble:SEEK:([T].[Record_Date] > [Expr1001] AND [T].[Record_Date] < [Expr1002])Kristen |
 |
|
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2005-10-18 : 11:58:44
|
Another data point... the following isn't being affected by the whether or not there's an index.SELECT *FROM #Temp AS T WHERE CAST(T.Record_Date AS SMALLDATETIME) BETWEEN CAST('2005-06-29 12:18:00' AS smalldatetime) AND CAST('2005-06-29 12:18:00' AS smalldatetime) It is still doing an index seek, but there's an obvious difference in the Compute Scalar part of the execution plan. Notice the offsets being applied to the literal values before they're used in the seek: |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1001], [Expr1002], [Expr1003])) |--Compute Scalar(DEFINE:([Expr1001]=Convert('Jun 29 2005 12:18PM')-'Jan 1 1900 12:01AM', [Expr1002]=Convert('Jun 29 2005 12:18PM')+'Jan 1 1900 12:01AM', [Expr1003]=If (Convert('Jun 29 2005 12:18PM')-'Jan 1 1900 12:01AM'=NULL) then 0 else 6|If (Convert('Jun 29 2005 12:18PM')+'Jan 1 1900 12:01AM'=NULL) then 0 else 10)) | |--Constant Scan |--Index Seek(OBJECT:([tempdb].[dbo].[Temp].[IX_Record_Date] AS [T]), SEEK:([T].[Record_Date] > [Expr1001] AND [T].[Record_Date] < [Expr1002]), WHERE:(Convert([T].[Record_Date])='Jun 29 2005 12:18PM') ORDERED FORWARD)These aren't appearing in the version with the @Begin_Time, @End_Time variables.However, if you change the end literal to, say 12:20, it behaves like the version with the variables, i.e.SELECT *FROM #Temp AS T WHERE CAST(T.Record_Date AS SMALLDATETIME) BETWEEN CAST('2005-06-29 12:18:00' AS smalldatetime) AND CAST('2005-06-29 12:20:00' AS smalldatetime)is affected by the index. With the index the plan is: |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1001], [Expr1002], [Expr1003])) |--Compute Scalar(DEFINE:([Expr1001]=Convert('Jun 29 2005 12:18PM'), [Expr1002]=Convert('Jun 29 2005 12:20PM'), [Expr1003]=If (Convert('Jun 29 2005 12:18PM')=NULL) then 0 else 22|If (Convert('Jun 29 2005 12:20PM')=NULL) then 0 else 42)) | |--Constant Scan |--Index Seek(OBJECT:([tempdb].[dbo].[Temp].[IX_Record_Date] AS [T]), SEEK:([T].[Record_Date] > [Expr1001] AND [T].[Record_Date] < [Expr1002]), WHERE:(Convert([T].[Record_Date])<='Jun 29 2005 12:20PM' AND Convert([T].[Record_Date])>='Jun 29 2005 12:18PM') ORDERED FORWARD)The offsets have disappeared again! |
 |
|
|
|
|
|
|
|