当前位置:首页 » 编程语言 » sql语句不能被解析
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

sql语句不能被解析

发布时间: 2023-05-10 16:19:11

sql 语句的解析过程

五、 SELECT 子句

尽管出现在sql语句的最前面,SELECT在第五步的时候才被处理,SELECT子句返回的表会最终返回给调用者。这个子句包含三个子阶段:(5-1)计算表达式,(5-2) 处理DISTINCT,(5-3)应用TOP过滤。

1、 计算表达式

SELECT子句中的表达式可以返回或者操作前一步表中返回的基本列。如果这个sql语句是一个聚合查询,在Step 3之后,你只能使用GROUP BY中的列,对不属于GROUP集合中的列必须使用聚合运算。不属于FROM表中基本列的必须为其起一个别名,如YEAR(orderdate) AS orderyear。

注意:在SELECT子句中创建的别名,不能在之前的Step中使用,即使在SELECT子句中也不能。原因是sql的很多操作是同时操作(all at once operation),至于什么是all-at-once operation这里就不再介绍了。因此,SELECT子句中创建的别名只能在后面的子句中使用,如ORDER BY。例如:SELECT YEAR(orderdate) AS orderyear . . . ORDER BY orderyear。

在这个例子中:

SELECT C.customerid, COUNT(O.orderid) AS numorders

结果会得到一个虚拟表VT5-1:

C.customerid numorders

FIFSSA 0

FRNDO 2

2、应用DISTINCT子句

如果sql语句中使用了DISTINCT,sql会把重复列去掉,生成虚拟表VT5-2。

3、应用TOP选项

TOP选项是T-SQL提供的一个功能,用来表示显示多少行。基于ORDER BY子句定义的顺序,指定个数的列会被查询出来。这个过程生成虚拟表VT5-3。

正如上文提到的,这一步依赖于ORDER BY定义的顺序来决定哪些列应该显示在前面。如果你没有指定结果的ORDER BY顺序,也没有使用WITH TIES子句,每一次的返回结果可能会不一致。

在我们的例子中,Step 5-3被省略了,因为我们没有使用TOP关键字。

六、ORDER BY子句

前一步返回的虚拟表在这一步被排序,根据ORDER BY子句指定的顺序,返回游标VC6。ORDER BY子句也是唯一一个可以使用SELECT子句创建的别名的地方。

注意:这一步和之前不同的地方在于,这一步返回的结果是一个游标,而不是表。sql是基于集合理论的,一个集合没有对他的行定义顺序,它只是一个成员的逻辑集合,因此成员的顺序并不重要。带有ORDER BY子句的sql返回一个按照特定序列组织每一行的对象。ANSI 把这样的一个对象叫游标。理解这一点对你了解sql很重要。

上面的步骤如图所示:

❷ 如何对变异的sql语句做解析处理

