【问题标题】:How to optimize an Oracle query that has to_char in where clause for date如何优化在 where 子句中具有 to_char 的 Oracle 查询
【发布时间】:2011-02-06 13:12:20
【问题描述】:

我有一个包含大约49403459 记录的表。

我想查询某个日期范围内的表格。说04/10/201004/10/2010。但是,日期以10-APR-10 10.15.06.000000 AM(时间戳)格式存储在表中。

结果当我这样做时

SELECT bunch,of,stuff,create_date
FROM myTable
WHERE TO_CHAR (create_date,'MM/DD/YYYY)' >= '04/10/2010'
AND TO_CHAR (create_date, 'MM/DD/YYYY' <= '04/10/2010'

我得到529 行但在255.59 秒!这是因为我想我正在对每条记录执行 TO_CHAR。

但是,当我这样做时

SELECT bunch,of,stuff,create_date
FROM myTable
WHERE create_date >= to_date('04/10/2010','MM/DD/YYYY')
AND create_date <= to_date('04/10/2010','MM/DD/YYYY')

然后我在0.14 秒内得到0 结果。

我怎样才能使这个查询快速并且仍然获得有效的 (529) 结果?

此时我无法更改索引。现在我认为索引是在create_date 列上创建的。

如何转换两个日期范围,以便第一个日期范围转换为全 0 的时间戳,第二个日期范围转换为时间戳,即日期的最后一个时间戳。如果这有意义...?

以下 where 子句也不获取任何结果:

WHERE            
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
AND
create_date <= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')

【问题讨论】:

    标签: performance oracle date


    【解决方案1】:

    在您的第一个查询中,您进行的是字符比较而不是日期比较,这不应该产生正确的结果。

    例如,使用您的逻辑,01/02/2009 将大于 01/01/2010,因为在比较字符时,日组件“02”大于日组件“01”,并且永远不会计算年份.

    【讨论】:

    • 谢谢。我试过了,但我仍然没有得到任何结果。请看我的编辑
    • 我编辑了我的答案。我认为您的第二个查询可能是正确的。第一个查询给你不正确的结果。
    • @panorama12,再次阅读 ElectricDialect 的答案 - 你没有得到它。您使用的比较逻辑是错误的。
    【解决方案2】:

    这行得通:

    WHERE             
    create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
    AND 
    create_date <= to_timestamp('04/10/2010 23:59:59:123000','MM/DD/YYYY HH24:MI:SS.FF') 
    

    【讨论】:

      【解决方案3】:
      SELECT bunch,of,stuff,create_date
        FROM myTable
       WHERE create_date >= to_date('04/10/2010','MM/DD/YYYY')
         AND create_date < to_date('04/11/2010','MM/DD/YYYY')
      

      日期 04/10/2010 包括从 10 日午夜到晚上 11:59:59 的所有日期值,因此获取小于 11 日的所有内容将涵盖所有基数。另一种方法是确保 myTable 中的数据在数据输入时截断 CREATE_DATE 字段;我更喜欢对 DATE 字段执行此操作,如果我关心时间组件,我会使用 TIMESTAMP。

      【讨论】:

        【解决方案4】:

        这当然行不通:

        WHERE            
            create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
        AND
            create_date <= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
        

        因为这只会返回 create_date 为 4/10/2010 12:00 AM正是的行!

        如果您想获取在 2010 年 4 月 10 日的任何时间出现 create_date 的所有行,请使用以下命令:

        WHERE            
            create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
        AND
            create_date < to_timestamp('04/11/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
        

        或者,如果您愿意:

        WHERE create_date BETWEEN to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
                              AND to_timestamp('04/10/2010 23:59:59.999999','MM/DD/YYYY HH24:MI:SS.FF')
        

        顺便说一句,当你想代表午夜时,你可以省略所有其他部分。所以你可以说:

        WHERE            
            create_date >= to_timestamp('04/10/2010','MM/DD/YYYY')
        AND
            create_date < to_timestamp('04/11/2010','MM/DD/YYYY')
        

        【讨论】:

          【解决方案5】:

          我得到了 529 行,但在 255.59 秒内! 这是因为我想我在做 每个记录上的 TO_CHAR。

          如果您的第一个查询是 generate an execution plan...

          explain plan for 
          SELECT bunch,of,stuff,create_date
          FROM myTable
          WHERE TO_CHAR (create_date,'MM/DD/YYYY)' >= '04/10/2010'
          AND TO_CHAR (create_date, 'MM/DD/YYYY') <= '04/10/2010'
          /
          

          ...您会看到它进行了全表扫描。那是因为to_char() 阻止在创建日期使用您的索引。

          你没有说跑的时候多长时间返回结果...

          SELECT bunch,of,stuff,create_date
          FROM myTable
          WHERE             
          create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
          AND 
          create_date <= to_timestamp('04/10/2010 23:59:59:123000','MM/DD/YYYY HH24:MI:SS.FF')
          /
          

          ...但我预计它比 4 分钟更接近 0.14 秒。

          【讨论】:

            【解决方案6】:

            您的第一个查询正在对错误结果进行字符串比较。 您的第二个查询需要是:

            WHERE create_date >= TRUNC(to_date('04/10/2010','MM/DD/YYYY'))

            或将 hh:mi:ss 添加到谓词中。它不能简单地工作,因为您以与 Oracle 期望不同的方式格式化日期。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多