如何减少Oracle中以下查询的执行时间?

时间:2012-03-27 09:48:17

标签: sql oracle oracle11g

我在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
提前谢谢。

2 个答案:

答案 0 :(得分:2)

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

解释计划表明Oracle已经选择了最好的计划。所有你能做的就是改进它将为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))是一个死的赠品。智能钥匙是Teh Suck!无论如何,是否存在SUBSTR()调用返回与DIGITS不匹配的值的情况? (同样你的样本数据是模糊的。)如果DIGITS可靠地识别SUBTSR()的输出,我建议你放弃最后一行。

答案 1 :(得分:1)

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

但是,根据您迄今为止提供的信息,我不确定甲骨文能否提出更好的计划。鉴于谓词中的条件,单独matchcode上的索引不可能用于此查询。可以使用digits上的索引,但由于您将表连接到自身,因此可能效率低于仅进行两次完整扫描,因为digits上始终存在匹配(除了matchcode当它为NULL时,如果有的话。)

我们需要了解有关谓词中哪些条件过滤掉大多数行以提出更多建议的更多详细信息。假设digits上的不等式是主过滤器,您可能会从(matchcode,{{1}})上的单个索引中获得一些好处 - 它可能会将索引与自身连接起来在进入桌面之前消除了很多行。