年后一次系统升级后,监控数据库的工具DPA发现数据库的Total Wait时间突然飙增,如下截图所示,数据库的总体等待时间对比升级前飙增了非常多

另外就是发现出现了较多的等待事件,主要有latch: cache buffers chains、 latch: shared pool 、db file scattered read。根据这边的监控发现TOP SQL里面从升级前的0次变为了一天的一万多次(有些甚至更多),分析过后我们就找开发人员了解一下系统升级变跟的内容和改动

开发人员坚定的告诉们介绍,他只是将他负责的那个模块里面那些拼接SQL(Literal SQL)语句改写成了绑定变量(因为我们系统大量使用拼接SQL的方式,硬解析非常严重),所以我们一直建议他们使用绑定变量。由于改为绑定变量,所以DPA以前没有捕获这些SQl,后面因为执行次数激增,所以捕获了这些SQL,也发现其执行次数明显变化了,例如有些SQL语句的执行次数上万了。

后面经过分析、跟踪过后发现修改为绑定变量的SQL的实际执行计划变成全表扫描了。这也能解释为什么db file scattered read等待事件出现,因为全表扫描的缘故。下面就其中的一个SQL语句做分析,如下所示,我们在Toad或SQL Developer工具里面查看预估执行计划时,其执行计划都是走索引扫描(Index Scan),但是实际执行计划就是走全表扫描

实际执行计划(截图来自WORKLOAD REPOSITORY SQL Report )

刚开始我们以为是绑定变量的窥探机制造成(使用SQL首次运行时的值来生成执行计划。后续再次运行该SQL语句则使用首次执行计划来执行),但是分析过后发现,SC_NO这个字段建有唯一索引,不存在所谓的数据倾斜的情况。非常的纠结,纳闷,不解。同事用10046跟踪了SQL语句(其实是跟踪某个自己在Toad里面执行的SQL语句,这也是问题一直没有发现的原因),想不明白为什么,隐隐怀疑是数据库的bug来着,直到后面我在sqltrpt.sql查看某些SQL的调优优化建议,突然看到下面信息:

3- Restructure SQL finding (see plan 1 in explain plans section)

---------------------------------------------------------------------------

The predicate SYS_OP_C2C("SC_NO")=:B1 used at line ID 5 of the execution plan contains an implicit data type conversion on indexed column "SC_NO".This implicit data type conversion prevents the optimizer from selecting indices on table "SC_HD".

Recommendation

--------------------------------------------------------------------------

- Rewrite the predicate into an equivalent form to take advantage of indices.

顿时豁然开朗,肯定是开发人员在使用绑定变量时,使用了不一致的数据类型,导致了隐式转换(implicit data type conversion),于是联系开发人员确认,要了程序里面的代码,果然如此,SC_NO的数据类型为VARCHAR2,但是在代码里面绑定变量的类型为OracleType.NVarChar。悲剧的是几乎所有绑定变量都由于开发人员疏忽,都给错了数据类型。所以出现这么严重的情况

...........................................................

param = new OracleParameter(":scNo", OracleType.NVarChar);

            param.Value = Server.UrlDecode(joNo).ToUpper();

            paramsList.Add(param);

...........................................................

那么我们下面我们模拟一下绑定变量数据类型不一致,出现隐式转换导致不走索引的情况

SQL> alter system flush shared_pool;

 

System altered.

 

SQL> set autotrace on;

SQL> variable sc_no nvarchar2(20);

SQL> exec :sc_no :='A01Adfddf01I';

 

PL/SQL procedure successfully completed.

 

SQL> select  count(1) from sc_hd 

  2  where sc_no =:sc_no 

  3    and jo_status<>'l2' 

  4    and status<>'x';

 

  COUNT(1)

----------

         0

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 326413811

 

----------------------------------------------------------------------------------------

| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT             |         |     1 |    16 |     3   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE              |         |     1 |    16 |            |          |

|*  2 |   TABLE ACCESS BY INDEX ROWID| SC_HD   |     1 |    16 |     3   (0)| 00:00:01 |

|*  3 |    INDEX UNIQUE SCAN         | SC_HEAD |     1 |       |     2   (0)| 00:00:01 |

----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - filter("JO_STATUS"<>'l2' AND "STATUS"<>'x')

   3 - access("SC_NO"=:SC_NO)

 

 

Statistics

----------------------------------------------------------

       2082  recursive calls

          6  db block gets

     109260  consistent gets

     108647  physical reads

          0  redo size

        514  bytes sent via SQL*Net to client

        492  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

         48  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

SQL> 

此时,你查看实际执行计划,就会发现其走全表扫描。如下所示

如果此时你用一模一样的SQL(空格,字符大小一致,如下所示),在TOAD里面执行,即使你给绑定变量赋予的是VARCHAR2类型的数据,也会发现其实际执行计划走全表扫描,这个是因为绑定变量窥探,使用SQL首次运行时的值来生成执行计划。后续再次运行该SQL语句则使用首次执行计划来执行的缘故

select  count(1) from sc_hd 

where sc_no =:sc_no 

  and jo_status<>'l2' 

  and status<>'x';

