Oracle 9i - 日期算术的优化器问题?

时间:2011-08-08 14:30:03

标签: performance oracle oracle9i ora-00932

我们有一个包含(但有其他连接,表和条件)的查询:

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中的第二个条件。
  3. 然后,查询速度急剧上升(<1秒对44秒)。

    更多信息:

    • 对查询运行解释计划会产生错误ORA-00932: inconsistent datatypes: expected DATE got NUMBER
    • submitted_date列有一个索引和统计信息等已经运行
    • SubmittedDateTo + 1包裹在trunc()电话中不会影响效果
    • 我们没有具有类似数据量的非9i数据库等,以测试它是否是Oracle的版本。

    问题是:我们无法找到任何明确说明Oracle 9i Optimizer存在此类日期算术问题的信息。这是在这里发生的事情还是还有其他事情发生?

2 个答案:

答案 0 :(得分: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 Optimizer存在此类日期算术问题的信息。这是发生在这里的事情还是还有其他事情发生?”

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

希望它有所帮助,奥利。

答案 1 :(得分:1)

根据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(?)

RESP。

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