Oracle命准率及优化配置(二)

2014-11-24 11:46:51 · 作者: · 浏览: 3

2) 语义检查,实现数据字典的查找,以验证是否符合表和列的定义,类型是否正确;
3) (如果是CBO优化模式,关于CBO,请看后面Oracle的优化器一章)收集参考对象的统计;
4) 在所要求的对象上获取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义;
5) 检查用户的权限是否足够;
6) 从许多可能的执行路径中选择此语句最佳的执行计划;
7) 将它装入共享SQL区;
8) 生成语句的编译版本(P-CODE)。
解析是一个昂贵的操作,因为解析过程中需要消耗许多资源,而且费时,正因为如此,Oracle创造了共享池的概念,共享池会自动将解析过的SQL缓存起来,以后碰到相同的SQL,就不用再解析了,这样可以大大提高SQL的执行速度。

3.2.3.3 缓存SQL的原理
ORACLE 执行SQL语句时,先将SQL语句的字串通过一个hash算法得出一个hash值,然后检查共享池中是否已存在这个哈希值,若有就用已缓存的执行计划来执 行这个语句(即缓存命中,后面我们会提到共享池的命中率,就是这个概念),若没有(即缓存缺失)则需进行解析。
由于Oracle是通过SQL字符的hash值来判断是否为相同的SQL语句,因此,如果你的SQL有一点小小的变换,在Oracle看来,就是另外一个SQL了,会对它进行重新解析。
例如:
select id, name from members where id = 1403
select id, name From members where id = 1403
select name, id from members where id = 1403
这三条SQL在Oracle看来就是三条不同的SQL。

3.2.3.4 绑定变量
在大部分时候,sql语句里有一些经常会变化的值。例如:
select id, name from members where id = 1207
select id, name from members where id = 1208
select id, name from members where id = 1209
前面说过了,这样的SQL其实是三条不同的SQL,因为它们的字符明显不一样。那我们该怎么样才能让它们成为同一条SQL呢?可以通过绑定变量来实现。
下面是一条含绑定变量的sql 语句:
select id, name from members where id = :member_id
这样不管member_id如何变化,Oracle都会认为这条SQL是同一条,就可以节省解析的成本了。
那么,在java开发中,怎么使用绑定变量呢?注意,不要认为下面的代码是在使用绑定变量:
Statement stmt=conn.createStatement();
String member_id=member.id;
String sql="select id,name from members where id ="+member_id;
stmt.executeQuery(sql);
上面的例子里,当member.id的值为1207时,我们传给stmt的SQL实际上是:
select id, name from members where id = 1207
当member.id的值为1208时,就是:
select id, name from members where id = 1208
它们在Oracle看来仍然是不同的SQL。
其实,在java中使用绑定变量非常简单,只需要使用PreparedStatement对象就可以了。如下:
String sql="select id,name from members where id = ";
PreparedStatement pstmt=conn.createStatement(sql);
pstmt.setString(1,member.id);//将member.id传给第一个问号。
这样,PreparedStatement会自动把这条SQL在传给Oracle时转化为类似下面的SQL:
select id, name from members where id = :member_id
这样就实现了绑定变量,它只需解析一次,不管member.id如何变化,都不用再做解析了。
我们使用的Hibernate,内部就是使用PreparedStatement来处理的,因此,我们不需要为使用绑定变量做任何事情,Hibernate已经帮我们做好了。

3.2.3.5 查看共享池
通过下面的命令查看共享池内存的大小:
show parameter shared_pool_size;
结果见下图:

3.2.3.6 修改共享池
通过下面的命令可以修改共享池内存的大小:
alter system set shared_pool_size=90M scope=both;



shared_pool_size是一个动态参数,可以在运行时修改,因此这里的scope设置为both,新的内存大小马上生效,并且还将修改保存在Oracle的启动文件里。

3.2.3.7 查看共享池命中率
共享池命中率可以反映出SQL重复使用率的高低,命中率越高,说明SQL重复使用率越高,也就是节省的SQL解析时间越多,反映在系统上就是查询数据越快。
可以通过以下命令查看命中率:
select sum(pinhits) / sum(pins) * 100 "看命中率咯" from v$librarycache;
结果如下图:



如果命中率低于95%,则要考虑调整共享池大小。我们知道,如果没有在程序里使用绑定变量,那么就算共享池再大,也不会有什么好的效果,反而会有副作用。因此,更重要的事情是把使用最多的SQL改成绑定变量,你将会看到明显的效果。

3.2.4 数据缓冲区
如 果每次执行一个操作时,Oracle都必须从磁盘读取所有数据块并在改变它之后又必须把每一块写入磁盘,显然效率会非常低。数据缓冲区存放需要经常访问的 数据,供所有用户使用。修改数据时,首先从数据文件中取出数据,存储在数据缓冲区中,修改/插入数据也存储在缓冲区中,commit或DBWR(下面有详 细介绍)进程的其他条件引发时,数据被写入数据文件。数据缓冲区的大小是可以动态调整的,但是不能超过sga_max_size的限制。
3.2.4.1 查看数据缓冲区
通过下面的命令查看数据缓冲区内存的大小:
show parameter db_cache_size;
结果见下图:


3.2.4.2 修改数据缓冲区
通过下面的命令可以修改数据缓冲区内存的大小:
alter system set db_cache_size=50M scope=both;
db_cache_size是一个动态参数,可以在运行时修改,因此这里的scope设置为both,新的内存大小马上生效,并且还将修改保存在Oracle的启动文件里。

3.2.4.3 查看数据缓冲区命中率
数据缓冲区也有一个命中率的概念,一般要求命中率在90%或95%以上,如果你的命中率过低,说明你的数据库效率很低,需要调整数据缓冲区的大小。
可以通过下面的命令查看命中率:
select (1 - ((physical.value - direct.value - lobs.value) / logical.value)) * 100 "命中率"
from v$sysstat physical,
v$sysstat direct,
v$sysstat lobs