2

我们有一个查询,其中包括(但有其他联接、表和 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.

然后,查询速度显着加快(< 1 秒 vs. 44+ 秒)。

更多的信息:

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

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

4

2 回答 2

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 设置,因此很难判断,但如果使用显式转换可以提高性能,那么我建议您使用它们(这也是更好的做法)。

希望它有所帮助,奥利。

于 2011-08-08T15:06:15.047 回答
1

根据Oracle 文档(这是 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
于 2011-08-08T15:09:24.433 回答