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

环境:

spring jdbc 3.2.3.RELEASE

oracle 11.2.0.1.0 - Production

生产环境存在大表(3000万数据):WR_MP_HOURW_R,包含复合主键:

mp_cp char(13),

DT  date

对应索引名称:WR_MP_HOURW_R_PRI。

问题:针对此表的更新很慢,每条update大概需要2秒。更新的时候使用的where 条件包含mp_cp =? and DT =?

问题分析:

通过AWR 查找到针对此表的更新有大量的物理读,因此判定更新时的执行计划有问题。通过查找对应sql的执行计划,发现没有走索引。具体查找过程如下:

1)找到对应的sql_id:通过select t.SQL_TEXT,t.SQL_ID,t.ADDRESS,t.HASH_VALUE from v$sql  t where t.SQL_TEXT   like '%WR_MP_HOURW_R%';

2) 根据sql_id查找计划:select * from table(dbms_xplan.display_cursor('sql_id',null,'advanced'));

果然发现sql没有走索引,而是走的 table access full。正常应该走 INDEX UNIQUE SCAN。具体计划如下:

4f1150b881333f12a311ae9ef34da474.pngSQL_ID  16gzsf0ccjjwg, childnumber04f1150b881333f12a311ae9ef34da474.png-------------------------------------4f1150b881333f12a311ae9ef34da474.pngupdatesl_szy_mwr_intra .WR_MP_HOURW_RsetMP_CD=:1,SPE_REG_DATA=4f1150b881333f12a311ae9ef34da474.png:2,HOUR_W=:3,DT=:4whereMP_CD=:5andDT=:64f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngPlanhash value:34981916164f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.png-------------------------------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png|Id|Operation|Name|E-Rows|E-Bytes|Cost (%CPU)|E-Time|4f1150b881333f12a311ae9ef34da474.png-------------------------------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png|0|UPDATESTATEMENT||||35061(100)||4f1150b881333f12a311ae9ef34da474.png|1|UPDATE|WR_MP_HOURW_R|||||4f1150b881333f12a311ae9ef34da474.png|*2|TABLEACCESSFULL|WR_MP_HOURW_R|21|504|35061(1)|00:07:01|4f1150b881333f12a311ae9ef34da474.png-------------------------------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.pngQuery Block Name/Object Alias (identifiedbyoperation id):

4f1150b881333f12a311ae9ef34da474.png-------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png1-UPD$14f1150b881333f12a311ae9ef34da474.png2-UPD$1/WR_MP_HOURW_R@UPD$14f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngOutline Data

4f1150b881333f12a311ae9ef34da474.png-------------4f1150b881333f12a311ae9ef34da474.png1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/**//*+

d18c02628675d0a2c816449d98bda930.png      BEGIN_OUTLINE_DATA

d18c02628675d0a2c816449d98bda930.png      IGNORE_OPTIM_EMBEDDED_HINTS

d18c02628675d0a2c816449d98bda930.png      OPTIMIZER_FEATURES_ENABLE('11.2.0.3')

d18c02628675d0a2c816449d98bda930.png      DB_VERSION('11.2.0.3')

d18c02628675d0a2c816449d98bda930.png      ALL_ROWS

d18c02628675d0a2c816449d98bda930.png      OUTLINE_LEAF(@"UPD$1")

d18c02628675d0a2c816449d98bda930.png      FULL(@"UPD$1" "WR_MP_HOURW_R"@"UPD$1")

d18c02628675d0a2c816449d98bda930.png      END_OUTLINE_DATA

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngPeeked Binds (identifiedbyposition):

4f1150b881333f12a311ae9ef34da474.png--------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png5-(VARCHAR2(30), CSID=852):'2108811006101'4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngPredicate Information (identifiedbyoperation id):

4f1150b881333f12a311ae9ef34da474.png---------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png2-filter(("MP_CD"=:5ANDINTERNAL_FUNCTION("DT")=:6))

4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngColumnProjection Information (identifiedbyoperation id):

4f1150b881333f12a311ae9ef34da474.png-----------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png2-(upd=2,3,4,5; cmp=2,3; cpy=2,3) "WR_MP_HOURW_R".ROWID[ROWID,10], 

4f1150b881333f12a311ae9ef34da474.png       "MP_CD"[CHARACTER,13], "DT"[DATE,7], "HOUR_W"[NUMBER,22], 

4f1150b881333f12a311ae9ef34da474.png       "SPE_REG_DATA"[CHARACTER,1]4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngNote

4f1150b881333f12a311ae9ef34da474.png-----4f1150b881333f12a311ae9ef34da474.png-Warning: basicplanstatisticsnotavailable. These areonlycollectedwhen:

4f1150b881333f12a311ae9ef34da474.png*hint'gather_plan_statistics'isusedforthe statementor4f1150b881333f12a311ae9ef34da474.png*parameter'statistics_level'issetto'ALL', at sessionorsystemlevel4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.png===4f1150b881333f12a311ae9ef34da474.pngSQL_ID  62mars8u2ysj1, childnumber04f1150b881333f12a311ae9ef34da474.png-------------------------------------4f1150b881333f12a311ae9ef34da474.pngupdatesl_szy_mwr_intra .WR_MP_HOURW_RsetMP_CD=4f1150b881333f12a311ae9ef34da474.png'2201050002001',        SPE_REG_DATA='0',         HOUR_W=1368.0,    

4f1150b881333f12a311ae9ef34da474.png    DT=to_date('06-05-2015 06:00:00','dd-mm-yyyy hh24:mi:ss')   

4f1150b881333f12a311ae9ef34da474.pngwhereMP_CD='2201050002001'andDT=to_date('06-05-2015 

4f1150b881333f12a311ae9ef34da474.png06:00:00','dd-mm-yyyy hh24:mi:ss')

4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngPlanhash value:234794540

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

通过hint 处理强制走索引:/*+ INDEX(WR_MP_HOURW_R WR_MP_HOURW_R_PRI)*/  。发现走了INDEX SKIP SCAN。

