【问题标题】:How to reduce the execution time of the following query in Oracle?如何减少Oracle中以下查询的执行时间?
【发布时间】:2012-03-27 09:48:16
【问题描述】:

我在 Oracle 11g 中编写了以下 SQL 查询。

SELECT p.matchcode      pmatchcode,
       p1.matchcode     p1matchcode,
       p.digits         digit,
       p1.effectivedate peff,
       p1.expirydate    pexp,
       p.expirydate     p1exp,
       p.tariff_id      tariff_id
  FROM tt_matchcodes_view p1
  JOIN tt_matchcodes_view p
    on p.tariff_id = p1.tariff_id
   AND p.type_id = p1.type_id
   AND p1.Digits = p.Digits
   AND p.matchcode <> p1.matchcode
   AND p1.EffectiveDate < p.expirydate
   AND (p1.expirydate IS NULL OR p1.expirydate > p.expirydate)
   AND substr(p.matchcode, 0, length(p1.matchcode)) = p1.matchcode;

tt_matchcodes_view 表有 71392 条记录。我在该表的字段matchcode and digits 上创建了两个索引。执行需要 10 多分钟。有没有办法减少执行时间。

样本表数据:

MATCHCODE   DIGITS  DEST_ID MATCH   EFFECTIVEDATE   EXPIRYDATE  INHERITED   TARIFF_ID   TYPE_ID
1787    1787    73999   1   01/03/2012      0   22  1
1787201 1787    73999   0   01/03/2012      -1  22  1
1787202 1787    73999   0   01/03/2012      -1  22  1
1787203 1787    73999   0   01/03/2012      -1  22  1
1787204 1787    73999   0   01/03/2012      -1  22  1
1787205 1787    73999   0   01/03/2012      -1  22  1
1787206 1787    73999   0   01/03/2012      -1  22  1
1787207 1787    73999   0   01/03/2012      -1  22  1
1787208 1787    73999   0   01/03/2012      -1  22  1
1787212 1787    73999   0   01/03/2012      -1  22  1

执行计划:

OPERATION   OPTIONS OBJECT_NAME OBJECT_INSTANCE OPTIMIZER   ID  PARENT_ID   DEPTH   POSITION    COST    CARDINALITY BYTES   CPU_COST    IO_COST
SELECT STATEMENT                ALL_ROWS    0       0   703 703 3   501 83322403    698
HASH JOIN                   1   0   1   1   703 3   501 83322403    698
TABLE ACCESS    FULL    TT_MATCHCODES_VIEW  2       2   1   2   1   95  65498   5174342 22711001    94
TABLE ACCESS    FULL    TT_MATCHCODES_VIEW  1       3   1   2   2   95  65498   5763824 22711001    94

提前致谢。

【问题讨论】:

  • 你为什么有substr(p.matchcode, 0, length(p1.matchcode))?这是没有意义的。同样正如@GauravSoni 提到的,请编辑并添加执行计划
  • 您将tt_matchcodes_view 描述为一张表格,但它的名字暗示了一些不同的东西。那么,它真的是一个表还是一个视图?
  • P1 的匹配码应该出现在 P 匹配码中。这就是我将 SUBSTR 保留在那里的原因。 tt_matchcodes_view 只是一个临时表,不是视图[忽略名称]。
  • 查询返回多少行?您是如何执行查询的(在 TOAD 中,在某些编程语言中,在 PL/SQL 中)?它是 Oracle 意义上的临时表(GLOBAL TEMPORARY TABLE),还是仅仅因为您不在生产系统中使用它?该表是否包含 BLOB 或 CLOB 列?
  • 查询返回 2686 行。我在 pl/sql 过程中使用它。我确实使用 pl/sql 开发人员进行了调试。在那里我发现它需要时间,它是一个全局临时表,它没有任何 CLOB 或 BLOB 列。

标签: sql oracle oracle11g


【解决方案1】:

您的表格有超过 70000 行。您正在选择其所有记录两次,并根据不等式比较行。所以基本上你正在将每一行与表中的每一行进行比较。 (实际上并非全部,因为不是 TARIFF_ID 或 TYPE_ID 或 DIGITS 不匹配的那些,但似乎并不多)这是〜490,000,000次比较。在这种情况下,十分钟的执行时间似乎并不算太​​糟糕。

解释计划表明甲骨文选择了最好的计划。您所能做的就是为 Oracle 提供一个更有用的索引来改进它。使用 where 子句中所有列的复合索引可能会有所帮助。像这样的:

create index super_match_idx on tt_matchcodes_view
    (tariff_id, .type_id, digits, matchcode, expirydate, effectivedate )    

这可能会在索引上为您提供两次 FULL FAST SCANS,这应该比两次 FULL TABLE SCAN 操作更快。

顺便说一句,您在填充临时表时是否对数据进行了排序?使用与索引对齐的 ORDER BY 将提高聚类因子。因此,您可能会获得更快的检索,因为所有匹配的行更有可能位于连续块中。

我通常不建议对堆表中的行进行排序,但由于您已经支付了插入临时表的开销,因此您不妨得到尽可能多的回报。

哦,substr(p.matchcode, 0, length(p1.matchcode)) 是一个致命的赠品。智能钥匙很烂!无论如何,是否存在 SUBSTR() 调用返回的值与 DIGITS 不匹配的情况? (同样,您的样本数据不明确。)如果 DIGITS 可靠地识别 SUBTSR() 的输出,我建议您放弃最后一行。

【讨论】:

    【解决方案2】:

    由于这是一个全局临时表,您必须填充它,然后在同一个会话甚至事务中执行查询。这让我想知道 Oracle 是否在表为空时收集了有关表的统计信息,而这并不能反映其实际内容。您可以尝试在运行查询之前收集统计信息。如果这样可行,并且预计表的内容在每次运行之间不会有太大差异,那么您可能只想固定这些统计信息,这样它们就不会被替换。

    但是,根据您目前提供的信息,我不确定 Oracle 是否可以提出更好的计划。考虑到谓词中的条件,仅matchcode 上的索引不太可能用于此查询。可以使用digits 上的索引,但由于您将表连接到自身,这可能比仅执行两次完整扫描效率低,因为digits 上总会有匹配项(除非它为 NULL,如果有的话)。

    我们需要了解有关谓词中哪些条件过滤掉最多行的更多详细信息,以便提出更多建议。假设 matchcode 上的不等式是主要过滤器,您可能会从 (digits,matchcode) 上的单个索引中获得一些好处——它可能会与自身连接索引并消除之前的很多行完全去餐桌。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-29
      • 2020-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-09
      相关资源
      最近更新 更多