【问题标题】:What is a Covered Index?什么是涵盖索引?
【发布时间】:2010-09-08 21:28:27
【问题描述】:

我刚刚在一些数据库讨论中听说过涵盖索引这个术语——它是什么意思?

【问题讨论】:

    标签: sql database indexing


    【解决方案1】:

    覆盖索引是一个索引,其中包含查询所需的所有列,甚至可能更多列。

    例如,这个:

    SELECT *
    FROM tablename
    WHERE criteria
    

    通常会使用索引来加快使用条件检索哪些行的分辨率,但随后它将转到整个表来检索行。

    但是,如果索引包含列column1、column2column3,那么这个sql:

    SELECT column1, column2
    FROM tablename
    WHERE criteria
    

    并且,如果可以使用特定索引来加快确定要检索的行,该索引已经包含您感兴趣的列的值,因此它不必去表中检索行,但可以直接从索引中生成结果。

    如果您发现典型查询使用 1-2 列来解析哪些行,然后通常添加另外 1-2 列,则也可以使用此方法,附加这些额外的列可能是有益的(如果它们是全部相同)到索引,以便查询处理器可以从索引本身获取所有内容。

    这是一个关于这个主题的article: Index Covering Boosts SQL Server Query Performance

    【讨论】:

    • 这里是对覆盖指数cubrid.org/cubrid_covering_index的深入解释。文章使用数字和真实的 SQL 示例提供了解释。还解释了 Covering Index 如何提高数据库性能。
    • 因此,如果我为 col1、col2 和 col3 创建覆盖索引作为一个索引,那么我知道使用 col1、2 和 3 的查询会很快,但如果我也有一个仅使用的查询怎么办col2 和 col3?它会使用覆盖索引还是会进行全表扫描?我应该为 col2 和 col3 的组合创建一个单独的覆盖索引吗?
    • 我在covered index上找到的最佳文章是:red-gate.com/simple-talk/sql/learn-sql-server/…
    【解决方案2】:

    覆盖索引只是一个普通的索引。如果不需要分析数据就可以满足查询,则称为“覆盖”。

    示例:

    CREATE TABLE MyTable
    (
      ID INT IDENTITY PRIMARY KEY, 
      Foo INT
    ) 
    
    CREATE NONCLUSTERED INDEX index1 ON MyTable(ID, Foo)
    
    SELECT ID, Foo FROM MyTable -- All requested data are covered by index
    

    这是从 SQL Server 检索数据的最快方法之一。

    【讨论】:

    • 吹毛求疵,但由于您的表定义包含一个主键,它会在该列 (ID) 上创建一个聚集索引,因此将 ID 列添加到非聚集索引是多余的。聚集键会自动添加到任何非聚集索引中。
    • @edosoft -- 您的评论可能是特定于数据库的。我的理解是,大多数数据库都会添加一个 row location 来寻址存储页面上的行。主键是一个逻辑标识符,而不是块级存储地址。如果您的提议是正确的,则不需要主键索引 - 实际上通常需要。
    【解决方案3】:

    覆盖索引是“覆盖”特定表所需的所有列的索引,完全无需为给定的查询/操作访问物理表。

    由于索引包含所需的列(或它们的超集),表访问可以替换为索引查找或扫描——这通常要快得多。

    要涵盖的列:

    • 参数化或静态条件;受参数化或恒定条件限制的列。
    • 加入列;动态用于连接的列
    • 选定的列;回答选定的值。

    虽然覆盖索引通常可以为检索提供良好的好处,但它们确实会增加插入/更新开销;由于需要在每次更新时写入额外或更大的索引行。

    连接查询的覆盖索引

    覆盖索引作为联合查询的一种性能技术可能是最有价值的。这是因为联合查询比单表检索更昂贵且更有可能遭受高性价比问题。

    • 在联合查询中,应将覆盖索引视为每个表。
    • 每个“覆盖索引”都会从计划中删除一个物理表访问,并将其替换为仅索引访问。
    • 调查计划成本并试验哪些表最值得用覆盖索引替换。
    • 通过这种方式,可以显着降低大型连接计划的乘法成本。

    例如:

    select oi.title, c.name, c.address
    from porderitem poi
    join porder po on po.id = poi.fk_order
    join customer c on c.id = po.fk_customer
    where po.orderdate > ? and po.status = 'SHIPPING';
    
    create index porder_custitem on porder (orderdate, id, status, fk_customer);
    

    见:

    【讨论】:

      【解决方案4】:

      假设您有一个包含以下列的简单表,您在这里只索引了 Id:

      Id (Int), Telephone_Number (Int), Name (VARCHAR), Address (VARCHAR)
      

      假设您必须运行以下查询并检查它是否使用索引,以及是否在没有 I/O 调用的情况下高效执行。请记住,您只在Id 上创建了一个索引。

      SELECT Id FROM mytable WHERE Telephone_Number = '55442233';
      

      当您检查此查询的性能时,您会感到失望,因为Telephone_Number 未编入索引,这需要使用 I/O 调用从表中获取行。所以,这不是一个覆盖索引,因为查询中有一些列没有被索引,这导致频繁的 I/O 调用。

      要使其成为覆盖索引,您需要在(Id, Telephone_Number) 上创建一个复合索引。

      更多详情,请参考这篇博客: https://www.percona.com/blog/2006/11/23/covering-index-and-prefix-indexes/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-26
        • 2010-10-11
        • 1970-01-01
        • 2012-10-17
        • 1970-01-01
        相关资源
        最近更新 更多