views:

429

answers:

5

I have the following table in SQL Server 2008:

Session
(
sessionid varchar(10)
startdate dateteime
enddate dateteime
--rest of the fields go here
)

I have the following two nonclustered indexes created:

Inddex1: SessionID,startdate,enddate
Inddex2: startdate,enddate

I have the following query

select *
from session
where startdate>=@date1 and enddate <=@date2

on executing this query, both these idexes are not used. The query plan only shows the table scan.

Now I tried removing the index1 and executed the same SP Still index2 is not being used.

Any clues on how to make the SP to use index2? (No forced index use please.)

+1  A: 

Do you perhaps have a clustered index on the SessionID column? In that case your indexes are basically identical as any nonclustered index will implicitly include the clustered key.

How many rows are in the table, and what is the cardinality/uniqueness of the values? If the table is small enough, a table scan may be more efficient than an index lookup + bookmarp lookups to retrieve the remaining columns.

Mark S. Rasmussen
+1--small tables threw me for a long time because they refused to use indexes in many circumstances (for good reason, I guess)
Michael Haren
A: 

The composite index won't be used because it can't be used to optimsise that query. You should create a separate index on each column.

hopethisworks
Not true. The index may (emphasis on may) be used whenever there's a predicate on the first column of the index. Doesn't have to be equality.
Mark S. Rasmussen
you're right. answer edited.
hopethisworks
+1  A: 

Firstly, it's a good idea to have a primary key which you use as a unique, clustered index.

I'm not sure I get the point of those two composite index. Would you not be better with individual index on the dates?

Cybergibbons
A: 

You say the query processor isn't using one of your indexes, but you don't tell us what it is doing. I'll presume a table scan...?

You don't have a covering index for your query. Because you're doing "select *", the query processor knows that, at best, it can only get a "bookmark" from your index (either index would do), and then it will have to cross-reference that bookmark against the actual data pages in your table.

With that knowledge, the query processor will look at the amount of data in your table. If the amount of data there is small (for some definition of small) then it might decide that scanning the table is more efficient than an index seek following by a bookmark-lookup.

Consider changing the query and/or the index so that you only select fields that are entirely covered by the index. Then I would expect you to see index usage. But this isn't necessarily the right thing to do - creating a huge index for a seldom-used query might be wrong.

Martin
A: 

Any index with "startdate" as first column can help with the search for startdate>=@date1. Any index with "enddate" as first column can help with the search for "enddate <=@date2". But there is no index that can help with both.

And assuming there are almost no enddates with the same startdate, an index on (startdate,enddate) is no more useful than an index on (startdate).

So the table scan seems like a solid choice by Sql Server.

Even if you search for startdate>=@date1, it would still make sense to do a table scan. An index scan would give you a lot of references to the table that you'd have to resolve, which isn't worth it for a lot of data.

One query that should make use of the index is:

select * from session where startdate = @date1

Anyway, if you think you know better than the optimizer, you can enforce the use of an index like:

select *
from session with (index indexname)
where startdate>=@date1 and enddate <=@date2
Andomar
Not true. And index like (startdate, enddate) is great for a query with a predicate that filters on startdate first and enddate second. The index may be used. If there's a lot of columns, filtering on that index alone and doing bookmark lookups for the results will be a lot cheaper IO-wise than doing a full table scan.
Mark S. Rasmussen
It would help with "stardate = @a and enddate < @b", and it would prevent the table lookup in "select enddate where startdate > @x". So yeah there are some rare exceptions.
Andomar
It'll also help in his exact query.Having an index like (startdate,enddate) _will_ help in a query with a predicate like WHERE startdate >= @startdate AND enddate <= @enddateSince the index is basically just sorted data, it's a much faster way of filtering down the data. Using the first predicate and the index, we find all data that fulfils the first predicate. Given the index, the found data is now sorted according to the second predicate, and we can thus filter it down again.
Mark S. Rasmussen
Interesting. Start with an index binary search on ("startdate >= @startdate"). The result is not sorted by enddate, so that's an index scan on half the index. Then a lookup for the result rows. This lookup hurts for a large amount of rows, so I think Sql Server will prefer a brute force table scan.
Andomar