数据类型不一致和字符长度跨度大引起的绑定变量bind mismatch问题
背景:
接到用户报障说一套Oracle19c数据库近期出现insert语句执行变慢的情况,执行一次数据插入需要1秒+的时间,而且问题发生的数据库是跑在一体机上面,数据插入正常不应该这么慢,需要分析插入慢的原因
问题:
数据库近期出现insert语句执行变慢的情况,执行一次数据插入需要1秒+的时间,查看问题的insert语句使用了大量的绑定变量,数量达到5000+个
1 2 3 4 5 6 7 8 9 10 11 12 | --语句通过union构造多条数据进行批量插入 insert into table(A,B,C) select :1,:2,:3 from dual uion all select :4,:5,:6 from dual ... uion all select :5098,:5099,:5100 from dual |
问题分析:
查看语句的执行信息,可以看到语句下面有多个子游标,执行速度时快时慢,有的游标执行速度最慢到达3-4秒,最快则0.1秒,每个游标的执行计划都是相同的4069240402
我们首先排除是由于执行计划慢导致的问题一是语句的执行计划非常简单直接,就是通过查询dual然后插入表,二是语句的执行计划固定都是4069240402,但不同游标的执行速度会不一样
这里语句比较有问题的是,语句的有大量的子游标,游标复用率极低,基本每次执行都新生成一个子游标
继续通过10046跟踪语句的执行消耗,可以看到语句的主要消耗在CPU的execute,语句Misses in libarary cache during execute次数等于执行次数,每次执行在共享池里面均没有复用的缓存游标,也就是说每次执行都需要重新解析,结合语句存在大量的子游标,我们基本可以确定语句的主要性能瓶颈在于语句的子游标复用率极低,每次执行都需要重新硬解析生成新的子游标
查看语句的游标使用情况,通过数据库字典V$SQL_SHARED_CURSOR获取到语句下面有1000+的子游标,生成子游标的原因都是为BIND_MISMATCH
分析语句bind mismatch出现的原因,通过数据库字典v$sql_bind_capture查看应用SQL语句传入的绑定变量字段类型,再与插入目标表的字段类型进行比对,我们发现主要的原因为
1 传入变量类型TIMESTAMP与目标表的类型DATE不一致
2 传入变量varchar2长度跨度很大,同一个变量值,传入的长度出现分别为32,128,2000,4000,8192
根据Oracle官方对于bind mismatch的说明(Troubleshooting: High Version Count Issues (Doc ID 296377.1)),上述两种情形都会导致语句由于bind mismatch产生一个新的子游标,发生硬解析