Oracle 多列索引与单列索引

Oracle multiple vs single column index

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

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

  2. 列:B (numer(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 创建一个索引,如果我查询只选择 B,这个会受到索引的影响吗?

嗯,这一切 取决于

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

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

你怎么知道发生了什么?查看解释计划。

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


Q1 - If so, why should I create an index with those two columns?

哪个"two columns"? A?如果是主键列,Oracle 会自动创建索引,你不必那样做。


Q2 - If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?

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

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

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

  • 行的排序(例如,如果 PK 仅递增,则将附加所有值)
  • Link来排。这意味着如果你有任何额外的索引,它将包含整个 PK 以便能够从额外的索引跳转到其他行。

If I create an index only using the Column B, this will already improve my query right? The strategy behind this query would benefit from the index on column B?

视情况而定。如果您的 table 太小,Oracle 可以对其进行全面扫描。对于大型 table Oracle 可以(并且将在常见情况下这样做)对 B 列使用索引,然后执行 range scan. In this case Oracle check all values with B=30. Therefore, if you can only one row with B=30 then you can achieve good performance. If you have millions of such rows, Oracle will need to do million of reads. Oracle can get this information via statistic.

Q1 - If so, why should I create an index with those two columns?

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

但是,如果您的 table 有其他列,真正的执行计划将包括访问 PK(检索其他行)。

If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?

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

您问题的简单答案。

对于此查询:

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。

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

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

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

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

现在回答问题:

If I create an index only using the Column B, this will already improve my query right?

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

If so, why should I create an index with those two columns?

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

If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?

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