代码之家  ›  专栏  ›  技术社区  ›  Vishwajeet Gupta

在只有两种类型值的列上创建索引的效果如何

  •  2
  • Vishwajeet Gupta  · 技术社区  · 6 年前

    我在一个列上创建了一个索引,该列只有两个可能的值(Y和N),两个值的数据类型相同。

    假设列名是指示符。 我写了一个精选语句,比如,

    SELECT INDICATOR 
    FROM TEMP_TABLE 
    ORDER BY INDICATOR
    

    当我在SQL developer中对此查询使用explain plan时,它使用的是完整表扫描而不是索引扫描。

    为什么不使用索引表扫描。

    2 回复  |  直到 6 年前
        1
  •  7
  •   symcbean    6 年前

    为了在没有索引的表中查找记录,DBMS需要读取所有记录以查找匹配项。有了索引,DBMS只需要读取一组连续的记录就可以找到匹配项,然后在表中找到相应的记录。因此,当DBMS使用索引时,还有一个额外的步骤。

    粗略来说,如果从表中读取的记录超过5%,那么完整表扫描将比索引查找更快。

    但数据的分布也很重要。考虑99%的数据为“Y”的情况。使用索引来解析带有“Y”的记录将非常低效(应用我的经验法则相反,它将花费比完整表扫描长20倍的时间)。OTOH使用索引查找带有“N”的记录的效率将是完整表扫描的5倍。

    这就是Oracle对更复杂的索引属性使用直方图的原因。

    Oracle还有一个名为bind-peek的功能,它利用分布问题根据搜索的谓词选择最有效的查询。花点时间想想当查询模式与数据模式匹配时会发生什么情况-缓存的计划将取决于首先处理的查询版本。

    简短版本:不要对基数非常低的(一组)属性使用索引。

        2
  •  0
  •   mathguy    6 年前

    索引-至少在Oracle中,我不知道其他数据库-不会从底层列存储NULL。由于您要求从列中读取所有值,因此Oracle需要从基表中读取这些值(即使您只读取索引列,在这种情况下,无论基数估计和其他因素如何,都应该使用索引)。

    现在,也许你会说在你的列中没有空值-你真的是指你说的,每一行都有“Y”或“N”,没有空值。

    这是可以的,但只有在检索数据并检查数据后才能知道。相反,如果您希望按预期使用索引,Oracle需要知道,如果不先查看数据,该列中就不会有NULL。这意味着:您需要对表进行约束。如果事实上该列不应为NULL,则可以

    ALTER TABLE TEMP_TABLE MODIFY (INDICATOR NOT NULL);
    

    或者,

    SELECT INDICATOR 
    FROM TEMP_TABLE
    WHERE INDICATOR IS NOT NULL    --  ADDED! 
    ORDER BY INDICATOR
    

    将使用索引(试试!);但是,如果列不应该为NULL,那么为什么不使用约束显式表示呢。