如果空格不一致,或大小写,或换行不一致,你又会发现其实际执行计划走索引了,这也是当初我们在不了解应用程序源代码的情况,被这个情况给折腾疯了的情况,以为是数据库的bug引起的。其实还是因为绑定变量的数据类型与实际字段的数据类型不一致而引起的。

ORACLE绑定变量隐式转换导致性能问题的更多相关文章

  1. 关于ORACLE隐式转换后性能问题

    SELECT TM.MONEY_CODE FROM T_CONTRACT_MASTER T,T_MONEY TM WHERE T.MONEY_ID = TM.MONEY_ID AND T.POLICY ...

  2. oracle数据类型及其隐式转换

    oracle有三种最基本的数据类型,即字符型.数值型.日期型. oracle提供的单行函数中,针对不同的数据类型,提供大量实用的函数,同时提供一系列数据类型转换函数,如下: 1)to_char     ...

  3. SQL Server中提前找到隐式转换提升性能的办法

        http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...

  4. 隐式转换导致的cpu负载近100%

    1.背景:从昨天晚上通过钉钉和邮箱一直接收到频繁报cpu负载超过90%,刚好BI同事晚上.凌晨在线上配合审计频繁DML数据库(备注:BI有一个同事有个库的DML权限,后面等审计完会收回)加上我线上线下 ...

  5. mysql字符串的隐式转换导致查询异常

    如果mysql某个字段(name)类型为varchar, 加了索引,在执行where查询的时候,传入了int的值,这样就会全表扫描,把每一条的值都转换成int(会出现"中国"-&g ...

  6. DB性能-隐式转换

    1        什么是隐式转换 当源数据的类型和目标数据的类型不同的时候,如果没有转换函数,就会发生隐式转换,也称自动转换.当然, 有些情况下有些类型是不可以发生转换的,比如说从DATE类型转换到N ...

  7. MySQL性能优化:MySQL中的隐式转换造成的索引失效

    数据库优化是一个任重而道远的任务,想要做优化必须深入理解数据库的各种特性.在开发过程中我们经常会遇到一些原因很简单但造成的后果却很严重的疑难杂症,这类问题往往还不容易定位,排查费时费力最后发现是一个很 ...

  8. Oracle数据类型隐式转换小析

    测试使用环境:oracle 11g r1 平常写sql语句时,大大咧咧,不太注意和数字有关的数据类型,有时例如 where c1=111 和 where c1='111'这样混用,却不曾想这里面另有蹊 ...

  9. 大坑啊oracle的隐式转换

    (25)禁止使用属性隐式转换 解读:SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引,猜猜为什么?(这个线上问题不 ...

随机推荐

  1. MySQL 语句大全--------添加列,修改列,删除列

    ALTER TABLE:添加,修改,删除表的列,约束等表的定义. 查看列:desc 表名; 修改表名:alter table t_book rename to bbb; 添加列:alter table ...

  2. 用于PHP的Gearman Worker管理工具GearmanManager

    项目地址:https://github.com/brianlmoon/GearmanManager PHP环境要求 PHP 5.5.9 POSIX extension Process Control ...

  3. MongoVUE(MongoDB图像管理工具)

    介绍一款很不错的开源的MongoDB图形化管理工具:MongoVUE 下载地址:MongoVUE 1.6.9 破解版

  4. java Servlet+mysql 调用带有输入参数和返回值的存储过程(原创)

    这个数据访问的功能,我在.NET+Mysql .NET+Sqlserver  PHP+Mysql上都实现过,并且都发布在了我博客园里面,因为我觉得这个功能实在是太重要,会让你少写很多SQL语句不说,还 ...

  5. phpcms v9 数据源

    先到phpcms后台的模块下找到数据源 数据源有两种方式 1,内部数据源 2,外部数据源 这里只做外部数据源.添加一个外部数据源 1)必须填写数据库链接信息,指定一个数据名(在站内调用是使用) 2)进 ...

  6. Guacamole之本地安装Guacamole(二)

    摘要 在网上看到一篇Guacamole官方手册的翻译,但是找不到后续,于是想自己也翻译几篇,有时间的话,会尽量多翻译一些. 原文地址:http://guacamole.incubator.apache ...

  7. ENVI数据显示操作【Tools菜单操作1】

    ---恢复内容开始--- 一.Tools菜单命令及其功能 主图像窗口中Tool菜单多对应的下拉菜单共17项命令. 二.窗口链接/覆盖显示 窗口链接和叠加显示(Link和Overlay)是对多幅图像某一 ...

  8. 基于RulesEngine的业务规则实现

    规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策.接受数据输入,解释业务规则,并根据业务规则做出业务决策.比较常见 ...

  9. javascript数据类型理解整理

    起因:关于数据类型这块,自己看了很多遍相关的资料,每次查看和实践都有一些体会和理解:但又感到没有理解透,总是差一点,最近又在看这块的内容,加上最近的积累,做个相关笔记 ECMAScript数据类型:1 ...

  10. [js开源组件开发]模拟下拉选项框select

    模拟下拉选项框select 在css3流行的情况下,下拉框还是无法满足PD的需求,所以有了autosearch,有了模拟下拉框.效果如下图: select DEMO请案例点击这里查看.http://w ...