优化SQL查询:如何写出高性能SQL语句1、首先要搞明白什么叫执行计划?执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生欀如一条SQL语句如果用来从一个10万条记录的表中查1条记录,那查询优化器会选择“索引查找”方式,如果该表进行了归档,当前只剩下5000条记录了,那查询优化器就会改变方案,采用“全表扫描”方式。可见,执行计划并不是固定的,它是“个性化的”。产生一个正确的“执行计划”有两点很重要:(1)SQL语句是否清晰地告诉查询优化器它想干什么?(2)查询优化器得到的数据库统计信息是否是最新的、正确的?2、统一SQL语句的写法对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的。select*fromalselect*Fromal其实就是大小写不同,查询分析器就认为是两句不同的SQL语句,必须进行两次解析。生成2个执行计划。所以作为程序员,应该保证相同的查询语句在任何地方都一致,多一个空格都不行!3、不要把SQL语句写得太复杂我经常看到,从数据库中捕捉到的一条SQL语句打印出来有2张A4纸这么长。一般来说这么复杂的语句通常都是有问题的。我拿着这2页长的SQL语句去请教原作者,结果他说时间太长,他一时也看不懂了。可想而知,连原作者都有可能看糊涂的SQL语句,数据库也一样会看糊涂。一般,将一个Select语句的结果作为子集,然后从该子集中再进行查询,这种一层嵌套语句还是比较常见的,但是根据经验,超过3层嵌套,查询优化器就很容易给出错误的执行计划。因为它被绕晕了。像这种类似人工智能的东西,终究比人的分辨力要差些,如果人都看晕了,我可以保证数据库也会晕的。另外,执行计划是可以被重用的,越简单的SQL语句被重用的可能性越高。而复杂的SQL语句只要有一个字符发生变化就必须重新解析,然后再把这一大堆垃圾塞在内存里。可想而知,数据库的效率会何等低下。4、使用“临时表”暂存中间结果简化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。5、OLTP系统SQL语句必须采用绑定变量select*>’2010-10-2000:00:01′select*>’2010-09-2200:00:01′以上两句语句,查询优化器认为是不同的SQL语句,需要解析两次。如果采用绑定变量select*>@chgtime@chgtime变量可以传入任何值,这样大量的类似查询可以重用该执行计划了,这可以大大降低数据库解析SQL语句的负担。一次解析,多次重用,是提高数据库效率的原则。6、绑定变量窥测事物都存在两面性,绑定变量对大多数OLTP处理是适用的,但是也有例外。比如在where条件中的字段是“倾斜字段”的时候。“倾斜字段”指该列中的绝大多数的值都是相同的,一张人口调查表,其中“民族”这列,90%以上都是汉族。那么如果一个SQL语句要查询30岁的汉族人口有多少,那“民族”这列必然要被放在where条件中。这个时候如果采用绑定变量@nation会存在很大问题。试想如果@nation传入的第一个值是“汉族”,那整个执行计划必然会选择表扫描。然后,第二个值传入的是“布依族”,按理说“布依族”占的比例可能只有万分之一,应该采用索引查找。但是,由于重用了第一次解析的“汉族”的那个执行计划,那么第二次也将采用表扫描方式。这个问题就是着名的“绑定变量窥测”,建议对于“倾斜字段”不要采用绑定变量。7、只在必要的情况下才使用begintranSQLServer中一句SQL语句默认就是一个事务,在该语句执行完成后也是默认commit的。其实,这就是begintran的一个最小化的形式,好比在每句语句开头隐含了一个begintran,结束时隐含了一个commit。有些情况下,我们需要显式声明begintran,比如做“插、删、改”操作需要同时修改几个表,要求要么几个表都修改成功,要么都不成功。begintran可以起到这样的作用,它可以把若干SQL语句套在一起执行,最后再一起commit。好处是保证了数据的一致性,但任何事情都不是完美无缺的。Begintran付出的代价是在提交之前,所有SQL语句锁住的资源都不能释放,直到commit掉。可见,如果Begintran套住的SQL语句太多,那数据库的性能就糟糕了。在该大事务提交之前,必然会阻塞别的语句,造成block很多。Begintran使用的原则是,在保证数据一致性的前提下,begintran套住的SQL语句越少越好!有些情况下可以采用触发器同步数据,不一定要用begintran。8、一些SQL查询语句应加上nolock在SQL语句中加nolock是提高SQLServer并发性能的重要手段,在oracle中并不需要这样做,因为oracle的结构更为合理,有undo表空间保存“数据前影”,该数据如果在修改中还未commit,那么你读到的是它修改之前的副本,该副本放在undo表空间中。这样,oracle的读、写可以做到互不影响,这也是oracle广受称赞的地方。SQLServer的读、写是会相互阻塞的,为了提高并发性能,对于一些查询,可以加上nolock,这样读的时候可以允许写,但缺点是可能读到未提交的脏数据。使用nolock有3条原则。(1)查询的结果用于“插、删、改”的不能加nolock!(2)查询的表属于频繁发生页分裂的,慎用nolock!(3)使用临时表一样可以保存“数据前影”,起到类似oracle的undo表空间的功能,能采用临时表提高并发性能的,不要用nolock。9、聚集索引没有建在表的顺序字段上,该表容易发生页分裂比如订单表,有订单编号orderid,也有客户编号contactid,那么聚集索引应该加在哪个字段上呢?对于该表,订单编号是顺序添加的,如果在orderid上加聚集索引,新增的行都是添加在末尾,这样不容易经常产生页分裂。然而,由于大多数查询都是根据客户编号来查的,因此,将聚集索引加在contactid上才有意义。而contactid对于订单表而言,并非顺序字段。比如“张三”的“contactid”是001,那么“张三”的订单信息必须都放在这张表的第一个数据页上,如果今天“张三”新下了一个订单,那该订单信息不能放在表的最后一页,而是第一页!如果第一页放满了呢?很抱歉,该表所有数据都要往后移动为这条记录腾地方。SQLServer的索引和Oracle的索引是不同的,SQLServer的聚集索引实际上是对表按照聚集索引字段的顺序进行了排序,相当于oracle的索引组织表。SQLServer的聚集索引就是表本身的一种组织形式,所以它的效率是非常高的。也正因为此,插入一条记录,它的位置不是随便放的,而是要按照顺序放在该放的数据页,如果那个数据页没有空间了,就引起了页分裂。所以很显然,聚集索引没有建在表的顺序字段上,该表容易发生页分裂。曾经碰到过一个情况,一位哥们的某张表重建索引后,插入的效率大幅下降了。估计情况大概是这样的。该表的聚集索引可能没有建在表的顺序字段上,该表经常被归档,所以该表的数据是以一种稀疏状态存在的。比如张三下过20张订单,而最近3个月的订单只有5张,归档策略是保留3个月数据,那么张三过去的15张订单已经被归档,留下15个空位,可以在insert发生时重新被利用。在这种情况下由于有空位可以利用,就不会发生页分裂。但是查询性能会比较低,因为查询时必须扫描那些没有数据的空位。重建聚集索引后情况改变了,因为重建聚集索引就是把表中的数据重新排列一遍,原来的空位没有了,而页的填充率又很高,插入数据经常要发生页分裂,所以性能大幅下降。对于聚集索引没有建在顺序字段上的表,是否要给与比较低的页填充率?是否要避免重建聚集索引?是一个值得考虑的问题!10、加nolock后查询经常发生页分裂的表,容易产生跳读或重复读加nolock后可以在“插、删、改”的同时进行查询,但是由于同时发生“插、删、改”,在某些情况下,一旦该数据页满了,那么页分裂不可避免,而此时nolock的查询正在发生,比如在第100页已经读过的记录,可能会因为页分裂而分到第101页,这有可能使得nolock查询在读101页时重复读到该条数据,产生“重复读”。同理,如果在100页上的数据还没被读到就分到99页去了,那nolock查询有可能会漏过该记录,产生“跳读”。上面提到的哥们,在加了nolock后一些操作出现报错,估计有可能因为nolock查询产生了重复读,2条相同的记录去插入别的表,当然会发生主键冲突。11、使用like进行模糊查询时应注意有的时候会需要进行一些模糊查询比如select*fromcontactwhereusernamelike‘%yue%’关键词%yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%,12、数据类型的隐式转换对查询效率的影响sqlserver2000的数据库一的程序在提交sql语句的时候,没有使用强类型提交这个字段的值,由sqlserver2000自动转换数据类型,会导致传入的参数与主键字段类型不一致,这个时候sqlserver2000可能就会使用全表扫描。Sql2005上没有发现这种问题,但是还是应该注意一下。13、SQLServer表连接的三种方式(1)MergeJoin(2)NestedLoopJoin(3)HashJoinSQLServer2000只有一种join方式——NestedLoopJoin,如果A结果集较小,那就默认作为外表,A中每条记录都要去B中扫描一遍,实际扫过的行数相当于A结果集行数xB结果集行数。所以如果两个结果集都很大,那Join的结果很糟糕。SQLServer2005新增了MergeJoin,如果A表和B表的连接字段正好是聚集索引所在字段,那么表的顺序已经排好,只要两边拼上去就行了,这种join的开销相当于A表的结果集行数加上B表的结果集行数,一个是加,一个是乘,可见mergejoin的效果要比NestedLoopJoin好多了。如果连接的字段上没有索引,那SQL2000的效率是相当低的,而SQL2005提供了Hashjoin,相当于临时给A,B表的结果集加上索引,因此SQL2005的效率比SQL2000有很大提高,我认为,这是一个重要的原因。总结一下,在表连接时要注意以下几点:(1)连接字段尽量选择聚集索引所在的字段(2)仔细考虑where条件,尽量减小A、B表的结果集(3)如果很多join的连接字段都缺少索引,而你还在用SQLServer2000,赶紧升级吧。