此时说明复合索引有一个字段oracle认为不在条件中或者是经过了转换。使得oracle只走了复合索引的其中一个字段。

由于我们的update条件是复合索引的两个字段都在where条件里面,所以很大可能是发生了字段类型转换。

其实从上文件指出计划中也可以发现,出现类型转换  INTERNAL_FUNCTION("DT") 。

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

当然如果是复合索引,oracle有可能会走 INDEX FAST FULL SCAN或者INDEX SKIP SCAN。然是如果数据量很大,索引全部扫描也很费时间。必须要走INDEX UNIQUE SCAN才能保证效率。

在发现了发生数据类型转换后,就只能从程序下手找问题,看是否传入的值有问题。

通过查询spring源码,发现:

类:org.springframework.jdbc.core.StatementCreatorUtils的271行开始为最终调用jdbc驱动来通过PreparedStatement设置值的地方:

第346行,如果我们在传参数的时候,没有指定对应在数据库要映射什么类型是,spring帮我们做了处理,如下

1fa987a29c6482f53d401256f96355eb.png//这里说明我们没有指定要映射到数据库的什么类型

ca75c07623e1b494fee67e8f316fc310.gifelseif(sqlType==SqlTypeValue.TYPE_UNKNOWN)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(isStringValue(inValue.getClass()))9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                ps.setString(paramIndex, inValue.toString());

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png//看这里,所有java.util.Date,java.util.Date,java.sql.Date,java.sql.Timestamp都被用了ps.setTimestamp处理了,这就是根本原因97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifelseif(isDateValue(inValue.getClass()))9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                ps.setTimestamp(paramIndex,newjava.sql.Timestamp(((java.util.Date) inValue).getTime()));

ecedf933ec37d714bd4c2545da43add2.png            }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifelseif(inValueinstanceofCalendar)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                Calendar cal=(Calendar) inValue;

d18c02628675d0a2c816449d98bda930.png                ps.setTimestamp(paramIndex,newjava.sql.Timestamp(cal.getTime().getTime()), cal);

ecedf933ec37d714bd4c2545da43add2.png            }97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifelse9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//Fall back to generic setObject call without SQL type specified.d18c02628675d0a2c816449d98bda930.pngps.setObject(paramIndex, inValue);

ecedf933ec37d714bd4c2545da43add2.png            }8f1ba5b45633e9678d1db480c16cae3f.png        }4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifprivatestaticbooleanisDateValue(Class inValueType)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn(java.util.Date.class.isAssignableFrom(inValueType)&&d18c02628675d0a2c816449d98bda930.png!(java.sql.Date.class.isAssignableFrom(inValueType)||d18c02628675d0a2c816449d98bda930.png                        java.util.Date.class.isAssignableFrom(inValueType)||d18c02628675d0a2c816449d98bda930.png                        java.sql.Timestamp.class.isAssignableFrom(inValueType)));

8f1ba5b45633e9678d1db480c16cae3f.png}

找到问题之后如何解决:

spring为我们提供了SqlParameterValue或者SqlParameter供我们包装:

如果字段是date类型,我们传入java.util.date 此时需要封装成new SqlParameterValue(Types.TIME, value);

当然这里不能用Types.DATE 因为如果用Types.DATE最终会被转换后为java.sql.date,将会丢失时分秒。

如果字段是timestemp类型,我们传入java.util.date, 此时需要封装成new SqlParameterValue(Types.TIMESTAMP, value);

