MySQL:低基数/选择性列=如何索引?

Jan*_*Jan 40 mysql database

我需要在我的表(列)中添加索引并偶然发现这篇文章:

有多少数据库索引太多了?

Quote:"话虽如此,你可以明确地添加很多无意义的索引到一个不会做任何事情的表.将B-Tree索引添加到具有2个不同值的列将是没有意义的,因为它不会在查找数据方面添加任何内容.列中的值越独特,它就越能从索引中受益."

如果只有两个不同的值,那么指数真的没有意义吗?给出如下表(MySQL数据库,InnoDB)

Id (BIGINT)
fullname (VARCHAR)
address (VARCHAR)
status (VARCHAR)
Run Code Online (Sandbox Code Playgroud)

更多条件:

  • 该数据库包含3亿条记录
  • 状态只能"启用"和"禁用"
  • 1.5亿条记录的状态=启用,1.5亿条记录的状态=已禁用

我的理解是,如果没有状态索引,select where status=’enabled’会导致完整的表扫描有3亿条记录要处理吗?

当我在状态上使用BTREE索引时查找的效率如何?

我应该索引这个专栏吗?

MySQL InnoDB提供了哪些替代方案(可能是任何其他索引),通过给定示例中的"where status ="enabled"子句有效地查找记录,并且值的基数/选择性非常低?

a'r*_*a'r 38

您描述的索引几乎毫无意义.当您需要选择与总行数相比较少的行时,最好使用索引.

其原因与数据库访问表的方式有关.可以通过全表扫描来评估表,其中每个块依次被读取和处理.或者通过rowid或key查找,其中数据库具有键/ rowid并读取它所需的确切行.

在您使用基于主键或其他唯一索引的where子句的情况下,例如.where id = 1,数据库可以使用索引来准确引用行的数据存储位置.这显然比进行全表扫描和处理每个块更有效.

现在回到你的例子,你有一个where子句where status = 'enabled',索引将返回150m行,数据库必须使用单独的小读取依次读取每一行.而使用全表扫描访问表允许数据库使用更有效的更大读取.

有一点,最好只进行全表扫描而不是使用索引.使用mysql,您可以将其FORCE INDEX (idx_name)用作查询的一部分,以允许在每个表访问方法之间进行比较.

参考:http: //dev.mysql.com/doc/refman/5.5/en/how-to-avoid-table-scan.html

  • 我明白你在说什么,但通常会有一些其他限制因素.例如,假设他增加了限制10,那么指数更好,不是吗?我想有人问你是对的 (2认同)

ext*_*eon 11

我很遗憾地说我不同意迈克.添加索引意味着限制MySQL的完整记录搜索量,从而限制通常是瓶颈的IO.

这个索引不是免费的; 你需要更新索引时在插入/更新和搜索本身上付费,因为它现在需要加载索引文件(300M记录的全文索引可能不在内存中).所以很可能你得到额外的 IO而不是限制它.

我同意二进制变量最好存储为一个bool或tinyint的说法,因为这会减少行的长度,从而可以限制磁盘IO,同时数字的比较也更快.

如果您需要速度并且很少使用禁用的记录,您可能希望有2个表,一个用于启用,一个用于禁用记录,并在状态更改时移动记录.由于它增加了复杂性和风险,这将是我最后的选择.如果你碰巧去了它,肯定会在1次交易中进行.

它只是突然出现在你的脑海中,你可以通过使用explain语句检查实际使用的索引.这应该向您展示MySQL如何优化查询.我真的不知道MySQL优化查询,但是从postgresql我知道你应该在数据库上解释一个与真实数据库大致相同(大小和数据)的查询.因此,如果您在数据库上有一个副本,请在表上创建一个索引,然后查看它实际使用的是什么.正如我所说,我对此表示怀疑,但我绝对不知道一切:)

  • +1使用分区或2个单独的表是一个很好的建议. (3认同)

Ana*_*var 7

如果数据像50:50那样分发,那么查询就像在哪里status="enabled"将避免半扫描表.

在这些表上具有索引完全取决于数据的分布,即,如果具有启用状态的条目是90%而其他条目是10%.对于查询,status="disabled"它只扫描表的10%.

所以在这些列上有索引取决于数据的分布.


dr0*_*r01 5

@a'r 答案是正确的,但是需要指出的是,索引的有用性不仅取决于其基数,还取决于数据的分布和在数据库上运行的查询。

在 OP 的情况下,有 150M 条记录status='enabled'和150M 条记录status='disabled',索引是不必要的,浪费资源。

在 299M 条记录status='enabled'和 1M条记录的情况下status='disabled',索引在类型为 的查询中很有用(并将被使用)SELECT ... where status='disabled'
类型查询SELECT ... where status='enabled'仍将使用全表扫描运行。