Oracle 数据库有一个高速缓存区,记录了所有使用过的sql,不同的注释,不同的大小写,都将分为不同的sql。但是对于使用变量的sql则会只记录一次。

当Oracle第一次收到sql时需要对其进行一系列解析,称为硬解析,过程比较复杂这里不细说,然后把sql保存在高速缓存区,下一次再使用此sql时,就从缓存区直接加载sql相关信息,称为软解析,不再进行硬解析过程速度比第一次使用该语句要快。

这样就保证了sql执行的速度,当然,第一次执行会慢一些。

比如下面3条sql语句。

select * from books where id=1;

select * from books where id=2;

select * from books where id=3;

执行过之后,Oracle缓存区就会记录这3条语句。我们可以使用下面语句来查看

select sql_text from v$sql where sql_text like '%books%'

可以看到是3条sql语句,每条语句都会执行一次硬解析,假如一次硬解析时间为10,一次软解析时间为1,那么上述3条sql的执行时间将会是3*10=30.

如果我们只使用一条sql的话,例如:

select * from books where id=:0;

:0 是一个变量,在执行的时候可以改变为对应的值,那么当执行上述3条sql时只有第一次执行了硬解析,后面两次都会执行软解析,所耗时间为10+1+1=12.速度大大提高。

假如在java中我们写sql语句使用拼接的方式的话,如下

String sql = "select * from books where id="+id;

那么每换一个id,就会在Oracle缓存区增加一条sql记录。如果id很多,那么缓存区就会变得非常庞大,最重要的是,每次都要进行硬解析。假如执行10,000次,所耗时间就是100,000。

但如果这样写

String sql = "select * from books where id=?";

在oracle中就会转换成:

select * from books where id=:0;

只有第一次执行时进行硬解析,以后都将进行软解析,那么所执行10,000次所花费的时间只有10+9,999=10,009。速度提高了将近10倍,而事实上我这里给的数字只是举例,实际中这个差距更大。

所以我们在用Java编写sql时,使用PreparedStatement并不是只有屏蔽sql注入这一种特效,还有优化sql执行的特效