【问题标题】:Is there any performance gain in indexing a boolean field?索引布尔字段是否有任何性能提升?
【发布时间】:2012-05-18 11:22:08
【问题描述】:

我正要编写一个包含WHERE isok=1 的查询。顾名思义,isok 是一个布尔字段(实际上是一个 TINYINT(1) UNSIGNED,根据需要设置为 0 或 1)。

索引该字段是否有任何性能提升?引擎(在这种情况下为 InnoDB)在查找索引时的性能会更好还是更差?

【问题讨论】:

标签: mysql indexing innodb


【解决方案1】:

只是在这里对其他几个答案进行更详细的说明,因为根据我的经验,那些查看此类问题的人与我们在同一条船上,我们都听说索引布尔字段毫无意义,但是.. .

我们有一个包含大约 400 万行的表,一次只有大约 1000 行左右会标记一个布尔开关,这就是我们搜索的内容。在我们的布尔字段上添加索引可以将查询速度提高几个数量级,从大约 9 多秒缩短到几分之一秒。

【讨论】:

  • 是的,虽然您应该明确地尝试理解事物的“原因”,但始终在实际数据集上进行测量并尝试不同的事物,以查看您的理论是否与数据库引擎的实际行为相匹配(你会感到惊讶...)
  • @Eelco 你是对的,但在这种情况下,结果实际上与基本理论非常吻合。只有当您有大约 50% 的可能性遇到与您的搜索匹配的项目时,它应该可以忽略不计的基本想法才有意义。然后,要找到 100 个匹配项,数据库需要迭代 200 个项目。但是,如果项目仅匹配 1% 的时间,则需要迭代 10,000 个项目。
  • 我喜欢人们在现场实际尝试并给予绩效提升反馈,而不仅仅是哲学。
  • WHERE my_col > 0 而不是 my_col = 1 似乎也有助于提高速度
【解决方案2】:

不是真的。你应该把它当作一本书来思考。如果一本书中只有 3 种单词并且您将它们全部编入索引,那么您的索引页数将与普通页数相同。

如果一个值的记录相对较少,则会提高性能。例如,如果您有 1000 条记录,其中 10 条为 TRUE,那么使用 isok = 1 搜索会很有用

正如迈克尔·杜兰特所说,它也会使写入速度变慢。

编辑:可能重复:Indexing boolean fields

这里解释了即使你有一个索引,如果你有太多的记录,它也不会使用索引。 MySQL not using index when checking = 1 , but using it with = 0

【讨论】:

  • 看起来像“是:2 - 否:1”。这里有人错了,但是谁?
  • 这并不完全正确,没有索引的mysql需要扫描整个表才能找到相关的行。
  • 否则它会扫描整个索引。 (在大多数情况下都一样长)
  • 这假定 TRUE 和 FALSE 之间的分布相等。正如下面@oucil 所提到的,如果您正在寻找一个相当罕见的布尔值,它仍然可能需要一段时间。并不是说您应该始终索引,但我会假设您的数据的性质和您的查询在大多数数据库引擎下也很重要。
  • @EdMassey - 不,RAM 与磁盘中的位置并不是那么简单。所有块(数据或索引)都根据需要在 buffer_pool 中“缓存”。所以任何一个块都可能在内存中,也可能不在内存中。
【解决方案3】:

这取决于实际查询和索引/查询组合的选择性。

案例A:条件WHERE isok = 1,没有其他内容:

SELECT *
FROM tableX
WHERE isok = 1
  • 如果索引有足够的选择性(假设您有 1M 行,而只有 1k 行有 isok = 1),那么 SQL 引擎可能会使用索引并且比不使用它更快。

  • 如果索引的选择性不够(比如你有 1M 行,超过 100k 有isok = 1),那么 SQL 引擎可能会不使用索引并做一个表扫描。

案例 B:条件 WHERE isok = 1 和更多内容:

SELECT *
FROM tableX
WHERE isok = 1
  AND another_column = 17

然后,这取决于您还有哪些其他索引。 another_column 上的索引可能比isok 上的索引更具选择性,后者只有两个可能的值。 (another_column, isok)(isok, another_column) 上的索引会更好。

【讨论】:

  • 我认为,与第一名相比,这是更正确的答案。还有数据的分布。
【解决方案4】:

这取决于数据的分布。

想象一下,我有一本书,有 1000 页紧密打印的页面,而我书中唯一的词是“是”和“否”,一遍又一遍地重复并随机分布。如果我被要求圈出所有“是”的实例,书后的索引会有所帮助吗?视情况而定。

如果是和否是随机分布的,那么在索引中查找将无济于事。索引会使这本书变得更大,无论如何我会更快地从前面开始,通过每一页寻找“是”的所有实例并圈出它们,而不是查找每个项目索引,然后将索引条目的引用指向它所引用的页面。

但是,如果在我这千页的​​书中只有十个“是”实例,而其他所有内容都只是数百万个“否”,那么索引将节省我大量时间来查找这十个“是”实例并绕着他们转。

在数据库中也是如此。如果是 50:50 分布,那么索引将无济于事 - 数据库引擎最好从头到尾遍历数据(全表扫描),索引只会使数据库更大,并且写入和更新速度较慢。但是,如果它类似于 4000:1 分布(根据此线程中的 oucil),那么如果它是您要查找的 4000 个项目中的 1 个,则索引查找可以大大加快它.

【讨论】:

  • 非常有用的类比,谢谢!
【解决方案5】:

不,通常不会。

当它们具有高选择性/基数时,您通常会为搜索建立索引。 在大多数表中,布尔字段的基数非常低。 它还会使您的写入速度稍微变慢。

【讨论】:

    【解决方案6】:

    实际上,这取决于您运行的查询。但是,通常是的,以及索引任何其他类型的字段。

    【讨论】:

      【解决方案7】:

      是的,索引会提高性能,请检查 EXPLAIN 有无索引的输出。

      来自文档:

      索引用于快速查找具有特定列值的行。如果没有索引,MySQL 必须从第一行开始,然后读取整个表以查找相关行。表越大,成本越高。如果表中有相关​​列的索引,MySQL 可以快速确定要在数据文件中间查找的位置,而无需查看所有数据。

      我认为在这种情况下,可以肯定地说索引不会降低性能,因此您只需从中获益。

      【讨论】:

      • 索引会在硬盘上提供大量数据,它会使写入速度变慢,因此您不仅可以从中受益。
      • 是的,但是在这种情况下,一个TINYINT(1) UNSIGNED列,数据的大小会很小。
      • 而且增加的写入开销可能相当低
      • 索引的大小不是会随着它指向的行数而增长,而不仅仅是索引字段的大小吗?
      【解决方案8】:

      索引只是一张地图。检索所有将 i​​s_xxx 设置为 true 的行是 O(1)。没有它,您需要扫描整个表并针对其中的每一行检查此谓词,即 O(n)

      【讨论】:

        猜你喜欢
        • 2013-11-22
        • 1970-01-01
        • 2013-06-06
        • 1970-01-01
        • 1970-01-01
        • 2010-12-23
        • 2015-01-03
        • 1970-01-01
        • 2019-12-05
        相关资源
        最近更新 更多