【问题标题】:Oracle 9i - Optimizer Issues with Date Arithmetic?Oracle 9i - 日期算术优化器问题?
【发布时间】:2011-08-08 14:30:03
【问题描述】:

我们有一个查询,其中包括(但还有其他联接、表和 where 条件):

SELECT
    o.contact_id, 
    o.completed_date, 
    o.submitted_date
FROM
    orders o /* 860,000 row table */
WHERE   
    ? <= o.submitted_date
    AND o.submitted_date < ? + 1

从 Java 应用程序调用。

? 参数允许检查两个日期之间提交的订单。

但是,这个查询运行得很慢。

我们转换为从 PL/SQL 运行以进行如下测试:

SubmittedDateFrom date:=to_date('2011-07-15', 'yyyy-mm-dd');
SubmittedDateTo date:=to_date('2011-07-15', 'yyyy-mm-dd');
CURSOR c_orgs    IS    
SELECT
    o.contact_id, 
    o.completed_date, 
    o.submitted_date
FROM
    orders o
WHERE   
    SubmittedDateFrom <= o.submitted_date
    AND o.submitted_date < SubmittedDateTo + 1;
BEGIN
    FOR c_o IN c_orgs LOOP
        DBMS_OUTPUT.put_line('Submitted date = '||c_o.submitted_date);                               
    END LOOP;
END;

如果我们:

  1. SubmittedDateTo 值转换为to_date('2011-07-16', 'yyyy-mm-dd')(即在查询之外进行算术运算),
  2. SubmittedDateTo 设为字符串并使用“to_date('SubmittedDateTo', 'yyyy-mm-dd') + 1”作为WHERE 中的第二个条件。

那么,查询速度显着加快(

更多信息:

  • 对查询运行解释计划会出现错误ORA-00932: inconsistent datatypes: expected DATE got NUMBER
  • submitted_date 列有索引和统计信息等已运行
  • SubmittedDateTo + 1 包装在trunc() 调用中不会影响性能
  • 我们没有类似数据量等的非9i数据库来测试它是否是Oracle的版本。

问题是:我们找不到任何明确说明 Oracle 9i 优化器在这种日期算法方面存在问题的信息。这是这里发生的事情还是发生了其他事情?

【问题讨论】:

  • 您是否能够通过测试用例(例如,从 dba_objects 等构建的表)复制问题。
  • 没试过。我的 DB 权限有限,因为我在 app-dev 而不是 dba 方面......
  • 您的 Java 代码是否将 DATE 或 STRING 绑定到 ?
  • 我们绑定到 ?带有java.sql.Timestamp 对象。请参阅 Ollie 的问题,了解真正的问题是什么。

标签: performance oracle oracle9i ora-00932


【解决方案1】:

我始终确保所有转换都得到明确处理(并假设 o.submitted_date 是 DATE 数据类型):

DECLARE
  CURSOR c_orgs    
  IS
     SELECT o.contact_id,      
            o.completed_date,
            o.submitted_date 
       FROM orders o 
      WHERE o.submitted_date BETWEEN TO_DATE(SubmittedDateFrom, 'yyyy-mm-dd') 
                                 AND TO_DATE(SubmittedDateTo, 'yyyy-mm-dd'); 
BEGIN
   FOR c_o IN c_orgs 
   LOOP
      DBMS_OUTPUT.put_line('Submitted date = '||c_o.submitted_date);
   END LOOP;
END; 

这确保了任何隐式转换都没有错误,并且所有转换的数据类型都很明显。

“问题是:我们找不到任何明确说明 Oracle 9i 优化器在这种日期算法方面存在问题的信息。这是这里发生的事情还是发生了其他事情?”

我不认为它是优化器,它可能是您的隐式转换的最终产品导致性能问题。由于我们没有来自 Oracle 数据库的日期等的 NLS 设置,因此很难判断,但如果使用显式转换可以提高性能,那么我建议您使用它们(这也是更好的做法)。

希望对你有帮助,奥利。

【讨论】:

  • Ollie,我接受了这个答案,因为您正确地暗示这不是由于优化器造成的。我对查询进行了更多操作,并且(在我没有显示的位中),我们有一个冗余连接到一个表中,我们没有给出一个索引提示,它被拖下来了。非常奇怪的是,要么 修复索引 使用带有预先计算的日期算术的原始查询(有连接/索引问题)将加快查询速度。如果同时使用连接/索引 + 预先计算的算法,速度会稍微快一些。
  • 我仍然对为什么更改索引问题所涵盖的日期算法感到头疼……
【解决方案2】:

根据Oracle documentation(这是 v10,但我猜这也适用于 9i),“...不支持 EXPLAIN PLAN 用于执行日期绑定变量的隐式类型转换的语句。”

除了 Ollie 建议的方法之外,您是否尝试过使用 trunc() resp。之间?

SELECT
    o.contact_id, 
    o.completed_date, 
    o.submitted_date
FROM
    orders o /* 860,000 row table */
WHERE   
    trunc(o.submitted_date) = trunc(?)

分别

SELECT
    o.contact_id, 
    o.completed_date, 
    o.submitted_date
FROM
    orders o /* 860,000 row table */
WHERE   
    o.submitted_date between ? and ? + 1

【讨论】:

  • Frank,TRUNC() 不会导致优化器忽略提交日期字段上的任何索引。 FWIW,我会在 ? + 1 也只是为了让我在做什么很明显。
  • 你说得对,trunc() 确实会这样做(除非你在 trunc(submitted_date) 上有一个基于函数的索引)。
  • 查看 Ollie 回答下的 cmets 了解实际情况。为了完整起见,使用 trunc() 不会影响性能。并且使用 between 会起作用,因为它在语义上不等效(between 暗示 &lt;= 当我们在 +1 日期需要 &lt; 时)。
猜你喜欢
  • 2014-05-21
  • 2014-05-24
  • 2017-12-19
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-05
  • 1970-01-01
相关资源
最近更新 更多