Reputation: 3735
Let suppose there is a table having two fields "id"
and "value"
. I have created a non-clustured index on "value"
field There is a parameter "@valueToCompare"
.
For example :
MyTable
Id(Int) Value(int)
1 9
2 11
3 13
4 7
5 8
6 20
@valueToCompare = 27
Now I want to write a query which will give me the resultset which satisfy "value & @valueToCompare = value"
condition
Hence my query will is
select * from MyTable where value & @valueToCompare = value
which will give the result after calculating
9 & 27 =9
11 & 27 =11
13 & 27 =9
7 & 27 =3
8 & 27 =8
20 & 27 =16
Now the problem with this query is that the optimizer will do index scan rather than Index seek
, hence less efficient.
So wanted to know is there a way to write the query to achieve index seek.
NOTE : I Will use the result set in c# code
Upvotes: 1
Views: 1563
Reputation: 726809
Since the current value of @valueToCompare
participates in an expression with one of the columns, there is no way to convert this to an index seek. However, you could potentially get a much faster lookup if you are willing to split the individual flags into their own columns.
To represent int
s from 0 to int.MaxValue
you would need 31 bit columns - say, v0
through v30
, inclusuve. You can make an index on them, and then split the search number into individual bits, and run your query. Instead of value & @valueToCompare = value
you would write a combination of checks corresponding to @valueToCompare
's binary value.
For example, if @valueToCompare
is 910 or 10012, the query would look like this:
SELECT ...
WHERE v0=1 AND v3=1
v0
is the column containing bit zero; v3
is the column containing bit three. These are the two bits set in the binary representation of nine.
Rather than managing the columns manually, you could let SQL Server manage them for you.
create table bitfields (
id int,
value int,
v0 as value & 1 persisted,
v1 as value & 2 persisted,
v2 as value & 4 persisted,
v3 as value & 8 persisted,
v4 as value & 16 persisted,
v5 as value & 32 persisted,
v6 as value & 64 persisted,
v7 as value & 128 persisted
-- ...and so on
)
create index bitfields_idx on bitfields (v0,v1,v2,v3,v4,v5,v6,v7)
Now you can search based on bitfied values that have been separated out for you. The query for the value & 9 = 9
on this table would look like this:
SELECT ...
WHERE v0=1 AND v3=8
The value to which you compare vN
is 2N, so for v0
it's 1
, for v1
it's 2
, for v2
it's 4
, for v3
it's 8
, and so on.
Upvotes: 0
Reputation: 10098
Index seek may or may not be more efficient than scan. Scaning a narrow covering index will probably be faster than seek&lookup, except for the highest selective queries.
A single bit column can only be 0 or 1; it's selectivity is 50% on average, so probably not a very good candidate for indexing. You can create an index, but taking into account very high cost of lookups it may or may not be used by the optimizer.
Combining it into a bitfield might be better solution, even more if you know your data and order the bits cleverly, from higher selectivity to lower. To illustrate the idea:
select * from MyTable where value < @valueToCompare and value & @valueToCompare = value
Upvotes: 1
Reputation: 12857
SQL Server will not use indexes to perform bitwise operations. You are out of luck, however you could maybe start by first creating a smaller resultset via a CTE or derived table and then perform the operation on a smaller set.
Upvotes: 0