❸ 为什么spring data jpa 的Query注解 不能解析SQL语句

MyBatis详解 与配置MyBatis+Spring+MySqlMyBatis 是一个可以自定余坦义SQL、存储过程和高级映射的持久层框架。MyBatis 摒除了大部分的JDBC代码、手工设置参数和结果集重获。MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型竖族桐、Map 接口和POJO 到数据库记录。相穗哪对Hibernate和Apache OJB等“一站式”ORM解决方案而言,Mybatis 是一种“半自动化”的ORM实现。需要使用的Jar包:mybatis-3.0.2.jar(mybatis核心包)。mybatis-spring-1.0.0.jar(与Spring结合包)。MyBatis简介 MyBatis 是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis 摒除了大部分的JDBC代码、手工设置参数和结果集重获。MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型、Map 接口和POJO 到数据库记录。相对Hibernate和Apache OJB等“一站式”ORM解决方案而言,Mybatis 是一种“半自动化”的ORM实现。需要使用的Jar包:mybatis-3.0.2.jar(mybatis核心包)。mybatis-spring-1.0.0.jar(与Spring结合包)。

❹ sql语句执行过程中会解析成二进制位被计算机识别吗在哪一个阶段被解析的

会解析成二进制的,和电脑交互的时候被解析的。

❺ oracle sql是怎么解析的

