ytoledano
ytoledano

Reputation: 3123

Sql Server doing a full table scan when first field in PK has few distinct values

I have this table (TableA):

(
    [FieldA] [int] NOT NULL,
    [FieldB] [int] NOT NULL,
    [Value] [float] NULL
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED 
(
    [FieldA] ASC,
    [FieldB] ASC
)

There are few distinct FieldA values, lets say FieldA can be {1,2,3,4,5,6}.

Why does this query causes a full table scan:

SELECT COUNT(*) FROM TableA WHERE FieldB = 1

While this doesn't:

SELECT COUNT(*) FROM TableA WHERE FieldB = 1 where FieldA in (1,2,3,4,5,6)

Can't Sql Server optimize this? If I had TableB where FieldA was a PK and I joined TableB and TableA the query would run similarly to the second query.

Upvotes: 1

Views: 2430

Answers (2)

ytoledano
ytoledano

Reputation: 3123

Apparently, what I was looking for is a skip-scan optimization which is available on Oracle but not on SQL Server. Skip scan can utilize an index if the leading edge column predicate is missing: http://social.msdn.microsoft.com/Forums/eu/transactsql/thread/48de15ad-f8e9-4930-9f40-ca74946bc401

Upvotes: 1

Paul Turner
Paul Turner

Reputation: 39685

The clustered index you've created is based on two columns. If you're doing a lookup on just one of those columns, SQL Server cannot generate a "key" value to use in the lookup process on that index, so it falls back to a table-scan approach.

Even though FieldA has a very small range of values it could contain, the SQL optimizer doesn't look at that range of values to determine whether it could "fudge" a key out of the information you've given it.

If you want to improve the performance of the first query, you will have to create another index on FieldB. If, as you say, there are not many distinct values in FieldA, and you do most of your lookups on a FieldB exclusively, you might want to consider moving your clustered index to be built only on FieldB and generate a unique index over FieldA and FieldB.

Upvotes: 1

Related Questions