2013-04-15 56 views
4

當我們在Oracle中執行任何sql語句時,散列值正被分配給該sql語句並存儲到庫緩存中。所以,以後,如果另一個用戶請求相同的查詢,那麼Oracle將查找散列值並執行相同的執行計劃。但是,我對散列值有一個疑問。我的意思是,哈希值如何生成?,我的意思是,Oracle服務器是否使用某些算法,或者他們只是將sql字符串轉換爲某個數字值。sql語句的散列值

,因爲我讀專業的Oracle SQL書,在其上撰文指出,

select * from employees where department_id = 60; 

SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID = 60; 

select /* a_comment */ * from employees where department_id = 60; 

將返回不同的散列值,因爲SQL語句執行時,那麼Oracle首先將字符串轉換爲哈希值。但是,當我嘗試這個,然後它返回相同的哈希值。

SQL> select * from boats where bid=10; 

no rows selected 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2799518614 

------------------------------------------------------------------------------------- 
| Id | Operation     | Name | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |  |  1 | 16 |  1 (0)| 00:00:01 | 
| 1 | TABLE ACCESS BY INDEX ROWID| BOATS |  1 | 16 |  1 (0)| 00:00:01 | 
|* 2 | INDEX UNIQUE SCAN   | B_PK |  1 |  |  0 (0)| 00:00:01 | 
------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - access("BID"=10) 

SQL> SELECT * FROM BOATS WHERE BID=10; 

no rows selected 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2799518614 

------------------------------------------------------------------------------------- 
| Id | Operation     | Name | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |  |  1 | 16 |  1 (0)| 00:00:01 | 
| 1 | TABLE ACCESS BY INDEX ROWID| BOATS |  1 | 16 |  1 (0)| 00:00:01 | 
|* 2 | INDEX UNIQUE SCAN   | B_PK |  1 |  |  0 (0)| 00:00:01 | 
------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - access("BID"=10) 

回答

6

在您的問題的文本中,您似乎描述了sql_id和/或hash_value。這是SQL語句文本的哈希值,也是Oracle用來確定共享池中是否已存在特定SQL語句的內容。但是,在您的示例中顯示的是plan_hash_value,它是爲SQL語句生成的計劃的哈希。這兩者之間可能存在多對多的關係。單個SQL語句(sql_id/hash_value)可以有多個不同的計劃(plan_hash_value),並且多個不同的SQL語句可以共享相同的計劃。例如,如果我編寫查詢EMP表中特定行的兩條不同SQL語句,我將得到相同的plan_hash_value

SQL> set autotrace traceonly; 
SQL> select * from emp where ename = 'BOB'; 

no rows selected 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3956160932 

-------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  1 | 39 |  3 (0)| 00:00:01 | 
|* 1 | TABLE ACCESS FULL| EMP |  1 | 39 |  3 (0)| 00:00:01 | 
-------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("ENAME"='BOB') 


SQL> ed 
Wrote file afiedt.buf 

    1* select * FROM emp WHERE ename = 'BOB' 
SQL>/

no rows selected 


Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3956160932 

-------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  1 | 39 |  3 (0)| 00:00:01 | 
|* 1 | TABLE ACCESS FULL| EMP |  1 | 39 |  3 (0)| 00:00:01 | 
-------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("ENAME"='BOB') 

如果我看在v$sql,但是,我會看到,產生兩種不同的sql_idhash_value

SQL> set autotrace off; 
SQL> ed 
Wrote file afiedt.buf 

    1 select sql_id, sql_text, hash_value, plan_hash_value 
    2 from v$sql 
    3 where sql_text like 'select%BOB%' 
    4* and length(sql_text) < 50 
SQL>/

SQL_ID  SQL_TEXT         HASH_VALUE PLAN_HASH_VALUE 
------------- ---------------------------------------- ---------- --------------- 
161v96c0v9c0n select * FROM emp WHERE ename = 'BOB'  28618772  3956160932 
cvs1krtgzfr78 select * from emp where ename = 'BOB' 1610046696  3956160932 

甲骨文認識到,這兩個語句是具有不同sql_idhash_value哈希值不同的查詢。但他們都碰巧產生了相同的計劃,所以他們最後得到了相同的plan_hash_value

+0

這意味着,這兩個sql語句應該有不同的散列值。而且,根據Oracle的說法,如果散列值在庫緩存中不可用,它將重新解析併爲sql語句生成新的計劃?不是嗎? – Ravi

+0

@jWeavers - 正確。我更新了示例以顯示'sql_id'之外的'hash_value'。 'hash_value'有點老派,'plan_id'更容易用作標識符而不是使用'address'和'hash_value'。較新的數據字典表(如AWR表)使用'sql_id'而不是'hash_value'。 –

0

我會說,你只是證明這本書在這種情況下是錯誤的。理論上,使用哈希標識概念性SQL語句而不是隨機大小的字符串似乎更好。我希望在生成哈希時也會忽略這些註釋。 ;-)

+0

但是,該書通過使用'select sql_text,sql_id,child_number,hash_value,address,v $ sql where upper(sql_text)''%EMPLOYEES%';''執行。 – Ravi

0

組線300 COL BEGIN_INTERVAL_TIME爲A30 選擇a.snap_id,a.begin_interval_time,從DBA_HIST_SNAPSHOT一個b.plan_hash_value,dba_hist_sqlstat b其中a.snap_id = b.snap_id和b.sql_id = '& SQL_ID',以便通過1;