发现明明有索引,当但是查询还是很慢。花费了几个小时。终于找到原因了。
之前试过使用强制索引。但是无效。
select /*+index(fy IDX_JFRQ)*/ *from tab fy where jfrq>?
网上找到原因:
由于需要小时分秒的信息,我们使用的是java.util.Date,观察发现在数据库端有类似如下函数转换
-
TO_TIMESTAMP(date_column) = parameter_timestamp
导致纵然加了hit也走不上索引.
为什么会触发oracle做隐式转换呢?因为在ibatis的处理中,java.util.Date会转换为java.sql.Timestamp(具体原因可以参考java.sql.PreparedStatement和相关文档,在此不详述)
-
ps.setTimestamp(i, new java.sql.Timestamp(((Date) parameter).getTime()))
JAVA传下去的是Timestamp,而数据库的类型是Date,根据oracle的策略,会对date类型做强制转换TO_TIMESTAMP(GMT_SEND),因此就走不上索引了 。
解决方案:
经过网上查询,认为可选且比较靠谱的解决方案主要有三种:
a.将数据库的列改为timestamp(修改了业务逻辑,该字段只要日期,不需要时间)
b.使用to_date('2020-03-08','yyyy-mm-dd')
to_date(to_char(?,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS');
c.将传入参数由java.util.Date转换为String,然后在ibatis端使用to_date函数解决(改动点太多)
and fjrq >= to_date(?,'YYYY-MM-DD HH24:MI:SS')
d.给GMT_SEND字段建函数索引(为了走索引而走索引,不是正常的解决问题的办法)
e.cast函数转成Date类型,最终是采用这种方案,对现有程序功能无影响且直接解决问题
and jfrq >= cast(? as date)