(按位)MySQL中的Supersets和Subsets

时间:2009-09-21 22:26:27

标签: mysql optimization bit-manipulation subset

以下查询在MySQL中是否有效:

SELECT * FROM table WHERE field & number = number; 
# to find values with superset of number's bits

SELECT * FROM table WHERE field | number = number; 
# to find values with subset of number's bits

...如果已创建该字段的索引?

如果没有,有没有办法让它跑得更快?

3 个答案:

答案 0 :(得分:6)

<强>更新

有关效果详情,请参阅我的博客中的此条目:


SELECT * FROM table WHERE field & number = number

SELECT * FROM table WHERE field | number = number

该指数可以通过两种方式有效:

  1. 避免早期表扫描(因为要比较的值包含在索引本身中)
    • 限制检查值的范围。
  2. 上述查询中的任何条件都不是 sargable ,这是索引不会用于范围扫描(条件与现在一样)。

    但是,点1仍然有效,索引也很有用。

    如果您的表格中包含平均每行100个字节和1,000,000个记录,那么表格扫描将需要扫描100 Mb个数据。

    如果你有一个索引(4 - 字节键,6 - 字节行指针和一些内部开销),查询将只需要扫描10 Mb个数据加上如果过滤器成功,表中的其他数据。

    • 如果您的条件没有选择性(您有很高的可能性来匹配条件),表扫描会更有效。
    • 如果您的条件具有选择性(您的可能性低于匹配条件),则索引扫描效率更高。

    这两个查询都需要扫描整个索引。

    但是通过重写AND查询,您也可以从索引的范围中受益。

    这个条件:

    field & number = number

    如果在number中设置field集的最高位,则

    只能匹配字段。

    你应该只为查询提供这个额外的条件:

    SELECT  *
    FROM    table
    WHERE   field & number = number
            AND field >= 0xFFFFFFFF & ~((2 << FLOOR(LOG(2, 0xFFFFFFFF & ~number))) - 1)
    

    这将使用粗滤波范围和精细滤波条件。

    number的最后一位未设置的位数越多越好。

答案 1 :(得分:1)

我怀疑优化器会想出那个......

也许你可以在这些查询上调用EXPLAIN并确认我的悲观猜测。 (当然记住,很多查询计划决策都是基于给定数据库的特定实例,即可变数据量和/或只是具有不同统计概况的数据可能会产生不同的计划)。

假设表具有大量行,并且“bitwised”标准保持足够的选择性)通过使用IN构造重写查询(或者使用IN构造重写查询),当避免对每一行进行按位操作时,可以实现可能的优化。加入)

类似的东西(概念性的,即没有经过测试的)

CREATE TEMPORARY TABLE tblFieldValues
  (Field INT);

INSERT INTO tblFieldValues
   SELECT DISTINCT Field
   FROM table;

-- SELECT * FROM table WHERE field | number = number; 
-- now becomes
SELECT * 
FROM table t
WHERE field IN 
    (SELECT Field 
     FROM tblFieldValues 
     WHERE field | number = number); 

这种方法的全部好处需要用不同的用例进行评估(所有这些用例在表中都有相当大的行数,因为否则直接的“WHERE字段|数字=数字”方法就足够了),但我怀疑这可能会明显加快。如果每次不需要重新创建“tblFieldValues”,则可以实现进一步的增益。当然,有效创建此表意味着在原始表中使用Field的索引。

答案 2 :(得分:0)

我自己尝试了这一点,并且按位操作不足以阻止Mysql在“field”列上使用索引。但是,很可能正在对指数进行全面扫描。