更快地查询一个二进制(1)字段或 8 位字段?

Posted

技术标签:

【中文标题】更快地查询一个二进制(1)字段或 8 位字段?【英文标题】:Faster to query one binary(1) field or 8 bit fields? 【发布时间】:2011-12-28 21:43:24 【问题描述】:

如果我在一条记录中有 8 个布尔值,并且在对表进行查询时始终使用这 8 个值,并且表中的数据是静态的(只读),那么通过索引和获取匹配记录是否更快?查询像 binary(1) 这样的单字节字段,还是将 8 个单独的位列全部添加到索引中更好?

【问题讨论】:

【参考方案1】:

单个位字段上的索引基本上是无用的。位具有可怕的选择性,0 或 1,并且可能会被优化器忽略。 8 位字段上的 8 个索引将是优化器忽略的 8 个索引。

字节列上的索引只是选择性稍高一些,有 256 个不同的值。但是,如果您正在寻找单独的位模式,例如“第 3 位打开”,那么就无法将其表示为要寻找的单独值或范围。

结论是,无论您尝试什么,最终都会进行表扫描无论如何

所以更好地解释你的问题是什么,而不是你的解决方案,也许我们可以考虑一些更有效的方法。

【讨论】:

+1 :您认为这 256 个不同的值仍然会让您很难不进行扫描。 不仅是引爆点,而且搜索和范围扫描不支持按位操作。表达像“bit 3 on and bi 7 off”这样简单的东西会导致相当多的可能范围。唯一有一些机会的操作是指定所有8个字段(位)的查找,从而导致查找精确的字节值。即使这样,具有 1/256 的选择性,也是一个相当广泛的搜索。 同意,OP 已指定每次查询都将使用所有 8 个值,因此不需要按位运算。计算值选项可能是同时允许两者的最佳选择,但正如您所说,无论如何它都不太可能工作。 如果所有 8 位都被 Always 指定,那么将这个 1 字节字段设置为聚集索引的前导键会有所帮助,因为它会导致对 1/256 大小的范围扫描表,这是一个显着的 IO 减少。但当然,必须考虑其余的工作量。 @Remus Rusanu:也许覆盖以位列开头的索引仍然有意义【参考方案2】:

我会选择一个被索引的字节选项,或者至少一个计算出的 1 字节列与 8 个值一起,以防您需要将它们分开用于其他设施。 (也许是两全其美)

作为一个字节,搜索所有 8 个值的匹配结果的基数比 8 个单独的索引更可能避免临界点 - 即使这 8 个索引可以由引擎连接,我怀疑该基数可能会使查询提示并扫描而不是搜索 - 必须运行测试来证明这一点。

【讨论】:

【参考方案3】:

单字节查询会更快。在内存中构造要比较的字节会快得多。

【讨论】:

定义你在内存中的意思,索引和数据都是以页面的最低粒度读取的 @Andrew 我的意思是,如果您在执行查询之前使用 8 个单独的字段(8 个比较)而不是 1 个字节和 8 位内置在内存中执行查询,这将是 1 个比较。 这是一个令人难以置信的微优化 - 索引使用和 IO 的更大问题更为重要 @Alex 答案基于对数据库查询将如何执行以及在执行查询时会有哪些开销的理解。我没有基准,但它的常识,可以通过数学或实验证明:)。 @Andrew 1 查询涵盖了这一点。我认为你没有抓住重点。

以上是关于更快地查询一个二进制(1)字段或 8 位字段?的主要内容,如果未能解决你的问题,请参考以下文章

Mysql优化

5checksum(校验和)的实现

如何把含有BLOB字段的表导出成二进制文本文件

Thrift的TCompactProtocol紧凑型二进制协议分析

数据库扩展性设计:使用二进制解决一条记录关联多个状态的问题

数据库扩展性设计:使用二进制解决一条记录关联多个状态的问题