我有一个表,它在一个整数列中存储标志值。(我不是设计师)
我有一个查询,其中一个where条件是
旗帜& 256 == 0
对于第8位不是1的所有无符号数,上述条件为真。
问题是,在sql server中,在将int转换为二进制时,它占用了太多时间,并且查询的性能因很多其他连接而降低。
有没有办法用一个简单的信息取代上述条件?
答案 0 :(得分:2)
根据您的说法,我认为您想用可搜索的运营商表达flags & 256
。
如果您的标志是最常用的位之一(即使用8位以上的位),这将更容易。为此,我们需要记住,在b
位上写的数字的值介于0和2之间 b -1。
如果第8位是最常用的,那么表示为数字的标志的值介于0和511之间。然后,flags & 256 > 0
等同于flags >= 256
,这是微不足道的,因为未设置第8位的任何二进制数是7位的数字,因此其值介于0和255之间。
理想情况下,为了在没有位掩码的情况下表达这一点,我们希望(flags % 512) >= 256
,但我怀疑它也不会受到攻击。因此,对于第8个以上的每个可能的标志组合,我们将需要枚举设置第8位的间隔。如果只使用1或2,则很容易,否则会更难。
假设你使用10位作为标志,那么你的位可以用00,01,10或11作为前缀。因为它们是位10和9,相应的数字(假设这些前缀后缀为8个零)是0,512,1024和1536。
因此,'标志的所有值的间隔都是' 第8位未设置是:
因此flag & 256 == 0
相当于flags BETWEEN 0 AND 255 OR flags BETWEEN 256 AND 511 OR flags BETWEEN 512 AND 767 OR flags BETWEEN 768 AND 1023
假设您有可能的F标志(也就是使用的位数),并且您对标志C(因此该位的位置)感兴趣。
标志设置为1
的间隔是,对于所有i< 2 F-C ,[(2i + 1)2 C ,(2i + 2)2 C -1]
标志设置为0
的间隔是,对于所有i< 2 F-C ,[(2i)2 C ,(2i + 1)2 C -1]
如您所见,您需要考虑2个 F-C 间隔。因此,如果有可能贿赂设计你的SQL数据库的人,让他把那个标志作为最大可能:F = C,你只需要一个标记来处理。
这是一个快速的&脏bash脚本将为您编写丑陋的interval子句:
#!/usr/bin/env bash
bits=10 # F, total number of possible flags
check=8 # C, position of the flag
grain=$(( 2 ** check ))
interval_offsets="$(seq 0 $grain $(( 2 ** bits -1 )) )"
str=
for i in $interval_offsets
do str="$str OR flags BETWEEN $(( i )) AND $(( i + grain - 1))"
done
echo "intervals for bit $check NOT set : ${str# OR}"
str=
for i in $interval_offsets
do str="$str OR flags BETWEEN $(( i + grain )) AND $(( i + 2 * grain - 1))"
done
echo "intervals for bit $check set : ${str# OR}"