我主要是Actionscript开发人员,但绝不是SQL方面的专家,但是我有时会不得不开发简单的服务器端内容。因此,我想我会问更多有经验的人关于标题中的问题。
我的理解是,通过在将只包含少量不同值的列中设置索引不会带来太多收益。我有一列保存一个布尔值(实际上是一个小整数,但我将其用作标志),并且此列用于我拥有的大多数查询的WHERE子句中。在理论上的"平均"情况下,记录值的一半将为1,另一半为0。因此,在这种情况下,数据库引擎可以避免全表扫描,但无论如何都必须读取很多行(总行数/ 2)。
那么,我应该将此列作为索引吗?
作为记录,我使用的是Mysql 5,但我对这样的一般理由更感兴趣:为何对我知道索引基数较低的列进行索引/没有意义。
提前致谢。
如果满足以下条件,索引甚至可以在低基数字段上提供帮助:
与其他值相比,当其中一个可能的值很少出现时,您可以进行搜索。
例如,几乎没有色盲女性,因此此查询:
SELECT *
FROM color_blind_people
WHERE gender = 'F'
将最有可能受益于gender上的索引。
当值倾向于按表顺序分组时:
SELECT *
FROM records_from_2008
WHERE year = 2010
LIMIT 1
尽管这里只有3个不同的年份,但是很可能首先添加了较早年份的记录,因此如果没有索引,则在返回第一个2010记录之前必须先扫描很多记录。
当您需要ORDER BY / LIMIT时:
没有索引,将需要filesort。尽管对LIMIT做了一些优化,但仍然需要全表扫描。
当索引涵盖查询中使用的所有字段时:
CREATE INDEX (low_cardinality_record, value)
SELECT SUM(value)
FROM mytable
WHERE low_cardinality_record = 3
当您需要DISTINCT时:
MySQL将使用INDEX FOR GROUP-BY,并且如果您的颜色很少,即使有数百万条记录,该查询也将是即时的。
这是低基数字段上的索引比高基数字段上的索引更有效的情况的示例。
请注意,如果DML性能不是问题,那么创建索引是安全的。
如果优化器认为索引效率低下,那么将仅不使用索引。
很好的例子!
可能值得在复合索引中包含布尔字段。例如,如果您有一个大型的邮件表,通常需要按日期对邮件进行排序,但是还具有一个布尔的Deleted字段,那么您通常会这样查询:
如果在Deleted和Date字段上具有复合索引,您肯定会从中受益。
谢谢。 也许我应该对综合指数进行一些研究(我只知道它的存在,但还没有真正使用它们)。 我以与示例代码非常相似的方式使用此列(尽管存在联接和其他内容,但是WHERE子句始终具有用于标记软删除的标志)。
有关复合索引为何在这种情况下非常有用以及布尔值为何应优先出现的进一步讨论:stackoverflow.com/questions/50239658/
我通常会做一个简单的"有索引"与"没有"索引测试。以我的经验,在使用ORDER BY索引列的查询上,您可以获得大部分性能。如果您对该列进行任何排序,则索引很有可能会有所帮助。
感谢您的回答。 在这种情况下,我不会在该列上进行排序。 它仅在此处将记录标记为启用/禁用。 我基本上使用它进行软删除。 这就是为什么我必须在大多数查询的WHERE子句中使用它的原因。
恕我直言,其用途有限。我认为在大多数情况下,除了该标志外,您在查询中还会使用其他条件,这可能会带来更多帮助。
在50%的情况下,我可能会进行一些基准测试(有/没有),看是否有很大的不同。
当记录的一半值是1而另一半值是0时,就没有必要在该列上放置索引了。查询优化器可能不会使用它。
但是,通常情况下,您有少量的"活动"记录和越来越多的"非活动"记录。例如,在错误跟踪系统中,您关心的是活动的错误,而几乎不关心已完成和已存档的错误。对于这种情况,诀窍是使用" dateInactivated"列来存储记录被停用/删除的时间戳。顾名思义,当记录处于活动状态时,该值为NULL,但一旦将其禁用,则将其写入系统日期时间。因此,随着"已删除"记录数的增加,该列上的索引最终具有很高的选择性,因为每个记录都将具有唯一的值(严格来说不是)。该查询将有
"... AND dateInactivated is NULL ..."
作为谓词的一部分,索引将只提取您关心的正确的行集。