OracleでSQLステートメントを実行すると、ハッシュ値がそのSQLステートメントに割り当てられ、ライブラリキャッシュに格納されます。したがって、後で別のユーザーが同じクエリを要求すると、Oracleはハッシュ値を見つけて同じ実行プランを実行します。しかし、ハッシュ値について疑問が1つあります。つまり、ハッシュ値がどのように生成されるか?、つまり、Oracleサーバーがいくつかのアルゴリズムを使用するのか、SQL文字列を数値に変換するだけなのかを意味します。
以来、私はそれが書かれているPro 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)
質問のテキストでは、sql_id
および/またはhash_value
を説明しているようです。これはSQLステートメントのテキストのハッシュであり、特定のSQLステートメントが共有プールにすでに存在するかどうかを判断するためにOracleが使用するものです。ただし、例で示しているのは、SQLステートメント用に生成されたプランのハッシュであるplan_hash_value
です。潜在的に、2つの間に多対多の関係があります。 1つのSQLステートメント(sql_id
/hash_value
)は複数の異なるプラン(plan_hash_value
)を持つことができ、複数の異なるSQLステートメントは同じプランを共有できます。
したがって、たとえば、EMP
テーブルから特定の行をクエリする2つの異なる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
を見ると、2つの異なるsql_id
値とhash_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
Oracleは、これら2つのステートメントが異なるsql_id
およびhash_value
ハッシュを持つ異なるクエリであることを認識しています。しかし、どちらもたまたま同じ計画を生成するため、最終的には同じplan_hash_value
になります。
行300col BEGIN_INTERVAL_TIME for a30 select a.snap_id、a.begin_interval_time、b.plan_hash_value from dba_hist_snapshot a、dba_hist_sqlstat b where a.snap_id = b.snap_id and b.sql_id = '&sql_id' order by 1;
この場合、あなたはその本が間違っていることを証明したと思います。そして理論的には、ランダムに大文字の文字列ではなく、概念的なSQLステートメントをハッシュで識別させる方が良いようです...そして、ハッシュを生成するときにコメントも無視されることを願っています。 ;-)