sql语句的哈希值

sql语句的哈希值,sql,oracle,sql-execution-plan,Sql,Oracle,Sql Execution Plan,当我们在Oracle中执行任何sql语句时,一个哈希值被分配给该sql语句并存储到库缓存中。因此,稍后,如果另一个用户请求相同的查询,那么Oracle会找到散列值并执行相同的执行计划。但是,我对散列值有一个疑问。我的意思是,散列值是如何生成的?我的意思是,Oracle server是使用一些算法,还是仅仅将sql字符串转换成一些数值 因为,我在读一本支持Oracle SQL的书,书上写着 select * from employees where department_id = 60; SEL

当我们在Oracle中执行任何sql语句时,一个哈希值被分配给该sql语句并存储到库缓存中。因此,稍后,如果另一个用户请求相同的查询,那么Oracle会找到散列值并执行相同的执行计划。但是,我对散列值有一个疑问。我的意思是,散列值是如何生成的?我的意思是,Oracle server是使用一些算法,还是仅仅将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)

我想说的是,在这种情况下,你只是证明了这本书是错的。从理论上讲,让散列识别概念性SQL语句似乎比用随机大写的字符串更好。。。我希望在生成哈希时也能忽略注释-

在问题文本中,您似乎在描述sql\u id和/或哈希值。这是SQL语句文本的散列,Oracle使用它来确定共享池中是否已经存在特定的SQL语句。但是,您在示例中显示的是plan_hash_值,它是为SQL语句生成的计划的哈希值。两者之间存在着潜在的多对多关系。单个SQL语句SQL\u id/哈希值可以有多个不同的计划计划\u哈希值,并且多个不同的SQL语句可以共享同一个计划

因此,例如,如果我编写两个不同的SQL语句来查询EMP表中的特定行,我将得到相同的plan\u hash\u值

但是,如果我查看v$sql,我将看到生成了两个不同的sql\u id和hash\u值

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认识到这两条语句是具有不同sql\u id和哈希值哈希的不同查询。但它们都生成了相同的计划,因此它们最终得到了相同的计划散列值。

设置第300行 col开始\u间隔\u a30的时间
从dba_hist_快照a、dba_hist_sqlstat b中选择a.snap_id、a.begin_interval_time、b.plan_hash_值,其中a.snap_id=b.snap_id和b.sql_id='&sql_id'按1顺序排列

但是,这本书通过使用select sql_text、sql_id、child_number、hash_值、address和v$sql中的执行来证明,其中uppersql_text类似于“%EMPLOYEES%”;。这意味着,两条sql语句都应该具有不同的哈希值。而且,根据Oracle的说法,如果库缓存中没有哈希值,它将重新解析并为sql语句生成新的计划?不是吗?@jWeavers-对。我更新了示例,除了显示sql\u id外,还显示了哈希值。哈希值有点过时,计划id更容易用作标识符,而不是使用地址和哈希值。较新的数据字典表(如AWR表)使用sql\u id而不是哈希值。
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