这样最终oracle就不会出现数据类型转换。

修改之后再查询执行计划,oracle 顺利的走了INDEX UNIQUE SCAN。效率立即从更新一条好几秒变为瞬时。具体计划如下:

4f1150b881333f12a311ae9ef34da474.pngSQL_ID  62mars8u2ysj1, childnumber04f1150b881333f12a311ae9ef34da474.png-------------------------------------4f1150b881333f12a311ae9ef34da474.pngupdatesl_szy_mwr_intra .WR_MP_HOURW_RsetMP_CD=4f1150b881333f12a311ae9ef34da474.png'2201050002001',        SPE_REG_DATA='0',         HOUR_W=1368.0,    

4f1150b881333f12a311ae9ef34da474.png    DT=to_date('06-05-2015 06:00:00','dd-mm-yyyy hh24:mi:ss')   

4f1150b881333f12a311ae9ef34da474.pngwhereMP_CD='2201050002001'andDT=to_date('06-05-2015 

4f1150b881333f12a311ae9ef34da474.png06:00:00','dd-mm-yyyy hh24:mi:ss')

4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngPlanhash value:2347945404f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.png-----------------------------------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png|Id|Operation|Name|E-Rows|E-Bytes|Cost (%CPU)|E-Time|4f1150b881333f12a311ae9ef34da474.png-----------------------------------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png|0|UPDATESTATEMENT||||3(100)||4f1150b881333f12a311ae9ef34da474.png|1|UPDATE|WR_MP_HOURW_R|||||4f1150b881333f12a311ae9ef34da474.png|*2|INDEXUNIQUESCAN|WR_MP_HOURW_R_PRI|1|24|2(0)|00:00:01|4f1150b881333f12a311ae9ef34da474.png-----------------------------------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.pngQuery Block Name/Object Alias (identifiedbyoperation id):

4f1150b881333f12a311ae9ef34da474.png-------------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png1-UPD$14f1150b881333f12a311ae9ef34da474.png2-UPD$1/WR_MP_HOURW_R@UPD$14f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngOutline Data

4f1150b881333f12a311ae9ef34da474.png-------------4f1150b881333f12a311ae9ef34da474.png1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/**//*+

d18c02628675d0a2c816449d98bda930.png      BEGIN_OUTLINE_DATA

d18c02628675d0a2c816449d98bda930.png      IGNORE_OPTIM_EMBEDDED_HINTS

d18c02628675d0a2c816449d98bda930.png      OPTIMIZER_FEATURES_ENABLE('11.2.0.3')

d18c02628675d0a2c816449d98bda930.png      DB_VERSION('11.2.0.3')

d18c02628675d0a2c816449d98bda930.png      ALL_ROWS

d18c02628675d0a2c816449d98bda930.png      OUTLINE_LEAF(@"UPD$1")

d18c02628675d0a2c816449d98bda930.png      INDEX(@"UPD$1" "WR_MP_HOURW_R"@"UPD$1" ("WR_MP_HOURW_R"."DT" 

d18c02628675d0a2c816449d98bda930.png              "WR_MP_HOURW_R"."MP_CD"))

d18c02628675d0a2c816449d98bda930.png      END_OUTLINE_DATA

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngPredicate Information (identifiedbyoperation id):

4f1150b881333f12a311ae9ef34da474.png---------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png2-access("DT"=TO_DATE('2015-05-06 06:00:00','syyyy-mm-dd hh24:mi:ss')AND4f1150b881333f12a311ae9ef34da474.png              "MP_CD"='2201050002001')

4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngColumnProjection Information (identifiedbyoperation id):

4f1150b881333f12a311ae9ef34da474.png-----------------------------------------------------------4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png2-(upd=2,3,4,5; cmp=2,3; cpy=2,3) "WR_MP_HOURW_R".ROWID[ROWID,10], 

4f1150b881333f12a311ae9ef34da474.png       "MP_CD"[CHARACTER,13], "DT"[DATE,7], "HOUR_W"[NUMBER,22], 

4f1150b881333f12a311ae9ef34da474.png       "SPE_REG_DATA"[CHARACTER,1]4f1150b881333f12a311ae9ef34da474.png 

4f1150b881333f12a311ae9ef34da474.pngNote

4f1150b881333f12a311ae9ef34da474.png-----4f1150b881333f12a311ae9ef34da474.png-Warning: basicplanstatisticsnotavailable. These areonlycollectedwhen:

4f1150b881333f12a311ae9ef34da474.png*hint'gather_plan_statistics'isusedforthe statementor4f1150b881333f12a311ae9ef34da474.png*parameter'statistics_level'issetto'ALL', at sessionorsystemlevel4f1150b881333f12a311ae9ef34da474.png

~end~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值