导读:Oracle的后台运作原理是什么?我们的一条命令是如何被执行的?今天我们就从一条简单的Select语句开始,看看Oracle数据库后台的运作机制。

Select语句可以说是DBA和数据库开发者在工作中使用最多的语句之一,但这条语句是如何执行?在Oracle数据库中又是如何运作的呢?今天我们就从一条简单的Select语句开始,看看Oracle数据库后台的运作机制。这对于我们之后的系统管理与故障排除非常有帮助。

第一步:客户端把语句发给服务器端执行

当我们在客户端执行select语句时,客户端会把这条SQL语句发送给服务器端,让服务器端的进程来处理这语句。也就是说,Oracle客户端是不会做任何的操作,他的主要任务就是把客户端产生的一些SQL语句发送给服务器端。虽然在客户端也有一个数据库进程,但是,这个进程的作用跟服务器上的进程作用事不相同的。服务器上的数据库进程才会对SQL语句进行相关的处理。不过,有个问题需要说明,就是客户端的进程跟服务器的进程是一一对应的。也就是说,在客户端连接上服务器后,在客户端与服务器端都会形成一个进程,客户端上的我们叫做客户端进程;而服务器上的我们叫做服务器进程。所以,由于所有的SQL语句都是服务器进程执行的,所以,有些人把服务器进程形象地比喻成客户端进程的“影子”。

第二步:语句解析

当客户端把SQL语句传送到服务器后,服务器进程会对该语句进行解析。同理,这个解析的工作,也是在服务器端所进行的。虽然这只是一个解析的动作,但是,其会做很多“小动作”。

1. 查询高速缓存。服务器进程在接到客户端传送过来的SQL语句时,不会直接去数据库查询。而是会先在数据库的高速缓存中去查找,是否存在相同语句的执行计划。如果在数据高速缓存中,刚好有其他人使用这个查询语句的话,则服务器进程就会直接执行这个SQL语句,省去后续的工作。所以,采用高速数据缓存的话,可以提高SQL语句的查询效率。一方面是从内存中读取数据要比从硬盘中的数据文件中读取数据效率要高,另一方面,也是因为这个语句解析的原因。

不过这里要注意一点,这个数据缓存跟有些客户端软件的数据缓存是两码事。有些客户端软件为了提高查询效率,会在应用软件的客户端设置数据缓存。由于这些数据缓存的存在,可以提高客户端应用软件的查询效率。但是,若其他人在服务器进行了相关的修改,由于应用软件数据缓存的存在,导致修改的数据不能及时反映到客户端上。从这也可以看出,应用软件的数据缓存跟数据库服务器的高速数据缓存不是一码事。

