各位新朋友~记得先点蓝字关注我哦~
问题描述
某医院客户反映两套数据库,.NET应用同样的插入语句,一套数据库insert要1秒左右,对业务有很大的影响,另外一套数据库插入却很快,相同的inser语句在别的非.NET程序相应明显快于.NET程序。
处理过程
在应用端通过sqlmontor监控应用sql执行日志发现,在应用insert时,会伴随着两条查询基表的语句,如下:

通过awr、ash报告并未发现业务语句执行慢,但发现有条查询基表的sql语句特别频繁:

sql语句select ac.constraint_name key_name, acc.column_name key_col,:"SYS_B_0" from all_cons_columns acc, all_constraints ac where acc.owner = ac.owner and acc.constraint_name = ac.constraint_name and acc.table_name = ac.table_name and ac.constraint_type = :"SYS_B_1" and ac.owner = :OwnerName and ac.table_name = :TableName order by acc.constraint_name执行非常频繁。
“exec dbms_system.set_ev(4046,61359,10046,12,’’);”对查询ip发起的IIS会话进行跟踪

结果显示在跟踪时段内,一共解析与执行6次,总耗时0.02秒,进一步证实单独的插入过程在数据库内执行效率不存在异常。
在跟踪文件中,发现.net发起的查询系统all_synonyms和all_cons_columns、all_constraints关联表信息,这些系统查询也花费了不少时间,该多余查询也影响了客户端的返回时间。
查询Oracle官方文档,该SQL语句为.NET特性自动发起的语句,解释如下:


具体官方文档为Frequent Query on ALL_CONS_COLUMNS And ALL_CONSTRAINTS When Using ODP.Net Statement Caching (Doc ID 1386371.1),官方解释该语句确实为.NET自身发起,而非程序生成的语句。
解决办法为增加.NET端语句缓存,一次执行多次使用,建议调整Statement Cache Size=200。
比较问题库和正常库两个基表all_cons_columns, all_constraints查询的执行计划,下图为有问题的数据库执行计划,走的是全表访问:

下图为正常库的执行计划,走的是索引

可以确定插入慢是由于基表查询执行计划评估出错而导致的,检查统计基本统计信息:

两个基表已经收集过统计信息,通过10053跟踪,发现数据库确实选择了强制进行全表查询

这说明走全表查询在数据库层面认为消耗比走索引低,查询使用列柱状信息

关联使用到CON$所在列OWNER#,列的信息没有收集,依然使用默认选择度,选择了错误的执行路径。
方法一:对CON$所在列OWNER#做列统计信息收集。

方法二:对查询的sql_id做SQLTUNE分析

接受性能较好的sqlprofile


总结
insert SQL语句在数据库内部执行并不慢,在12毫秒左右,唯一与其他程序的区别在于.NET自行发起的内部对象查询非实际应用发起,由于此现象为.NET特性无法改变,官方建议调大.NET端语句缓存,减少对数据库内部对象的查询,提高效率。
但是由于客户不能从代码层面修改.NET端语句缓存。所以只能从sql查询语句性能层面进行优化。在数据库层面,通过SQLTUNE的优化建议对sql查询语句进行优化和对统计信息进行重新收集。
美创运维中心数据库服务团队拥有Oracle ACE 1人、OCM 10余人、数十名Oracle OCP、MySQL OCP、红帽RHCA、中间件weblogic、tuxedo认证、达梦工程师 ,著有《Oracle DBA实战攻略》,《Oracle数据库性能优化方法和最佳实践》,《Oracle内核技术揭秘》等多本数据运维优化书籍。目前运维各类数据库合计2000余套,精通Oracle、MySQL、SQLServer、DB2、PostgreSQL、达梦等主流商业和开源数据库。并成为首批国内达梦战略合作伙伴之一,拥有海量经验和完善的人员培养体系。并同时提供超融合,私有云整体解决方案。







