tags:

views:

135

answers:

2

The following query uses an index seek on an index on the LastModifiedTime column.

SELECT 
      CONVERT(varchar, a.ReadTime, 101) as ReadDate,
      a.SubID,
      a.PlantID,
      a.Unit as UnitID,
      a.SubAssembly
FROM dbo.Accepts a WITH (NOLOCK)
WHERE  a.LastModifiedTime BETWEEN '3/3/2010' And '3/4/2010'
AND a.SubAssembly = '400'

The query below, which is almost identical to the above query, uses a clustered index scan, instead of the index on LastModifiedTime. Can anyone tell me why? And, more importantly, what I can do to get SQL Server to use the index on the LastModifiedTime column, without using an index hint.

Declare @LastModifiedTimeEnd dateTime
Declare @LastModifiedTimeStart dateTime

    SELECT 
          CONVERT(varchar, a.ReadTime, 101) as ReadDate,
          a.SubID,
          a.PlantID,
          a.Unit as UnitID,
          a.SubAssembly
    FROM dbo.Accepts a WITH (NOLOCK)
    WHERE  a.LastModifiedTime BETWEEN @LastModifiedTimeStart And @LastModifiedTimeEnd
    AND a.SubAssembly = '400'
+3  A: 

The query below, which is almost identical to the above query, uses a clustered index scan, instead of the index on LastModifiedTime. Can anyone tell me why?

The query below does not know the values of the parameters when building the plan and assumes that in general, the clustered index scan is better.

And, more importantly, what I can do to get SQL Server to use the index on the LastModifiedTime column, without using an index hint.

SELECT 
      CONVERT(varchar, a.ReadTime, 101) as ReadDate,
      a.SubID,
      a.PlantID,
      a.Unit as UnitID,
      a.SubAssembly
FROM dbo.Accepts a WITH (NOLOCK)
WHERE  a.LastModifiedTime BETWEEN @LastModifiedTimeStart And @LastModifiedTimeEnd
AND a.SubAssembly = '400'
OPTION (OPTIMIZE FOR (@LastModifiedTimeStart = '3/3/2010', @LastModifiedTimeEnd = '3/4/2010'))

Alternatively, you can add OPTION (RECOMPILE), which will create the different execution plan each time the query is run, taking the parameter values into the account (parameter sniffing).

This, however, does not guarantee that the index will be used.

Quassnoi
I'm confused as to why the query planner would assume the clustered index is better. Regardless of what the parameters are, it is still matching against a specific column which has an index created for it. What is the point of that index if it's only used with fixed parameters?
Kent Boogaart
@Kent: using a secondary index to retrieve a range of values requires joining the index back to the table. When the range is large, the join overhead outweighs the sorting overhead.
Quassnoi
@Quassnoi. I see - thanks. Guess I kind of assumed parameter sniffing would be default behavior. Presumably using `>= @LastModifiedTimeStart AND <= LastModifiedTimeEnd` would also preclude the use of the non-clustered index without specifying `OPTION(RECOMPILE)`.
Kent Boogaart
@Kent: `BETWEEN` is just a syntax sugar for the expression you provided. This expression is parsed and optimized in the very same way as `BETWEEN` is.
Quassnoi
+3  A: 

You can create a plan guide with sp_create_plan_guide. See Optimizing Queries in Deployed Applications by Using Plan Guides. A plan guide will help the optimizer into deciding whether to use the index range seek or the clustered scan.

Remus Rusanu