【问题标题】:Query not using indexes using using Table function使用 Table 函数查询不使用索引
【发布时间】:2016-12-03 20:14:04
【问题描述】:

我有以下查询:

select i.pkey as instrument_pkey,
       p.asof,
       p.price,
       p.lastprice as lastprice,
       p.settlementprice as settlement_price,
       p.snaptime,
       p.owner as source_id,
       i.type as instrument_type
from quotes_mxsequities p,
     instruments i,
     (select instrument, maxbackdays
      from TABLE(cast (:H_ARRAY as R_TAB))) lbd
where p.asof between :ASOF - lbd.maxbackdays and :ASOF
  and p.instrument = lbd.instrument
  and p.owner = :SOURCE_ID
  and p.instrument = i.pkey

自从我开始使用表函数以来,查询已经开始对表quotes_mxsequities进行全表扫描,这是一个大表。

之前我使用IN 子句时,包含表函数索引。

关于如何强制使用索引有什么建议吗?

编辑:

我将尝试获得解释计划,但只是补充一下,H_ARRAY 预计会有大约 10k 条目。 quotes_mxsequities 是一个数百万行的大表。 Instruments 又是一个大表,但行数少于quotes_mxsequitiesquotes_mxsequities 正在进行全表扫描,而 instruments 正在使用索引

【问题讨论】:

  • HARRAYquotes_mxsequities 中数据的一小部分吗?表中有多少行,您希望匹配多少行?即索引实际上是否合适?
  • @Alex:HARRAY 可以有大约 10k 行,而 quotes_mxsequities 是一个包含数百万行的巨大表。我们期望匹配大约 200 万行。
  • 如果您要匹配数百万甚至数千万行中的 200 万行,那么全表扫描可能会更有效。您只是看到了不同的计划,还是性能实际上比 IN 更差 - 假设数组和匹配数据相同?
  • @Alex:因此,如果它使用索引并在 2-3 分钟内完成,则它的性能非常好,而使用全表扫描则需要数小时。使用 in 子句大约需要 4 分钟。
  • 好的,基数提示有帮助吗?我不确定它是否会与那么大但值得尝试的阵列一起使用。或者动态采样提示,也许?

标签: sql oracle performance oracle12c


【解决方案1】:

没有解释计划和有关表结构、行数等信息,很难回答。

作为一种通用的简化方法,您可以尝试通过 INDEX hint 强制使用索引。

您的问题甚至可能是由于表格处理中的错误顺序造成的;您可以尝试使用 LEADING hint 使 Oracle 遵循正确的顺序(我想首先是 LBD)。

另一点可能是完全访问权限,而您可能需要一个嵌套循环;在这种情况下,您可以尝试USE_NL hint

【讨论】:

    【解决方案2】:

    很难从所提供的有限信息中确定,但看起来这是优化器无法确定表集合表达式的基数的问题,因为它的内容在解析时是未知的。使用存储的嵌套表可以使用统计信息,但这里没有可用的统计信息。

    如果没有这些信息,优化器默认猜测您的表集合将有 8K 条目,并将其用作基数估计;如果这是quotes_mxsequities 中行数的很大一部分,那么它将决定索引效率不高,并将使用全表扫描。

    您可以使用undocumented cardinality hint 告诉优化器您在集合中实际期望的元素数量;您大概不会确切知道,但您可能知道您通常期望大约 10 个。所以您可以添加一个提示:

    select /*+ CARDINALITY(lbd, 10) */ i.pkey as instrument_pkey,
    

    您可能还会发现这里的动态采样提示很有用,但如果没有要查看的真实数据,基数提示适用于基本执行计划,因此很容易看到它的效果。

    顺便说一句,你不需要对表表达式的子查询,你可以稍微简化为:

    from TABLE(cast (:H_ARRAY as R_TAB)) lbd,
         quotes_mxsequities p,
         instruments i
    

    甚至更好地使用现代连接语法:

    select /*+ CARDINALITY(lbd, 10) */ i.pkey as instrument_pkey,
           p.asof,
           p.price,
           p.lastprice as lastprice,
           p.settlementprice as settlement_price,
           p.snaptime,
           p.owner as source_id,
           i.type as instrument_type
    from TABLE(cast (:H_ARRAY as R_TAB)) lbd
    join quotes_mxsequities p
    on p.asof between :ASOF - lbd.maxbackdays and :ASOF
      and p.instrument = lbd.instrument
    join instruments i
    on i.pkey = p.instrument
    where p.owner = :SOURCE_ID;
    

    【讨论】:

      猜你喜欢
      • 2021-12-09
      • 2013-05-25
      • 2013-05-19
      • 1970-01-01
      • 2012-05-21
      • 2013-07-10
      • 2019-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多