【问题标题】:Does index still exists in these situations?在这些情况下索引是否仍然存在?
【发布时间】:2021-03-05 02:14:37
【问题描述】:

我有一些关于索引的问题。

首先,如果我在 WITH 子句中使用索引列,该列是否仍可用作主查询中的索引列?

例如,

WITH TEST AS (
SELECT EMP_ID
FROM EMP_MASTER
)

SELECT *
FROM TEST
WHERE EMP_ID >= '2000'

“EMP_MASTER”表中的“EMP_ID”是 PK,EMP_MASTER 的索引由 EMP_ID 组成。

在这种情况下,“索引扫描”是否发生在主查询中?

其次,如果我加入两个表,然后在 WHERE 中使用每个表中的两个索引列,会发生“索引扫描”吗?

例如,

SELECT *
FROM A, B
WHERE A.COL1 = B.COL1 AND
      A.COL1 > 200 AND
      B.COL1 > 100

表 A 的索引由“COL1”组成,表 B 的索引由“COL1”组成。

在这种情况下,在表连接之前是否会在每个表中发生“索引扫描”?

如果你能给我一些正确的建议,我真的很感激。

【问题讨论】:

  • 您应该在查询上运行 EXPLAIN 以查看发生了什么。
  • 不要忘记一个表可以有多个索引,而这些索引可以覆盖多个列。
  • 答案可以这样表述:如果索引存在,优化器可能会或可能不会选择使用它们(基于几个考虑)。但是,with 子句和连接的 where 子句中存在的谓词都不会阻止优化器使用索引。我相信这确实是您的问题 - 要么单独使用 with 子句,要么单独使用连接,无需其他原因,阻止使用索引?答案是明确的“不”。如果您有未使用索引的实际案例,则必须寻找其他原因。

标签: sql database oracle


【解决方案1】:

首先,SQL 是一种声明性 语言,而不是过程 语言。也就是说,一个 SQL 查询描述的是结果集,而不是具体的处理。 SQL 引擎使用优化器来确定生成结果集的最佳执行计划。

第二,Oracle有合理的优化器。

因此,Oracle 可能会在这些情况下使用索引。但是,您应该查看执行计划以了解 Oracle 的真正作用。

【讨论】:

  • 感谢您给我很好的建议。我想再问第一个问题以进行仔细检查。当我写下来时,我使用 WITH 创建了一个虚拟表('TEST' 表)。这个虚拟表是用物理表('EMP_MASTER'表)制作的。此虚拟表具有“EMP_ID”列,该列是 PK 和“EMP_MASTER”表中的第一个索引列。在这种情况下,优化器可以像“现在,EMP_ID 列来自虚拟表('TEST' 表)但该列是物理表('EMP_MASTER'表)中的第一个索引列。因此,使用索引是合理的."?
  • 另外,我真的很想检查执行计划,但在我的情况下无法检查。这就是我问这个的原因。
  • @WooseokChoi 。 . .执行的是有向无环图 (DAG)。这与查询几乎没有关系,看起来与查询完全不同。 Oracle 的优化器通常足够聪明,可以确定过滤器可以使用索引——没有承诺,因为优化器可能很挑剔并且可能会混淆——但它通常会做正确的事情。
【解决方案2】:

首先,如果我在 WITH 子句中使用索引列,该列是否仍可用作主查询中的索引列?

是的。 CTE(WITH 部分)与任何其他查询一样 - 如果查询引用索引使用的物理表列,那么引擎将使用索引如果它认为这是一个好主意.

在这种情况下,“索引扫描”是否发生在主查询中?

根据您提供的有限信息,我们无法判断。引擎将根据其关于索引中数据分布的启发式(例如STATISTICS 对象)和它拥有的其他信息(例如缓存的查询执行计划)来​​扫描或查找索引。

在这种情况下,在表连接之前是否会在每个表中发生“索引扫描”?

由于它是一个范围查询,引擎使用索引扫描而不是索引搜索可能是有意义的 - 但它也可以进行表扫描并忽略索引,如果索引不够选择性和具体。还要考虑查询标志以强制读取未提交的数据(例如,为了提高性能和避免锁定)。

【讨论】:

    猜你喜欢
    • 2011-09-04
    • 2014-07-08
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    相关资源
    最近更新 更多