在sql查询中实现索引查找的Bitwise操作的替代方案

时间:2014-04-07 18:26:04

标签: c# sql sql-server performance

假设有一个包含两个字段"id""value"的表格。我创建了一个non-clustured index on "value"字段有一个参数"@valueToCompare"

For example : 
MyTable
Id(Int) Value(int)
1       9
2       11
3       13
4       7
5       8
6       20

@valueToCompare = 27

现在我想编写一个查询,它将给出满足"value & @valueToCompare = value"条件的结果集 因此我的查询将是

select * from MyTable where value & @valueToCompare = value

将在计算后给出结果

9 & 27   =9
11 & 27  =11
13 & 27  =9
7 & 27   =3
8 & 27   =8
20 & 27  =16

现在这个查询的问题是优化器会执行index scan rather than Index seek,因此效率会降低。

所以想知道有没有办法编写查询来实现索引查找。

注意:我将使用c#code

中的结果集

3 个答案:

答案 0 :(得分:0)

SQL Server不会使用索引来执行按位操作。你运气不好,但是你可以先通过CTE或派生表创建一个较小的结果集,然后在较小的集合上执行操作。

答案 1 :(得分:0)

由于@valueToCompare的当前值参与其中一列的表达式,因此无法将其转换为索引搜索。但是,如果您愿意将各个标志拆分为各自的列,则可能会获得更快的查找速度。

要将int从0表示为int.MaxValue,您需要31位列 - 比如v0v30,包含。您可以对它们建立索引,然后将搜索号拆分为单个位,然后运行查询。您可以编写与value & @valueToCompare = value的二进制值对应的检查组合而不是@valueToCompare

例如,如果@valueToCompare为9 10 或1001 2 ,则查询将如下所示:

SELECT ...
WHERE v0=1 AND v3=1

v0是包含零位的列; v3是包含第三位的列。这些是以二进制表示形式设置的两个位。

您可以让SQL Server为您管理这些列,而不是手动管理列。

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)

现在,您可以根据已经分离出的咬合值进行搜索。此表中value & 9 = 9的查询如下所示:

SELECT ...
WHERE v0=1 AND v3=8

您比较vN的值是2 N ,因此对于v0它是1,对于v1它是2 },v24v38,依此类推。

答案 2 :(得分:0)

索引搜索可能会或可能不会比扫描更有效。除了最高选择性查询之外,扫描窄覆盖索引可能比搜索和查找更快。

单个位列只能是0或1;它的选择性平均为50%,因此可能不是一个非常好的索引候选者。您可以创建索引,但考虑到查询的成本非常高,优化程序可能会也可能不会使用它。

将它组合到一个位域可能是更好的解决方案,如果你知道你的数据并巧妙地对这些位进行排序,从更高的选择性到更低的顺序,可能会更好。为了说明这个想法:

select * from MyTable where value < @valueToCompare and value & @valueToCompare = value