Oracle查询隐式类型转换不走索引
2016-02-20 18:43
776 查看
1. 框架
mybatis,oracle2. 问题
昨天DBA发来邮件说有一个SQL引起CPU高负载。查看了一下SQL,根据时间条件查询,时间是有索引的,但是CPU会突然飙高。SELECT * FROM ( SELECT t1.*,rownum as rn FROM ( SELECT count(:"SYS_B_0") as COUNT ,T.USER_ID, T.USER_NAME FROM TEST T WHERE :"SYS_B_1"=:"SYS_B_2" AND CREATED_TIME >= :4 AND CREATED_TIME <= :5 group by T.USER_ID,T.USER_NAME ORDER BY COUNT desc ) t1 WHERE rownum <= :6 ) t2 WHERE rn >= :7
然后看一下SQL的执行计划,发现该SQL进行了全表扫描。
可以看到查询的时候使用了过滤器,这就意味着传过来的日期和数据库中的日期格式不对应,可以断定是由于隐式转换导致了时间索引没有用,导致了CPU的飙升。
3. 原因
数据库中的类型是Date类型,传值过去的是Timestamp类型,Java代码里使用的是java.util.Date,配置文件并没有指定类型。那么问题应该就是出在mybaits上了。mybaits把日期类型直接转化为Timestamp类型,来看下代码:
org.apache.ibatis.type.BaseTypeHandler<T> public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { if (jdbcType == null) { throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); } try { ps.setNull(i, jdbcType.TYPE_CODE); } catch (SQLException e) { throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + <span> </span>"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + <span> </span>"Cause: " + e, e); } } else { setNonNullParameter(ps, i, parameter, jdbcType); } }
org.apache.ibatis.type.DateTypeHandler @Override public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { ps.setTimestamp(i, new Timestamp((parameter).getTime())); }
org.apache.ibatis.type.DateOnlyTypeHandler @Override public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { ps.setDate(i, new java.sql.Date((parameter.getTime()))); }
这里我们看到日期的handler有两个,一个是Timestamp,一个默认是sql.Date。
经过调试代码,发现日期的默认处理handler是DateTypeHandler,那么传到数据库中的值就变成了Timestamp类型了。
主要原因(摘抄)
在9i以后,11g以前的oracle jdbc中存在date类型丢失时间的bug,原因是其jdbc驱动将oracle的date类型处理为java.sql.date 类型,这就丢失了时间部分;事实上,如果是使用ibatis,pojo属性的类型设置为java.util.date,确保 jdbctype不为 date或者time,则避免了这个bug。因为此时ibatis会以java.sql.timestamp来处理该字段。总的来说就是时间精度处理引起的问题。
4. 解决方法
如果查询是按照日期来的话,可以在参数中指定jdbcType类型为date。如果需要更精确的时间查询,可以传入字符串,使用to_date()函数进行转化日期。
http://hidba.org/
相关文章推荐
- Oracle 集群心跳及其參数misscount/disktimeout/reboottime
- Jmeter之JDBC Request使用方法(oracle)
- Linux Is Not Matrix——oracle监听设置
- oracle中split的使用
- oracle数据库学习 (上)
- Hadoop学习笔记——1.java读取Oracle中表的数据,创建新文件写入Hdfs
- Failed to upgrade Oracle Cluster Registry configuration(root.sh)
- Oracle12c中分区(Partition)新特性之TRUNCATEPARTITION和EXCHANGE PARTITION级联功能
- Oracle 11G R2 DataGuard日常维护及故障处理
- Oracle基础(二)---操作命令
- Linux redhat5.5下安装oracle 11g
- 强大的oracle函数wm_concat
- Oracle字符集修改
- Oracle11g服务器端和客户端安装到同一笔记本中需要注意的问题
- Datatypes translation between Oracle and SQL Server
- 11.Oracle深度学习笔记——操作系统自动化监控脚本
- 使用apt-get下载oracle-java-8代码
- oracle TX等待事件的解决方法
- Oracle中用一个表更新另一个表
- Oracle 12C RAC的optimizer_adaptive_features造成数据插入超时