java.sql.date , java.sql.timestamp 谓词 -> Oracle 分区数据类型

Posted

技术标签:

【中文标题】java.sql.date , java.sql.timestamp 谓词 -> Oracle 分区数据类型【英文标题】:java.sql.date , java.sql.timestamp predicate -> Oracle partition data type 【发布时间】:2014-06-09 08:34:16 【问题描述】:

您好,我们有很大的 Oracle 列对象,我们已使用 DATE

数据类型 对其进行分区

其中一个分区如下所示:

GCP_P1  TO_DATE(' 2011-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN') 83  M_DATA01    DISABLED    348132  15214   146 08.06.2014 02:20:40 1078    0

每个分区为一周。

我们通过带有 jdbc 的瘦客户端运行我们的 sql。没有 ORM,只有纯 jdbc。

当分区列的谓词项是 java.sql.timestamp 时,我们意识到查询不会从分区中受益。但是,当它是 java.sql.date 类型时,执行计划显示成功的分区访问。

例如,我们的 sql 看起来像这样:

SELECT COUNT(1) FROM ATABLE WHERE PARTITIONED_COLUMN > ?

当我们的java语句是:

preparedStatement.setDate(...); // it benefits from partition

但是当它是这样的时候:

preparedStatement.setTimestamp(...); //it does not benefits from partition

我正在从蟾蜍那里寻找它们。我有经验,当它是java.sql.date时,它在oracle上被解释为DATE,当它是java.sql.timestamp时它被解释为TIMESTAMP

我正在使用以下 sql 语句跟踪捕获的 jdbc 日期类型

SELECT *
  FROM V$SQL_BIND_CAPTURE
WHERE WAS_CAPTURED = 'YES' AND LAST_CAPTURED BETWEEN SYSDATE-1/50 AND SYSDATE
ORDER BY LAST_CAPTURED DESC;

我的问题是你遇到过这样的问题吗?如果是这样,你会指导我看一些文件吗?

【问题讨论】:

【参考方案1】:

您描述的案例记录在第 8 节 - 映射"Getting Started with the JDBC API" 的 SQL 和 Java 类型

8.3.12 DATE, TIME, and TIMESTAMP

因为标准 Java 类 java.util.Date 不匹配任何 这三种 JDBC 日期/时间类型(它包括 DATE 和 TIME信息但没有纳秒),JDBC定义了三个 java.util.Date 的子类以对应于 SQL 类型。它们是:

java.sql.日期

用于 SQL 日期信息。时、分、秒和 java.util.Date 基类的毫秒字段应设置为 零。如果提供给 java.sql.Date 的毫秒数 构造函数是否定的,驱动程序将计算日期为 1970 年 1 月 1 日之前的毫秒数。否则,日期为 计算为 1 月 1 日之后的指定毫秒数, 1970 年。

java.sql.Time

用于 SQL TIME 信息。年、月、日 java.util.Date 基类的字段设置为 1970 年、1 月和 1. 这是 Java 时代的“零”日期。

java.sql.时间戳

用于 SQL TIMESTAMP 信息。此类通过添加扩展 java.util.Date 纳秒字段。

【讨论】:

虽然这是关于 jdbc 类型的好信息,但它对 Oracle 的 DATE 类型的细节以及它如何映射到 jdbc 类型没有帮助。 映射的逻辑出现了。由于这是实现细节,因此无需编写可能会有所不同。要使用 Oracle DATE 类型的细节,您应该退出 Java API 并使用 oracle.sql 包。恕我直言,这里不是这种情况,因为这是在驱动程序内部完成的。 几乎可以肯定这里的问题是使用的列是 Oracle DATE 类型。通过使用标准的 jdbc setTimestamp 方法,oracle 在幕后进行强制转换。要获得所需的行为(能够利用索引或分区),必须处理 oracle.sql.DATE ojdbc 对象。 你说得对。但这是通过映射指定的。如果您使用java.sql.Date,将使用日期,另一方面,当您使用java.sql.Timestamp 时,将使用TIMESTAP,但如果您在DATE 列上使用setTimestamp。 JDBC 在oracle.sql.Timestap 的实例上创建并传递它。因为TIMESTAMP 宽了 4 个字节(纳秒)。在准备执行计划期间,引擎找不到TIMESTAP 类型的索引,因此它不会使用它。这意味着决定是在 db 级别而不是 jdbc 上。 结束用户应确保从 API 调用有效方法,正确性基于发布的映射。另一种方法是将参数直接传递给您在答案中描述的语句。但是我们仍然必须知道该类型在 DB 中,如果我们使用 oracle.sql.DATE 我们会成功,但如果我们使用 oracle.sql.TIMESTAP 我们会像 OP 一样失败。【参考方案2】:

oracle jdbc developers guide 包含从 jdbc 类型到 oracle 数据类型的映射。由于其复杂性,有一个特定于 DATE 数据类型的section。它有以下注释:

在 Oracle 数据库 11g 中,如果您在 DATE 列上有索引 由 SQL 查询使用,然后为了获得更快和准确的结果,您 必须按以下方式使用 setObject 方法:

 Date d = parseIsoDate(val); 
 Timestamp t = new Timestamp(d.getTime());
 stmt.setObject(pos, new oracle.sql.DATE(t,(Calendar)UTC_CAL.clone()));

【讨论】:

以上是关于java.sql.date , java.sql.timestamp 谓词 -> Oracle 分区数据类型的主要内容,如果未能解决你的问题,请参考以下文章

java.sql.date和java.util.date的区别和转换

java.util.Date 和 java.sql.Date 有啥区别? [复制]

SQL DATE 与 java.sql.Date 中的时区

java.util.Date 不能转换为 java.sql.Date [重复]

Java.sql.Date精确度问题处理

java.sql.date , java.sql.timestamp 谓词 -> Oracle 分区数据类型