Hard Parse&Soft Parse,hardparse
DDL每次执行都需要进行硬解析。
SQL 解析过程
Oracle对此SQL将进行几个步骤的处理过程:
1、语法检查(syntax check): 检查此sql的拼写是否语法。
2、语义检查(semantic check): 诸如检查sql语句中的访问对象是否存在及该用户是否具备相应的权限。
3、对sql语句进行解析(prase): 利用内部算法对sql进行解析,生成解析树(parse tree)及执行计划(execution plan)。
4、执行sql,返回结果(execute and return)
5个执行步骤:
1:语法分析
2:权限与对象检查
3: 在共享池中检查是否有完全相同的之前完全解析好的. 如果存在,直接跳过4和5,运行Sql, 此时算soft parse.
4:选择执行计划
5:产生执行计划
3的解释:
Oracle将会对传递进来的SQL语句使用HASH函数运算得出HASH值,再与共享池中现有语句的HASH值进行比较看是否一一对应。现有数据库中SQL语句的HASH值我们可以通过访问v$sql、v$sqlarea、v$sqltext等数据字典中的HASH_VALUE列查询得出。
如果SQL语句的HASH值一致,那么ORACLE事实上还需要对SQL语句的语义进行再次检测,以决定是否一致。那么为什么Oracle需要再次对语句文本进行检测呢?不是SQL语句的HASH值已经对应上了?事实上就算是SQL语句的HASH值已经对应上了,并不能说明这两条SQL语句就已经可以共享了。
Dictionary Cache
The data dictionary is a collection of database tables and views containing reference information about the database, its structures, and its users. Oracle accesses the data dictionary frequently during SQL statement parsing. This access is essential to the continuing operation of Oracle.
The data dictionary is accessed so often by Oracle that two special locations in memory are designated to hold dictionary data. One area is called the data dictionary cache, also known as the row cache because it holds data as rows instead of buffers (which hold entire blocks of data). The other area in memory to hold dictionary data is the library cache. All Oracle user processes share these two caches for access to data dictionary information.
Parsing
Parsing is one stage in the processing of a SQL statement. When an application issues a SQL statement, the application makes a parse call to Oracle. During the parse call, Oracle:
-
Checks the statement for syntactic and semantic validity
-
Determines whether the process issuing the statement has privileges to run it
-
Allocates a private SQL area for the statement
Oracle also determines whether there is an existing shared SQL area containing the parsed representation of the statement in the library cache. If so, the user process uses this parsed representation and runs the statement immediately. If not, Oracle generates the parsed representation of the statement, and the user process allocates a shared SQL area for the statement in the library cache and stores its parsed representation there.
Note the difference between an application making a parse call for a SQL statement and Oracle actually parsing the statement. A parse call by theapplication associates a SQL statement with a private SQL area. After a statement has been associated with a private SQL area, it can be run repeatedly without your application making a parse call. A parse operation by Oracle allocates a shared SQL area for a SQL statement. Once a shared SQL area has been allocated for a statement, it can be run repeatedly without being reparsed.
Both parse calls and parsing can be expensive relative to execution, so perform them as seldom as possible.
其中分析分为硬分析(Hard Parse)和软分析(Soft Parse)。一条SQL语句通过语法检查后,Oracle 会先去shared pool 中找是否有相同的sql,如果找着了,就叫软分析,然后执行SQL语句。硬分析主要是检查该sql所涉及到的所有对象是否有效以及权限等关系,然后根据RBO或CBO模式生成执行计划,然后才执行SQL语句。可以看出,硬分析比软分析多了很多动作,而这里面的关键是“在shared pool 中是否有相同的sql”,而这就取决于是否使用绑定变量。另:oracle9i引入了soft soft parse,先到pga中的session cursor cache list列表中去查找(session cursor cache list的长度是由session_cache_cursor参数决定的),如果没有找到这条sql,这时候才去检查shard_pool.对于Oltp系统,很多时候硬分析的代价比执行还要高,这个我们可以通过10046事件跟踪得知。(2)共享池中SQL语句数量太多,重用性极低,加速了SQL语句的老化,导致共享池碎片过多。共享池中不同的SQL语句数量巨大,根据LRU原则,一些语句逐渐老化,最终被清理出共享池;这样就导致shared_pool_size 里面命中率下降,共享池碎片增多,可用内存空间不足。而为了维护共享池内部结构,需要使用latch,一种内部生命周期很短的lock,这将使用大量的cpu 资源,使得性能急剧下降。不使用绑定变量违背了oracle 的shared pool 的设计的原则,违背了这个设计用来共享的思想。2、怎么查看没有使用绑定变量select * from v$sql or v$sqlarea 查看是否有很多类似的语句,除了变量不一样,其他的都一样3、如何使用绑定变量?编写java 程序时,我们习惯都是定义JAVA 的程序变量,放入SQL 语句中,如String v_id = 'xxxxx';String v_sql = 'select name from table_a where id = ' + v_id ; 以上代码,看起来是使用了变量v_id ,但这却是java 的程序变量,而不是oracle 的绑定变量,语句传递到数据库后,此java 的程序变量已经被替换成具体的常量值,变成:select * from table_a where name = 'xxxxx' ;假定这个语句第一次执行,会进行硬分析。后来,同一段java 代码中v_id 值发现变化(v_id = 'yyyyyy'),数据库又接收到这样的语句:select * from table_a where name = 'yyyyyy' ;ORACLE 并不认为以上两条语句是相同的语句,因此对第二条语句会又做一次硬分析。这两条语句的执行计划可是一样的!其实,只需将以上java 代码改成以下这样,就使用了oracle 的绑定变量:String v_id = 'xxxxx';String v_sql = 'select name from table_a where id = ? '; //嵌入绑定变量stmt = con.prepareStatement( v_sql );stmt.setString(1, v_id ); //为绑定变量赋值stmt.executeQuery()......余下全文>>
变量绑定 是指在sql语句的条件中使用变量而不是常量。比如shared pool里有两条sql语句,
select * from tab1 where col1=1;
select * from tab1 where col1=2;
对oracle数据库来说,这是两条完全不同的SQL,对这两条语句都需要进行hard parse。因为oracle会根据sql语句的文本去计算每个字符在内存里的hash值,因此虽然上述两条SQL只有一个字符不一样,oracle根据hash算法在内存中得到的hash地址就不一样,所以oracle就会认为这是两条完全不同的语句。而如果将上述SQL改写成select * from tab1 where col1=:var1;,然后通过对变量var1的赋值去查询,那么oracle对这条语句第一次会进行hard parse,以后就只进行soft parse。假设某条语句被重复执行了几十万次,那么使用bind var带来的好处是巨大的。一个应用程序如果bind var使用不充分,那么几乎一定会伴随着严重的性能问题。
绑定变量是相对文本变量来讲的,所谓文本变量是指在SQL直接书写查询条件,这样的SQL在不同条件下需要反复解析,绑定变量是指使用变量来代替直接书写条件,查询bind value在运行时传递,然后绑定执行。优点是减少硬解析,降低CPU的争用,节省shared_pool ;缺点是不能使用histogram,sql优化比较困难