【问题标题】:Oracle multiple vs single column indexOracle 多列索引与单列索引
【发布时间】:2020-05-06 20:01:21
【问题描述】:

假设我有一个包含以下列的表格:

  1. 列:A (numer(10)) (PK)

  2. 列:B(数字(10))

  3. 列:C (numer(10))

    CREATE TABLE schema_name.table_name (
    column_a number(10) primary_key,
    column_b number(10) ,
    column_c number(10)
    );
    

A 列是我的 PK。

想象一下我的应用程序现在有一个由 B 和 C 查询的流。类似于:

SELECT * FROM SCHEMA.TABLE WHERE B=30 AND C=99

如果我只使用 B 列创建索引,这已经改善了我的查询,对吗?

此查询背后的策略将受益于 B 列上的索引?

Q1 - 如果是这样,我为什么要使用这两列创建索引?

Q2 - 如果我决定用 B 和 C 创建一个索引,如果我查询选择only B,这个会受到索引的影响吗?

【问题讨论】:

标签: sql oracle database-indexes


【解决方案1】:

嗯,这一切都取决于

如果该表很小,那么无论您创建任何索引,您都不会看到任何好处 - 它只是太小,Oracle 会立即返回数据。

如果表是巨大的,那么它取决于列的选择性。无法保证 Oracle 将永远使用该索引。如果优化器决定(根据它拥有的信息 - 不要忘记定期收集统计信息!)不应该使用索引,那么你创建它是徒劳的(虽然,你可以选择使用提示,但是 - 除非你知道什么你在做,别做)。

你怎么知道发生了什么?请参阅解释计划。

但是,一般来说,是的 - 索引有帮助。


Q1 - 如果是这样,我为什么要使用这两列创建索引?

哪“两列”? A?如果是主键列,Oracle 会自动创建索引,你不必这样做。


Q2 - 如果我决定用 B 和 C 创建一个索引,如果我查询只选择 B,这个会受到索引的影响吗?

如果您正在谈论复合索引(分别包含 B 和 C 列),并且如果查询使用 B 列,那么是的 - 将使用索引(好的,可能被使用)。但是,如果查询只使用 C 列,那么这个索引就完全没用了。

【讨论】:

  • 在问题 1 上,基本上是为了优化 B 和 C 选择的查询,如果我应该用 B 和 C 创建一个复合索引,或者如果一个索引只使用 B(所以它也会涵盖,B) 的查询也会得到优化。
【解决方案2】:

简短回答:始终检查实际性能,而不是理论。这意味着,我的答案需要在真实数据库中进行验证。

在 SQL(Oracle、Postgre、MsSql 等)内部,主键至少用于两个目的:

  • 行的顺序(例如,如果 PK 仅增加,则所有值都将被追加)
  • 链接到行。这意味着如果您有任何额外的索引,它将包含整个 PK 以便能够从额外的索引跳转到其他行。

如果我只使用 B 列创建索引,这已经改进了我的查询,对吧? 此查询背后的策略将受益于 B 列上的索引?

这取决于。如果您的表太小,Oracle 可以对其进行全盘扫描。对于大型表,Oracle 可以(并且将在常见情况下)使用 B 列的索引,然后使用 range scan。在这种情况下,Oracle 检查所有 B=30 的值。因此,如果您只能使用 B=30 的一行,那么您可以获得良好的性能。如果您有数百万这样的行,Oracle 将需要进行数百万次读取。 Oracle 可以通过via statistic获取此信息。

Q1 - 如果是这样,我为什么要使用这两列创建索引?

需要直接访问行。在这种情况下,Oracle 只需几次跳转即可找到您的行。此外,您可以应用unique 修饰符来帮助Oracle。然后它就会知道,不会返回多于一行。

但是,如果您的表有其他列,实际执行计划将包括对 PK 的访问(以检索其他行)。

如果我决定用B和C创建一个索引,如果我查询只选择B,这个会受索引的影响吗?

是的。 Please check the details here。如果索引有多个列,Oracle 将根据列顺序对它们进行排序。例如。如果您使用列 B, C 创建索引,那么 Oracle 将能够使用它来检索诸如“B=30”之类的值,例如当你只限制 B.

【讨论】:

    【解决方案3】:

    您的问题的简单答案。

    对于这个查询:

    SELECT *
    FROM SCHEMA.TABLE
    WHERE B = 30 AND C = 99;
    

    (B, C)(C, B) 的最佳索引。顺序确实很重要,因为两个比较是=

    可以使用任一列上的索引,但需要扫描所有匹配值以与第二个值进行比较。

    如果您在(B, C) 上有一个索引,那么它可以用于WHERE B = 30 上的查询。 Oracle 还实现了跳过扫描优化,因此该索引也有可能用于WHERE C = 99——但可能不会。

    我认为documentation for MySQL 对多列索引有很好的介绍。它不包括跳过扫描,但在其他方面非常适用于 Oracle。

    【讨论】:

      【解决方案4】:

      尽管已经回答了这个问题并且已经接受了一个答案,但我还是会提供更多信息:-)

      索引是对 DBMS 的一种提议,它可以在某些情况下更快地访问数据。是否实际使用索引由 DBMS 决定。

      Oracle 有一个内置的优化器,它会查看查询并尝试找到最佳执行计划以获得您想要的结果。

      假设所有行中有 90% 有 B = 30 AND C = 99。那么,为什么 Oracle 要费力地遍历索引,最后却不得不访问表中的几乎每一行呢?因此,即使在两列上都有索引,Oracle 也可能决定根本不使用索引,甚至会因为针对索引的决定而更快地执行查询。

      现在回答问题:

      如果我只使用 B 列创建索引,这已经改进了我的查询,对吗?

      可能。如果 Oracle 认为 B = 30 大大减少了它必须从表中读取的行数,它会的。

      如果是这样,我为什么要使用这两列创建索引?

      如果B = 30 AND C = 99 的组合限制了从表中进一步读取的行,则最好使用此索引。

      如果我决定用B和C创建一个索引,如果我查询只选择B,这个会受索引的影响吗?

      如果索引位于(B, C),即首先是 B,那么 Oracle 可能会发现它很有用,是的。在表中只有两列的极端情况下,这甚至是一个覆盖索引(即包含查询中访问的所有列)并且 DBMS 不必读取任何表行,因为所有信息都是已经在索引本身中。如果索引是(C, B),即首先是 C,则不太可能使用该索引。不过,在某些极端情况下,Oracle 可能会这样做。

      【讨论】:

        猜你喜欢
        • 2018-07-27
        • 1970-01-01
        • 2013-11-05
        • 2011-11-07
        • 2010-09-15
        • 1970-01-01
        • 2021-09-01
        • 2016-05-17
        相关资源
        最近更新 更多