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 有啥区别? [复制]