【问题标题】:index is not being used in oracle query with collection in where condition在条件条件下收集的 Oracle 查询中未使用索引
【发布时间】:2017-07-25 11:30:24
【问题描述】:

我有一个名为 MyTable 的事件表,在这个表中我有 MyTableId 列,我们在该列上创建了索引。该表有 7000 万行。 现在,我创建了一个清除过程,它基于表类型集合 MyTableCollection 清除事件。该集合有 100 行限制。因此,作为一个整体,我们一次可以清除 100 行。但是当我在 proc 中运行以下查询时,它卡住了 40 分钟。

DELETE  FROM MyTable
            WHERE   MyTableId IN (SELECT MyTableId FROM TABLE(MyTableCollection))

当我使用硬编码值对此查询运行分析器时,它显示索引范围扫描

DELETE  FROM MyTable
                WHERE   MyTableId IN (10,20,30)

后台查询中的collection是否起到了查询中不使用索引的作用?我在想 oracle 可能会对集合中获取的行数感到困惑。我对么 ?解决办法?

P.S:我正在考虑实施 FORALL 来删除行。

【问题讨论】:

  • 最好使用forall,因为您将使用MyTableId = col(i).MyTableId 之类的东西而不是in ()
  • 您也可以使用WHERE MyTableId MEMBER OF MyTableCollection(如果是简单的数字列表)。尝试未记录的提示 /*+ CARDINALITY(MyTableCollection 3) */ 告诉 Oracle 您的集合的大小(如果事先大致知道)
  • @Wernfried,我正在考虑使用提示。感谢您的帮助。

标签: oracle performance indexing collections plsql


【解决方案1】:

当你执行这个...

WHERE   MyTableId IN (10,20,30)

...优化器足够聪明,知道它将达到三行。但如果你这样做......

WHERE   MyTableId IN (SELECT /*+ CARDINALITY(MyTableCollection 3) */MyTableId FROM TABLE(MyTableCollection))

然后它不知道集合中有多少行。所以它假设有 8192 行,并相应地选择执行计划。

但是您可以使用cardinality 提示告诉优化器集合中有多少行:

WHERE   MyTableId IN (SELECT /*+ CARDINALITY(MyTableCollection 100) */
                      MyTableId FROM TABLE(MyTableCollection))

“这个表有 7000 万行”

顺便说一句,检查表统计信息的新鲜度是值得的,因为我们仍然希望优化器考虑索引来获得 8192/70000000 行。

【讨论】:

    猜你喜欢
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多