当我为DATE列传递java.sql.Timestamp时,为什么Oracle这么慢?

Aar*_*lla 6 oracle performance timestamp date jdbc

我有一个DATE带有时间列的表(在Oracle中通常没有TIME类型).当我从JDBC查询该列时,我有两个选择:

  • 使用Oracle手动转换值 to_date()
  • 用一个 java.sql.Timestamp

这两种方法都有效,并且具有独特的可怕区域.我的问题是我在SELECT输入数据时.以下是两个示例查询:

select *
from TABLE
where TS between {ts '2009-12-08 00:00:00.000'} and {ts '2009-12-09 00:00:00.000'}

select *
from TABLE
where TS between trunc({ts '2009-12-08 00:00:00.000'}) and trunc({ts '2009-12-09 00:00:00.000'})
Run Code Online (Sandbox Code Playgroud)

两个查询都有效,返回相同的结果并生成完全相同的输出EXPLAIN PLAN.使用此正确的索引.

只有查询一个运行15分钟,而第二个查询需要0.031秒.这是为什么?是否有一个中心位置来解决这个问题,或者我是否必须检查我对该列的所有查询并完全确定它trunc()在那里?当我需要选择到某一秒时,如何解决此问题?

[编辑]该表已分区,我在Oracle 10.2.0上.

小智 5

这是因为 TIMESTAMP 数据类型比 DATE 更准确,所以当您将 TIMESTAMP 参数值提供给 DATE 列条件时,Oracle 必须将所有 DATE 值转换为 TIMESTAMP 进行比较(这是上面的 INTERNAL_FUNCTION 用法),因此索引必须已满扫描。


CMG*_*CMG 3

我不明白 {ts '2009-12-08 00:00:00.000'} 的实际含义,因为据我所知,这不是 Oracle SQL。您能准确显示您正在运行的查询是什么吗?

一个可能的问题是您用毫秒指定范围。Oracle 的 DATE 类型只能精确到秒。(如果需要存储秒的小数部分,请使用 TIMESTAMP 类型)。但可能发生的情况是,在第一个查询中,Oracle 将每个 DATE 值转换为 TIMESTAMP,以便与指定的 TIMESTAMP 进行比较。在第二种情况下,它知道 TRUNC() 会有效地将您的值舍入为可以表示为 DATE 的值,因此不需要转换。

如果您想避免此类隐式转换,请确保始终进行同类比较。例如

select * 
from my_table t
where t.ts between to_date('2009-12-08','YYYY-MM-DD') and to_date('2009-12-09','YYYY-MM-DD')
Run Code Online (Sandbox Code Playgroud)

  • `{ts ...}`、`{d ...}` 是 JDBC 的一个隐藏功能,它允许您以与数据库无关的方式指定 java.sql.Timestamp、java.sql.Date。 (4认同)
  • 我很确定问题是隐式类型转换之一。如果您给 Oracle 一个时间戳值来与 DATE 类型列进行比较,那么它将必须进行转换,并且它将避免舍入。因此唯一的选择是将其所有 DATE 值转换为 TIMESTAMP。因此,它会非常慢,并且无法在 DATE 列上使用索引。您可以通过在日期列上创建基于函数的索引来解决此问题,其中日期表示为时间戳。 (2认同)

归档时间:

查看次数:

11082 次

最近记录:

11 年,5 月 前