2. 语句合法性检查。当在高速缓存中找不到对应的SQL语句时,则数据库服务器进程就会开始检查这条语句的合法性。这里主要是对SQL语句的语法进行检查,看看其是否合乎语法规则。如果服务器进程认为这条SQL语句不符合语法规则的时候,就会把这个错误信息,反馈给客户端。在这个语法检查的过程中,不会对SQL语句中所包含的表名、列名等等进行SQL他只是语法上的检查。

3. 语言含义检查。若SQL语句符合语法上的定义的话,则服务器进程接下去会对语句中的字段、表等内容进行检查。看看这些字段、表是否在数据库中。如果表名与列名不准确的话,则数据库会就会反馈错误信息给客户端。

所以,有时候我们写select语句的时候,若语法与表名或者列名同时写错的话,则系统是先提示说语法错误,等到语法完全正确后,再提示说列名或表名错误。若能够掌握这个顺序的话,则在应用程序排错的时候,可以节省时间。

4. 获得对象解析锁。当语法、语义都正确后,系统就会对我们需要查询的对象加锁。这主要是为了保障数据的一致性,防止我们在查询的过程中,其他用户对这个对象的结构发生改变。对于加锁的原理与方法,我在其他文章中已经有专门叙述,在这里就略过不谈了。

5. 数据访问权限的核对。当语法、语义通过检查之后,客户端还不一定能够取得数据。服务器进程还会检查,你所连接的用户是否有这个数据访问的权限。若你连接上服务器的用户不具有数据访问权限的话,则客户端就不能够取得这些数据。故,有时候我们查询数据的时候,辛辛苦苦地把SQL语句写好、编译通过,但是,最后系统返回个 “没有权限访问数据”的错误信息,让我们气半死。这在前端应用软件开发调试的过程中,可能会碰到。所以,要注意这个问题,数据库服务器进程先检查语法与语义,然后才会检查访问权限。

6. 确定最佳执行计划。当语句与语法都没有问题,权限也匹配的话,服务器进程还是不会直接对数据库文件进行查询。服务器进程会根据一定的规则,对这条语句进行优化。不过要注意,这个优化是有限的。一般在应用软件开发的过程中,需要对数据库的sql语言进行优化,这个优化的作用要大大地大于服务器进程的自我优化。所以,一般在应用软件开发的时候,数据库的优化是少不了的。

当服务器进程的优化器确定这条查询语句的最佳执行计划后,就会将这条SQL语句与执行计划保存到数据高速缓存。如此的话,等以后还有这个查询时,就会省略以上的语法、语义与权限检查的步骤,而直接执行SQL语句,提高SQL语句处理效率。

第三步:语句执行

语句解析只是对SQL语句的语法进行解析,以确保服务器能够知道这条语句到底表达的是什么意思。等到语句解析完成之后,数据库服务器进程才会真正的执行这条SQL语句。

这个语句执行也分两种情况。一是若被选择行所在的数据块已经被读取到数据缓冲区的话,则服务器进程会直接把这个数据传递给客户端,而不是从数据库文件中去查询数据。若数据不在缓冲区中,则服务器进程将从数据库文件中查询相关数据,并把这些数据放入到数据缓冲区中。

这里仍然要注意一点,就是Oracle数据库中,定义了很多种类的高速缓存。像上面所说的SQL语句缓存与现在讲的数据缓存。我们在学习数据库的时候,需要对这些缓存有一个清晰的认识,并了解各个种类缓存的作用。这对于我们后续数据库维护与数据库优化是非常有用的。

第四步:提取数据

当语句执行完成之后,查询到的数据还是在服务器进程中,还没有被传送到客户端的用户进程。所以,在服务器端的进程中,有一个专门负责数据提取的一段代码。他的作用就是把查询到的数据结果返回给用户端进程,从而完成整个查询动作。

从这整个查询处理过程中,我们在数据库开发或者应用软件开发过程中,需要注意以下几点:

一是要了解数据库缓存跟应用软件缓存是两码事情。数据库缓存只有在数据库服务器端才存在,在客户端是不存在的。只有如此,才能够保证数据库缓存中的内容跟数据库文件的内容一致。才能够根据相关的规则,防止数据脏读、错读的发生。而应用软件所涉及的数据缓存,由于跟数据库缓存不是一码事情,所以,应用软件的数据缓存虽然可以提高数据的查询效率,但是,却打破了数据一致性的要求,有时候会发生脏读、错读等情况的发生。所以,有时候,在应用软件上有专门一个功能,用来在必要的时候清除数据缓存。不过,这个数据缓存的清除,也只是清除本机上的数据缓存,或者说,只是清除这个应用程序的数据缓存,而不会清除数据库的数据缓存。

