使用具有低基数的索引是否有意义?

时间:2010-01-21 21:46:46

标签: sql indexing cardinality

我主要是一个Actionscript开发人员,绝不是SQL专家,但我不得不开发简单的服务器端。所以,我想我会在标题中向更有经验的人询问这个问题。

我的理解是,通过在一个包含很少不同值的列中设置索引,您不会获得太多收益。我有一个包含布尔值的列(实际上它是一个小的int,但我将它用作标志),并且此列用于我所拥有的大多数查询的WHERE子句中。在理论上的“平均”情况下,一半的记录值将为1而另一半为0.因此,在这种情况下,数据库引擎可以避免全表扫描,但无论如何都必须读取大量行(总行/ 2)。

那么,我应该将此列作为索引吗?

为了记录,我正在使用Mysql 5,但是我更感兴趣的是一般理由为什么它对我知道哪个列基数较低的列索引/没有意义。

提前致谢。

5 个答案:

答案 0 :(得分:69)

如果符合以下情况,索引甚至可以在低基数字段中提供帮助:

  1. 当其中一个可能的值与其他值相比非常罕见并且您搜索它时。

    例如,色盲女性很少,所以这个查询:

    SELECT  *
    FROM    color_blind_people
    WHERE   gender = 'F'
    

    最有可能受益于gender上的索引。

  2. 当值倾向于按表顺序分组时:

    SELECT  *
    FROM    records_from_2008
    WHERE   year = 2010
    LIMIT 1
    

    虽然此处只有3个不同的年份,但最早的年份记录最有可能首先添加,因此如果不是索引,则必须在返回第一个2010记录之前扫描很多记录

  3. 当您需要ORDER BY / LIMIT时:

    SELECT  *
    FROM    people
    ORDER BY
            gender, id
    LIMIT 1
    

    如果没有索引,则需要filesort。虽然它对LIMIT做了一些优化,但它仍然需要全表扫描。

  4. 当索引涵盖查询中使用的所有字段时:

    CREATE INDEX (low_cardinality_record, value)
    
    SELECT  SUM(value)
    FROM    mytable
    WHERE   low_cardinality_record = 3
    
  5. 当您需要DISTINCT时:

    SELECT  DISTINCT color
    FROM    tshirts
    

    MySQL将使用INDEX FOR GROUP-BY,如果您的颜色很少,即使有数百万条记录,此查询也会即时显示。

    这是一个场景的示例,当低基数字段上的索引 比高基数字段上的更多时。

  6. 请注意,如果问题的DML性能不是很高,那么创建索引是安全的。

    如果优化器认为索引效率低下,则不会使用索引。

答案 1 :(得分:9)

在复合索引中包含boolean字段可能是值得的。例如,如果您有一个大型消息表,通常需要按日期排序,但您还有一个布尔已删除字段,那么您经常会这样查询:

SELECT ... FROM Messages WHERE Deleted = 0 AND Date BETWEEN @start AND @end

已删除日期字段上使用复合索引肯定会受益。

答案 2 :(得分:3)

我通常做一个简单的“有索引”和“没有”索引测试。根据我的经验,您可以获得使用ORDER BY索引列的查询的大部分性能。如果您对该列进行了任何排序,索引很可能会有所帮助。

答案 3 :(得分:2)

恕我直言,它的用处有限。我假设在大多数情况下,除了可能有助于提供更多帮助的标志之外,您还在查询中使用了其他标准。

在50%时,我可能会做/不用的基准测试,看看它是否有很大的不同。

答案 4 :(得分:0)

当记录的一半值是1,另一半值是0时,就没有必要在该列上放置索引了。查询优化器可能不会使用它。

但是,通常情况下,您有少量的“活动”记录集和越来越多的“非活动”记录集。例如,在错误跟踪系统中,您关心的是活动的错误,而几乎不关心已完成和已存档的错误。对于这种情况,诀窍是使用“ dateInactivated”列来存储记录被停用/删除的时间戳。顾名思义,当记录处于活动状态时,该值为NULL,但一旦将其禁用,则将其写入系统日期时间。因此,随着“已删除”记录数的增加,该列上的索引最终具有很高的选择性,因为每个记录都将具有唯一的值(严格来说不是)。该查询将具有

"... AND dateInactivated is NULL ..." 

作为谓词和索引的一部分,将只提取您关心的正确的行集。