【问题标题】:Need some advice to optimize an Oracle query需要一些建议来优化 Oracle 查询
【发布时间】:2012-08-14 01:43:48
【问题描述】:

我有两个应用程序:第一个应用程序在 MyTable 表中插入数据。第二个以块的形式读取 MyTable 表的行:假设每次读取 1000 行。第二个应用程序必须按时间顺序读取数据,并使用类似于以下内容的查询:

SELECT
    C1,
    C2
FROM
(
    SELECT
        rownum AS RowNumber, 
        C1, 
        C2
    FROM
        MyTable
    WHERE
        C3 = :C3
        AND IsProcessed = 0
    ORDER BY
        Timestamp
) temp 
WHERE 
    temp.RowNumber <= 1000

查询有效,但是当表中有大量未处理的行(例如1000万行)等待时,它很慢(超过一分钟,通常只需要几秒钟即可执行)MyTable。我想这是正常的,因为 Oracle 必须首先按时间顺序对所有相关行进行排序...... 所以我的问题是:有没有更好的方法来编写这个查询?

【问题讨论】:

  • 为了确定,您在IsProcessedTimestamp 列上确实有适当的索引?
  • 是的,存在相应的索引。
  • “当很多...时很慢” 定义“慢”和“很多”。您的查询看起来很合理,但我们在谈论什么数据?另外,你在做软删除吗? (已处理)。
  • 能否提供一个执行计划?谁更新IsProcessed 并且他们经常提交?请注意,在长时间运行的批处理中,从具有较长 UNDO/REDO 日志(大量写入后很少提交)的表中进行选择可能会导致 Oracle 中的大量负载
  • @tbone :我更新了我的问题。

标签: sql oracle query-optimization


【解决方案1】:

从你的执行计划来看,我猜你的谓词C3 = :C3 是相当昂贵的。您应该尝试通过避免 RAW 类型来优化它。有几种选择:

  • 确保您在SUBCONTRACTID 上有一个索引
  • 尝试在NVL(BUSINESSTRANSACTIONID, HEXTORAW('00')) 上添加基于函数的索引
  • 确保您在BUSINESSTRANSACTIONID 上有一个索引,并使用IS NULL 而不是NVL(...) 进行查询
  • 如果您可以放宽底层业务需求,当然可以删除ORDER BY timestamp 子句并以任意顺序处理记录。

除此之外,您的查询似乎还不错。

另外,请尝试应用 /*+FIRST_ROWS(1000)*/ 提示,因为在您的查询中似乎由于某种原因这不是自动完成的,即使使用 ROWNUM 过滤

【讨论】:

  • 我的应用程序是用 .NET 编写的,我必须(别无选择:()使用 GUID 作为主键...这就是我有一些 RAW 列的原因。回答您的问题:1)我在 SubcontractId 列上有一个索引。 2)好的,我明天试试。 3) 我有一个关于 BusinessTransactionId 的索引。但是如果我使用“IS NULL”,Oracle 会进行全面扫描...... 4)我不能放松要求:(我也会尝试你建议的提示。谢谢!我想我明天会接受你的回答。
  • @schglurps:是的,它看起来比一开始看起来更棘手。我不太习惯使用RAW 类型,但你可以试试运气用适当的CHARVARCHAR2 类型替换RAW...虽然,这只是一个疯狂的猜测...跨度>
  • 我尝试了基于函数的索引和您建议的提示,这似乎稍微提高了查询的性能。我的应用程序必须处理大量数据,也许这个瓶颈指出我必须改进他们的架构。感谢您的帮助!
【解决方案2】:

您实际上不需要为 RowNumber 定义列:

SELECT C1, C2 
FROM (
   SELECT C1, C2     
   FROM   MyTable
   WHERE  C3 = :C3
      AND IsProcessed = 0
   ORDER BY Timestamp 
   ) temp
WHERE ROWNUM <= 1000

使其“更快”的唯一方法是进一步限制派生表的大小。

【讨论】:

    【解决方案3】:
    SELECT * FROM
      (    SELECT C1, C2
          FROM MyTable
         WHERE C3 = :C3
           AND IsProcessed = 0
         ORDER BY Timestamp
      ) WHERE rownum <= 1000;
    

    试试这个查询。

    【讨论】:

    • 那会产生错误的结果。 ROWNUM 可以在其他谓词之前进行评估...
    • 这行不通,因为Oracle只会订购1000行,而不是表中的所有行...
    猜你喜欢
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 2017-01-06
    • 2012-01-19
    相关资源
    最近更新 更多