二是绝大部分SQL语句都是按照这个处理过程处理的。我们DBA或者基于Oracle数据库的开发人员了解这些语句的处理过程,对于我们进行涉及到SQL语句的开发与调试,是非常有帮助的。有时候,掌握这些处理原则,可以减少我们排错的时间。特别要注意,数据库是把数据查询权限的审查放在语法语义的后面进行检查的。所以,有时会若光用数据库的权限控制原则,可能还不能满足应用软件权限控制的需要。此时,就需要应用软件的前台设置,实现权限管理的要求。而且,有时应用数据库的权限管理,也有点显得繁琐,会增加服务器处理的工作量。因此,对于记录、字段等的查询权限控制,大部分程序涉及人员喜欢在应用程序中实现,而不是在数据库上实现。

❻ 为什么spring data jpa 的Query注解 不能解析SQL语句

为什么spring data jpa 的Query注解 不能解析SQL语句
你铅型举这个findone(id)是用自己的槐碧@Query注解的jpql语句? 如果不是,方法应该是findOne(Interger id)才对,可但是你这个实体类哪里有id的字段; 你也可以试试findBy字段这种方式 另外注意下几个Repository接口的细微区别,会不租或会问题出在接口选择上面!

❼ 无法解析SQL语句, 请检查SQL语法错误. 代码: 1054 错误: Unknown column 's.uid' in 'where clause'

s代表的那个表里面没有uid这个字段,,,所以是未知的字段名,,你看看那个字段是不是uuid

❽ Sql语句解析过程

为了将用户写的SQL文本转化为Oracle认识的且可执行的语句 这个过程就叫做解析过程 解析分为硬解析和软解析 一条SQL语句在第一次被执行时必须进行硬解析

当客户端发出一条SQL语句(也可以是一个存储过程或者一个匿名PL/SQL块)进入shared pool时(注意 我们从前面已经知道 Oracle对这些SQL不叫做SQL语句 而是称为游标 因为Oracle在处理SQL时 需要很多相关的辅助信息 这些辅助信息与SQL语句一起组成了游标) Oracle首先将SQL文本转化为ASCII值 然后根据hash函数计算其对应的hash值(hash_value) 根据计算出的hash值到library cache中找到对应的bucket 然后比较bucket里是否存在该SQL语句

如果不存在 则需要按照我们前面所描述的 获得shared pool latch 然后在shared pool中的可用chunk链表(也就是bucket)上找到一个可用的chunk 之后释放shared pool latch 在获得了chunk以后 这块chunk就可以认为是进入了library cache 接下来 进行硬解析过程 硬解析包括以下几个步骤

对SQL语句进行文法检查 看是否有文法错误 比如没有写from select拼写错误等 如果存在文法错误 则退出解析过程

到数据字典里校验SQL语句涉及的对象和列是否都存在 如果不存在 则退出解析过程 这个过程会加载dictionary cache

将对象进行名称转换 比如将同名词翻译成实际的对象等 比如select * from t中 t是一个同名词 指向hr t 于是Oracle将t转换为hr t 如果转换失败 则退出解析过程

检查发出SQL语句的用户是否具有访问SQL语句里所引用的对象的权限 如果没有权限 则退出解析过程

通过优化器创建一个最优的执行计划 这个过程会根据数据字典里记录的对象的统计信息 来计算最优的执行计划 这一步牵涉大量数学运算 是最消耗CPU资源的

将该游标所产生的执行计划 SQL文本等装载进library cache的heap中

