ITPub博客

首页 > Linux操作系统 > Linux操作系统 > Compute hash_value based on the given sql_id

Compute hash_value based on the given sql_id

原创 Linux操作系统 作者:小靓妞 时间:2011-05-23 11:31:27 0 删除 编辑
…Or in other words, how to translate SQL_ID to a hash value :)

I once wrote a script. to demo this in my Advanced Oracle Troubleshooting class.

Check this, I’ll run a query and then check what is its SQL_ID and HASH_VALUE from V$SQL:

SQL> select * from dual;

D
-
X

SQL> select sql_id, hash_value from v$sql
  2  where sql_text = 'select * from dual';

SQL_ID        HASH_VALUE
------------- ----------
a5ks9fhw2v9s1  942515969


So, V$SQL reports the real SQL_ID and HASH_VALUE above.

Now lets use my i2h.sql script. ( i2h stands for: sql Id to Hash value ):

SQL> @i2h a5ks9fhw2v9s1

SQL_ID        HASH_VALUE
------------- ----------
a5ks9fhw2v9s1  942515969

It works! :)

The code itself is simple (and you can download the script. from here)

select
    lower(trim('&1')) sql_id
  , trunc(mod(sum((instr('0123456789abcdfghjkmnpqrstuvwxyz',substr(lower(trim('&1')),level,1))-1)
                       *power(32,length(trim('&1'))-level)),power(2,32))) hash_value
from
    dual
connect by
    level <= length(trim('&1'))
/

Basically all I do is take the SQL ID, interpret it as a 13 character base-32 encoded number and then take only the lowest 4 bytes worth of information (4 bytes in base-256) out of that number and that’s the hash value.

So, SQL_ID is just another hash value of the library cache object name.

Actually, since 10g the full story goes like this:

1) Oracle hashes the library cache object name with MD5, producing a 128 bit hash value
2) Oracle takes last 64 bits of the MD5 hash and this will be the SQL_ID (but it’s shown in base-32 for brevity rather than in hex or as a regular number)
3) Oracle takes last 32 bits of the MD5 hash and this will be the hash value (as seen in v$sql.hash_value).

The hashing approach changed between 9i and 10g, so in 10g+ you have a v$sql.old_hash_value column to represent the before-10g hash algorithm. This can be useful when comparing plans & statistics when testing migration from 9i to 10g.

Library cache is physically still organized by the hash value, not SQL_ID. When you query views like X$KGLOB or V$SQL by SQL_ID, then Oracle just extracts the low 4 bytes from the SQL_ID and still does the lookup by hash value.

So, despite only SQL_ID showing up everywhere in Enterprise Manager and newest Oracle views and scripts, the hash_value isn’t going anywhere, it’s a fundamental building block of the library cache hash table.

Tanel,

In 11g, you can do this:

SQL> select dbms_utility.SQLID_TO_SQLHASH(’btxdhy7gkbwjk’) hash_value FROM DUAL;

HASH_VALUE
———-
3743806002

CREATE OR REPLACE FUNCTION sqltext_to_sqlid(sql_text IN clob)
RETURN VARCHAR2
AS
    PRAGMA AUTONOMOUS_TRANSACTION;
    v_sqlset_name VARCHAR2(30);
    v_sqlset_cursor DBMS_SQLTUNE.SQLSET_CURSOR;
    v_sqlid VARCHAR2(13);
    v_sql_text CLOB;
    NUL CONSTANT varchar2(1) := CHR(0);
BEGIN
    if ( NUL = SUBSTR(sql_text, LENGTH(sql_text), 1) )
    then
        v_sql_text := sql_text;
    else
        v_sql_text := sql_text || NUL;
    end if;
 
    -- Create a semi-random name for the SQL SET
    v_sqlset_name := 'SQLTEXT_TO_SQLID_' || DBMS_RANDOM.STRING('U', 13);
 
    -- Create the SQL Set
    DBMS_SQLTUNE.CREATE_SQLSET (sqlset_name => v_sqlset_name);
 
    -- Populate the SQL Set
    OPEN v_sqlset_cursor FOR
        SELECT SQLSET_ROW(null, 0, v_sql_text, null, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0, 0, null, 0, null, null)
        FROM DUAL;
    DBMS_SQLTUNE.LOAD_SQLSET(v_sqlset_name, v_sqlset_cursor);
 
    SELECT sql_id INTO v_sqlid FROM TABLE(DBMS_SQLTUNE.SELECT_SQLSET(v_sqlset_name));
 
    -- Drop the SQL Set
    DBMS_SQLTUNE.DROP_SQLSET (sqlset_name => v_sqlset_name);
 
    RETURN v_sqlid;
END;
/
SHOW ERRORS

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/24387280/viewspace-696032/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 格式化输出
下一篇: Data block address
请登录后发表评论 登录
全部评论

注册时间:2010-12-13

  • 博文量
    37
  • 访问量
    38934