我有两种方法可以从数据库中选择一组条目:
SELECT ... WHERE `level` IN (1,2,4,8) LIMIT ...;
或
SELECT ... WHERE `level` & mask LIMIT ...;
总共有4个'级别',编号为1,2,4,8(因为其他地方也可以使用相同的面具)。 IN()
或mask
的大括号都可以包含4个级别中的一个或多个的任意集合。该列已编入索引。查询仍然比舒适更长,我们正在努力优化速度。
昨天一个人说决定使用天真的IN()导致最多四次比较,而我应该使用位掩码代替。今天我听说位掩码会完全阻止列上索引的优势,而且会慢得多。
你能告诉我哪种方法会更快吗?
答案 0 :(得分:18)
你的问题很老了,但我仍然会回答它。
位掩码很可能会变慢,因为它必须计算出按位AND的计算,而IN
将使用level
的索引值来查找它在括号内的参数中(我认为应该是单O(log(n))
次操作)。
现在,你可能缺少的是,他们不会做同样的事情。
您的第一个查询只会检查level
是1,2,4还是8。
您的第二个查询,或实际上类似于:
SELECT ... WHERE (`level` & mask) = mask LIMIT ...;
能够查找包含您想要的掩码的levels
以及可能更多的掩码,在您的情况下,它可以检查1到15之间的所有值组合。因此,性能受到影响。
至于强制基准@AlanFoster建议,我不同意他。
使用以下任一方法为查询添加前缀要好得多:
EXPLAIN
或EXPLAIN QUERY PLAN
检查SQLite匹配的行数。
EXPLAIN QUERY PLAN SELECT * FROM ... WHERE level IN (2, 3);
SEARCH TABLE ... USING INDEX ..._level (level=?) (~20 rows)
EXPLAIN QUERY PLAN SELECT * FROM ... WHERE (level & 2) = 2;
SCAN TABLE ... (~500000 rows)
如您所见,按位AND运算符需要全表扫描。