Oracle数据库作为一个管理数据的产品,必须能够认出用户所提交的管理命令(通常叫做SQL语句),从而进行响应。认出的过程叫做解析SQL语句的过程,响应的过程叫做执行SQL语句的过程。解析是一个相当复杂的过程,它要考虑各种可能的异常情况,比如SQL语句涉及的对象不存在、提交的用户没有权限等。而且,还需要考虑如何执行SQL语句,采用什么方式去获取数据等。解析的最终结果是要产生 Oracle自 己内部的执行计划,从而指导SQL的执行过程。可以看到,解析是一个非常消耗资源的过程。因此,Oracle在解析用户提交的SQL 语句的过程 中,如果对每次出现的新的SQL语句都按照标准过程完整地从头到尾解析一遍的话,效率太低。尤其随着并发用户数量的增加、 数据量的增 加,数据库的整体性能将直线下降。
Oracle对SQL语句进行了概括和抽象,将SQL语句提炼为两部分。一部分是SQL语句的静态部分,也就是SQL语句本身的关键词、所涉及的表名称以及表的列名等。另一部分是SQL语句的动态部分,也就是SQL语句中的字面值(literal value,即有关表里的数据部分,比如 where name='hsj'中,hsj就是SQL语句中的字面值,而where name就是SQL语句中的静态部分)。很明显,整个数据库中所包含的对象数量 是有限 的,而表中所包含的数据则是无限的。而正是这无限的数据导致了SQL语句的千变万化,也就是说,在数据库处理的所有SQL语句中 ,静态部 分可以认为数量是有限的,而动态部分则是无限的。而实际上,动态部分对解析的影响相比于静态部分对解析的影响来说是微乎 其微,也就 是说通常情况下,对于相同的静态部分的SQL语句来说,不同的动态部分所产生的解析结果(执行计划)基本都是一样的(除非 表里的数据 分布极其不均匀,则有可能导致不同的动态部分产生不同的执行计划)。这也就为Oracle提高解析SQL语句的效率提供了方向。
Oracle会将用户提交来的SQL语句都缓存在内存中。每次处理新的一条SQL语句时,都会先在内存中查看是否有相同的SQL语句。如果相同则可以减少最重要的解析工作(也就是生成执行计划),从而节省了大量的CPU资源;反之,如果没有找到相同的SQL语句,则必须重新从头到尾进行完整的解析。这部分存放SQL语句的内存就叫做共享池。当然,shared pool里不仅仅是SQL语句,还包括执行计划、PL/SQL代 码、 PL/SQL程序的机器码、管理shared pool的内存结构、控制信息等内容。
如果SQL语句使用了绑定变量(bind variable),也就是用一个变量来替代SQL中的字面值。那么Oracle在shared pool中查找到相同的SQL语句的概率相对就很大。比如:
select c1 from t1 where c2=1;
select c1 from t1 where c2=2;
select c1 from t1 where c2=3;
这里的1、2、3就是SQL中的字面值。如果写成:
select c1 from t1 where c2=:v1;
这里的v1就是绑定变量,用来替代上面的1、2、3。解析时使用绑定变量,而在具体执行SQL时,才将字面值传入。这时,解析就是比较 SQL 语句的静态部分。前面我们已经知道,静态部分是有限的,很容易就能够缓存在内存里,从而找到相同的SQL语句的概率很高。如果没有使用绑定变量,则就是比较SQL语句的静态部分和动态部分,而动态部分的变化是无限的,因此这样的SQL语句很难被缓存在shared pool 里。 毕竟内存是有限的,不可能把所有的动态部分都缓存在shared pool里。不使用绑定变量导致的直接结果就是,找到相同的SQL语句的 概率较 低,导致必须完整地解析SQL语句,也就导致消耗更多的资源。从这里也可以看出,只有我们使用了绑定变量,才真正遵循了Oracle 引入 shared pool的根本思路,才能够更有效地利用shared pool。
shared pool的大小由初始化参数shared_pool_size决定。Oracle 10g以后可以不用设定该参数,而只需要指定sga_target,从而由 Oracle 自动决定shared pool的大小尺寸。
在一个很高的层次上来看,shared pool可以分为库缓存(library cache)和数据字典缓存(dictionary cache)。Library cache存放了最近执行的SQL语句、存储过程、函数、解析树以及执行计划等。而dictionary cache则存放了在执行SQL语句过程中,所参照的数据 字典的 信息,包括SQL语句所涉及的表名、表的列、权限信息等。dictionary cache里面的信息都是以数据行的形式存放的,而不是以数据 块的形 式存放的,因此也叫做row cache。对于dictionary cache来说,Oracle倾向于将它们一直缓存在shared pool里,不会将它们交换 出内存, 因此我们不用对它们进行过多的关注。而library cache则是shared pool里最重要的部分,也是在shared pool中进进出出最活跃 的部分, 需要我们仔细研究。所以,我们在说到shared pool实际上就可以认为是在指library cache