【问题标题】:Oracle performance tuning - iterating table in column sectionOracle 性能调优 - 列部分中的迭代表
【发布时间】:2017-05-15 08:22:56
【问题描述】:

以下查询需要 220 秒。我想调一下。 查询中主要使用了三个表。两个很大,一个相当小。

表格中的计数:

INST        --14851330 records 
INST_S_INC  --52234424 records
INVES         -- 80000 records

查询:

SELECT 
(
  SELECT CODE
  FROM   CURRENCY CURR
  WHERE  CURR.CURRENCY_ID =
           ( SELECT CURRENCY_ID
             FROM INST  INSTR--14851330 records 
             WHERE INSTR.INVES_ID = INV.INVES_ID
             UNION ALL
             SELECT CURRENCY_ID
             FROM INST_S_INC ISI--52234424 records
             WHERE ISI.INVES_ID = INV.INVES_ID
           )
)
FROM   INVES INV -- 80000 records
WHERE  TRUNC(CREATED_DATETIME) <SYSDATE
ORDER BY CREATED_DATETIME
;--220 secs

我尝试如下重写查询,但现在需要 418 秒。有什么其他的调音方法吗?

SELECT
(
  SELECT CODE
  FROM CURRENCY CURR
  WHERE CURR.CURRENCY_ID =ISI.currency_id
  union all
  SELECT CODE
  FROM CURRENCY CURR
  WHERE CURR.CURRENCY_ID =INSTR.currency_id
) code
FROM   INVES INV
       left outer join (
         select INVES_ID,currency_id from INST
       )  INSTR
       on  INSTR.INVES_ID = INV.INVES_ID
       left outer join (
         select INVES_ID,currency_id from INST_S_INC
       )  ISI
       on  ISI.INVES_ID = INV.INVES_ID
WHERE TRUNC(CREATED_DATETIME) <SYSDATE 
ORDER BY CREATED_DATETIME
;--418 secs

【问题讨论】:

  • 有哪些索引可用?连接列的数据类型有哪些?你的执行计划是什么?
  • WHERE INSTR.INVES_ID = INV.INVES_ID ---- 这是使用索引 INSTR.INVES_ID - 在此创建索引 WHERE ISI.INVES_ID = INV.INVES_ID---- 这是使用索引 ISI .INVES_ID - 在此创建索引
  • @swetabhmalaviya 编辑您的问题 - 不要尝试将其作为评论发布。
  • 索引不是魔杖,在任何情况下都无济于事,尤其是在这种情况下,全表扫描可能会有更多帮助
  • 你真的只是选择currency.code而不选择其他列吗???

标签: oracle performance optimization query-optimization


【解决方案1】:

你可以改变:

TRUNC(CREATED_DATETIME) < SYSDATE

收件人:

CREATED_DATETIME < TRUNC( SYSDATE ) + INTERVAL '1' DAY

这将允许您使用CREATED_DATETIME 上的任何索引(而不是必须在TRUNC(CREATED_DATETIME) 上使用基于函数的索引)。

很难解释您的要求,因为您没有描述您要实现的目标或表结构,但您也可以尝试使用 EXISTS 并直接从 CURRENCY 表中选择:

SELECT curr.CODE
FROM   CURRENCY CURR
WHERE  EXISTS (
         SELECT CURRENCY_ID
         FROM   INST
                INNER JOIN
                INVES
                ON ( INST.INVES_ID = INVES.INVES_ID )
         WHERE  INSRT.CURRENCY_ID  = CURR.CURRENCY_ID
         AND    CREATED_DATETIME   < TRUNC( SYSDATE ) + INTERVAL '1' DAY
       )
OR     EXISTS (
         SELECT CURRENCY_ID
         FROM   INST_S_INC ISI
                INNER JOIN
                INVES
                ON ( ISI.INVES_ID = INVES.INVES_ID )
         WHERE  ISI.CURRENCY_ID   = CURR.CURRENCY_ID
         AND    CREATED_DATETIME  < TRUNC( SYSDATE ) + INTERVAL '1' DAY
       )

或者在EXISTS 中使用UNION ALL

【讨论】:

    【解决方案2】:
    WHERE  TRUNC(CREATED_DATETIME) <SYSDATE
    

    这个过滤器的意义何在?假设您将来不创建基本上定义全表扫描的记录。

    在没有解释计划和数据量、偏斜等细节的情况下进行性能调优是一个愚蠢的游戏,但这是我的猜测:

    SELECT curr,code
    FROM   INVES INV
           left outer join INST
           on  INSTR.INVES_ID = INV.INVES_ID
           left outer join  INST_S_INCISI
           on  ISI.INVES_ID = INV.INVES_ID
    left outer join CURRENCY CURR
    on CURR.CURRENCY_ID = coalesce (ISI.currency_id, INST.currency_id)
    ORDER BY inv.CREATED_DATETIME
    ;-
    

    【讨论】:

    • CURR.CURRENCY_ID = INST.currency_idCURR.CURRENCY_ID &lt;&gt; ISI.currency_idISI.currency_id 不为空时会发生什么?
    猜你喜欢
    • 2016-02-08
    • 2016-06-25
    • 2013-03-17
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    相关资源
    最近更新 更多