在硬解析的过程中 进程会一直持有library cache latch 直到硬解析结束为止 硬解析结束以后 会为SQL语句产生两个游标 一个是父游标 另一个是子游标 父游标里主要包含两种信息 SQL文本以及优化目标(optimizer goal) 父游标在第一次打开时被锁定 直到其他所有的session都关闭该游标后才被解锁 当父游标被锁定的时候是不能被交换出library cache的 只有在解锁以后才能被交换出library cache 父游标被交换出内存时 父游标对应的所有子游标也被交换出library cache 子游标包括游标所有的信息 比如具体的执行计划 绑定变量等 子游标随时可以被交换出library cache 当子游标被交换出library cache时 Oracle可以利用父游标的信息重新构建出一个子游标来 这个过程叫reload 可以使用下面的方式来确定reload的比率

select *sum(reloads)/sum(pins) Reload_Ratio from v$librarycache;

一个父游标可以对应多个子游标 子游标具体的个数可以从视图v$sqlarea的version_count字段体现出来 而每个具体的子游标则全都在视图v$sql里体现 当具体绑定变量的值与上次绑定变量的值有较大差异(比如上次执行的绑定变量值的长度是 位 而这次执行绑定变量的值的长度是 位)时或者当SQL语句完全相同 但是所引用的表属于不同的用户时 都会创建一个新的子游标

如果在bucket中找到了该SQL语句 则说明该SQL语句以前运行过 于是进行软解析 软解析是相对于硬解析而言的 如果解析过程中 可以从硬解析的步骤中去掉一个或多个的话 这样的解析就是软解析 软解析分为以下三种类型

第一种是某个session发出的SQL语句与library? cache里其他session发出的SQL语句一致 这时 该解析过程中可以去掉硬解析中的 和 但是仍然要进行硬解析过程中的 也就是表名和列名检查 名称转换和权限检查

* 第二种是某个session发出的SQL语句是该session之前发出的曾经执行过的SQL语句 这时 该解析过程中可以去掉硬解析中的 和 这四步 但是仍然要进行权限检查 因为可能通过grant改变了该session用户的权限

* 第三种是当设置了初始化参数session_cached_cursors时 当某个session第三次执行相同的SQL时 则会把该SQL语句的游标信息转移到该session的PGA里 这样 该session以后再执行相同的SQL语句时 会直接从PGA里取出执行计划 从而跳过硬解析的所有步骤 这种情况下 是最高效的解析方式 但是会消耗很大的内存

我们举一个例子来说明解析SQL语句的过程 在该测试中 绑定变量名称相同 但是变量类型不同时 所出现的解析情况 如下所示

首先 执行下面的命令 清空shared pool里所有的SQL语句

SQL> alter system flush shared_pool;

然后 定义一个数值型绑定变量 并为该绑定变数赋一个数值型的值以后 执行具体的查询语句

SQL> variable v_obj_id number;

SQL> exec :v_obj_id := ;

SQL> select object_id object_name from sharedpool_test

where object_id=:v_obj_id;

OBJECT_ID OBJECT_NAME

AGGXMLIMP

接下来 定义一个字符型的绑定变量 变量名与前面相同 为该绑定变数赋一个字符型的值以后 执行相同的查询

SQL> variable v_obj_id varchar ( );

SQL> exec :v_obj_id := ;

SQL> select object_id object_name from sharedpool_test

where object_id=:v_obj_id;

OBJECT_ID OBJECT_NAME

AGGXMLIMP

然后我们到视图v$sqlarea里找到该SQL的父游标的信息 并到视图v$sql里找该SQL的所有子游标的信息

SQL> select sql_text version_count from v$sqlarea where

sql_text like %sharedpool_test% ;

SQL_TEXT

VERSION_COUNT

select object_id object_name from sharedpool_test where

object_id=:v_obj_id

SQL> select sql_text child_address address from v$sql

where sql_text like %sharedpool_test% ;

SQL_TEXT

CHILD_ADDRESS ADDRESS

select object_id object_name from sharedpool_test where

object_id=:v_obj_id F

B D

select object_id object_name from sharedpool_test where

object_id=:v_obj_id FC

B D

从记录父游标的视图v$sqlarea的version_count列可以看到 该SQL语句有 个子游标 而从记录子游标的视图v$sql里可以看到 该SQL文本确实有两条记录 而且它们的SQL文本所处的地址(ADDRESS列)也是一样的 但是子地址(CHILD_ADDRESS)却不一样 这里的子地址实际就是子游标所对应的heap 的句柄

lishixin/Article/program/Oracle/201311/18653