Oracle SQL的硬解析、軟解析、軟軟解析


Oracle中每條sql在執行前都要解析,解析分為硬解析、軟解析、軟軟解析。

Oracle會緩存DML語句,相同的DML語句會進行軟解析。但不會緩存DDL語句,所以DDL每次都做硬解析。硬解析是一個很耗時的操作,所以應用程序內部很少執行執行DDL。DDL一般在部署前執行。

 

sql語句執行步驟:

1.語法檢查(syntax check)
2.語義檢查(symantic check): 對象是否存在,是否有權限。
3.sql解析(parse): 利用內部算法對sql進行解析,生成解析樹及執行計划。
4.執行sql,返回結果(execute and return)

 

首先了解一下sql解析時用到的內存結構——shared pool:
shared pool是一塊內存池,里邊又被分成了很多小的區塊,每個塊有他們的作用
1.free (空閑)

2.library cache (庫緩存,緩存sql語句以及sql所對應的執行計划)
3.row cache (字典緩存——庫里有多少表,多少用戶,多少個列,列的名字,列的數據類型,每個表多大等等都屬於數據庫自身信息。)

 

一個sql 語句,進入到數據庫后,server process 會拿着sql語句到shared pool中的library cache 里邊去找,看sql語句以前是否有執行過。也就是在library cache 里面看有沒有這條sql語句以及sql語句所對應的執行計划。(此過程是通過對傳遞進來的SQL語句使用HASH函數運算得出HASH值,與共享池中現有語句的HASH值進行比較看是否一一對應。現有數據庫中SQL語句的HASH值我們可以通過訪問v$sql、v$sqlarea、v$sqltext等數據字典中的HASH_VALUE列查詢得出。)


Parse主要分為三種:

1.Hard Parse (硬解析)
2.Soft Parse (軟解析)
3.Soft Soft Parse

 

Hard Parse:對提交的Sql完全重新從頭進行解析(當在shared Pool中找不到時候將會進行此操作),總共有一下5個執行步驟:
1.語法分析
2.權限與對象檢查
3.在共享池中檢查是否有完全相同的之前完全解析好的. 如果存在,直接跳過4和5,運行Sql, 此時算soft parse.
4.選擇執行計划
5.產生執行計划

 

注:創建解析樹、生成執行計划對於sql的執行來說是開銷昂貴的動作,所以,應當極力避免硬解析,盡量使用軟解析。這就是在很多項目中,倡導開發設計人員對功能相同的代碼要努力保持代碼的一致性,以及要在程序中多使用綁定變量的原因。


Soft Parse: 在Shared Pool中找到了與之完全相同的Sql解析好的結果后會跳過Hard Parse中的后面的兩個步驟。

 

Soft Soft Parse:當設置了session_cursor_cache這個參數之后,Cursor被直接Cache在當前Session的PGA中的,在解析的時候只需要對其語法分析、權限對象分析之后就可以轉到PGA中查找了,如果發現完全相同的Cursor,就可以直接去取結果了,也就就是實現了 Soft Soft Parse.

 

如果SQL語句的HASH值一致,那么ORACLE事實上還需要對SQL語句的語義進行再次檢測,以決定是否一致。那么為什么Oracle需要再次對語句文本進行檢測呢?不是SQL語句的HASH值已經對應上了?事實上就算是SQL語句的HASH值已經對應上了,並不能說明這兩條SQL語句就已經可以共享了。
 
例如:假如用戶SYS有自己的一張表EMP,他要執行查詢語句:select * from emp; 用戶SYSTEM也有一張EMP表,同樣要查詢select * from emp;這樣他們兩條語句在文本上是一模一樣的,他們的HASH值也會一樣,但是由於涉及到查詢的相關表不一樣,他們事實上是無法共享的. 

 

下面我們來看實驗:

數據庫版本:Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

 

create table test as select * from user_objects where 1<>1;

begin
  dbms_stats.gather_table_stats('TOUGH','TEST');
end;  

alter system flush shared_pool;

 

  • 硬解析

select * from test where object_id=20;
select * from test where object_id=30;

 

  • 軟解析

select * from test where object_id=40;
select * from test where object_id=40;

select * from test where object_id=50;
select * from test where object_id=50;
select * from test where object_id=50;
select * from test where object_id=50;

 

  • 軟軟解析

begin
  for i in 1 .. 4 loop
   
execute immediate 'select * from test where object_id=:i'
      using i;

  end loop;
end;

 

查看解析情況:

select sql_text, s.parse_calls, loads, executions
from   v$sql s
where  sql_text like 'select * from test where object_id%'
order  by 1, 2, 3, 4;

 

SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
select * from test where object_id=20  1 1 1
select * from test where object_id=30  1 1 1
select * from test where object_id=40  2 1 2
select * from test where object_id=50  4 1 4
select * from test where object_id=:i 1 1 4

 

object_id=20 -> 因為沒有緩存此條sql,所以硬解析

object_id=30 -> 因為沒有緩存此條sql,所以硬解析

object_id=40 -> 因為第一次執行已經緩存此條sql,所以軟解析次數為2,硬解析次數為1

object_id=50 -> 因為第一次執行已經緩存此條sql,所以軟解析次數為4,硬解析次數為1

object_id=:i -> 用了動態綁定變量,盡管執行了4次,但只做了一次硬解析和一次軟解析

 

字段解釋:

PARSE_CALLS - 解析的次數
LOADS - 硬解析的次數
EXECUTIONS - 執行的次數

 


 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM