当前位置:首页 > 情感口述 > 文章

oracle 索引字段包含date类型,使用spring jdbc更新时不走索引,而是走table access full的问题

日期:2019-08-13?|? 作者:本站原创?|? 112 人围观!

	oracle 索引字段包含date类型,使用spring jdbc更新时不走索引,而是走table access full的问题

环境:生产环境存在大表(3000万数据):WR_MP_HOURW_R,包含复合主键:mp_cpchar(13),DTdate对应索引名称:WR_MP_HOURW_R_PRI。

问题:针对此表的更新很慢,每条update大概需要2秒。 更新的时候使用的where条件包含mp_cp=andDT=问题分析:通过AWR查找到针对此表的更新有大量的物理读,因此判定更新时的执行计划有问题。 通过查找对应sql的执行计划,发现没有走索引。

具体查找过程如下:1)找到对应的sql_id:通过_TEXT,_ID,,_VALUEfromv$_TEXTlike%WR_MP_HOURW_R%;2)根据sql_id查找计划:select*fromtable(dbms__cursor(sql_id,null,advanced));果然发现sql没有走索引,而是走的tableaccessfull。 正常应该走INDEXUNIQUESCAN。 具体计划如下:首先考虑oracle是否没有搜集表的统计信息。

查看属性发现表和索引的统计都较新(oracle基本上一个小时会收集一次,以保证执行计划是最优的)。

通过hint处理强制走索引:/*+INDEX(WR_MP_HOURW_RWR_MP_HOURW_R_PRI)*/。 发现走了INDEXSKIPSCAN。

此时说明复合索引有一个字段oracle认为不在条件中或者是经过了转换。 使得oracle只走了复合索引的其中一个字段。 由于我们的update条件是复合索引的两个字段都在where条件里面,所以很大可能是发生了字段类型转换。 其实从上文件指出计划中也可以发现,出现类型转换INTERNAL_FUNCTION("DT")。

如果oracle在索引字段发现有类型转换(如数据库是date,但是传入的是timestemp)oralce将不走索引。

当然如果是复合索引,oracle有可能会走INDEXFASTFULLSCAN或者INDEXSKIPSCAN。 然是如果数据量很大,索引全部扫描也很费时间。

必须要走INDEXUNIQUESCAN才能保证效率。

在发现了发生数据类型转换后,就只能从程序下手找问题,看是否传入的值有问题。 通过查询spring源码,发现:类:的271行开始为最终调用jdbc驱动来通过PreparedStatement设置值的地方:第346行,如果我们在传参数的时候,没有指定对应在数据库要映射什么类型是,spring帮我们做了处理,如下//这里说明我们没有指定要映射到数据库的什么类型找到问题之后如何解决:spring为我们提供了SqlParameterValue或者SqlParameter供我们包装:如果字段是date类型,我们传入此时需要封装成newSqlParameterValue(,value);当然这里不能用因为如果用最终会被转换后为,将会丢失时分秒。 如果字段是timestemp类型,我们传入,此时需要封装成newSqlParameterValue(,value);这样最终oracle就不会出现数据类型转换。 修改之后再查询执行计划,oracle顺利的走了INDEXUNIQUESCAN。

效率立即从更新一条好几秒变为瞬时。

具体计划如下:~end~。


情感美文提供的文章均由网友转载于网络,若本站转载中的文章侵犯了您的权益,请与本站管理员联系. Copyright © 2006-2019 情感美文-情感专家www.c229.com All Rights Reserved.

返回顶部