当前位置: 移动技术网 > 科技>操作系统>Linux > [20191011]通过bash计算sql语句的sql_id.txt

[20191011]通过bash计算sql语句的sql_id.txt

2019年10月12日  | 移动技术网科技  | 我要评论

[20191011]通过bash计算sql语句的sql_id.txt

--//当我知道如何通过bash计算sql语句的full_hash_value ,就很想通过bash编程计算sql_id.当时受限自己能力
--//感觉不好实现.
--//链接: http://blog.itpub.net/267265/viewspace-2142512/=> [20170724]关于sql_id那些事.txt

1.简单介绍sql_id.
--//sql_id的计算是使用md5算法进行哈希,生成一个128位的hash value,其中低32位作为hash value显示,sql_id则取了后64位。
--//实际上sql_id使用32进制表示,hash_value使用10进制表示。

2.环境:
scott@book> @ &r/ver1
port_string                    version        banner
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/linux 2.4.xx            11.2.0.4.0     oracle database 11g enterprise edition release 11.2.0.4.0 - 64bit production

select * from emp where deptno=10;
--//查询可以知道sql_id='557p4j1ggw222'.

scott@book> select sql_text c70,sql_id,hash_value  from v$sql where sql_id = '557p4j1ggw222';
c70                                sql_id        hash_value
---------------------------------- ------------- ----------
select * from emp where deptno=10  557p4j1ggw222 1593706562

scott@book> select name c70,hash_value,full_hash_value from v$db_object_cache where name like '%emp%' and hash_value=1593706562;
c70                               hash_value full_hash_value
--------------------------------- ---------- --------------------------------
select * from emp where deptno=10 1593706562 8bb974871a4f8c88529ea4885efe0842
select * from emp where deptno=10 1593706562 8bb974871a4f8c88529ea4885efe0842

--//注以上是以前的测试!!

3.简单说明如何计算sql_id:
--//简单说明sql_id采用32进制,编码0-9,a-z.没有eilo字符,这些字符容易与数字0,1混淆.
--//编程利用bc obase=32;ibase=16;输出.通过数组base32定位编码.注意bc的输出例子:
$ echo "obase=32;ibase=16; 529ea4885efe0842" | bc| tr -d '\\\r\n'
 05 05 07 21 04 17 01 15 15 28 02 02 02
--//这些数字是10进制数字,前面虽然有0,不能写成${base32[$i]},必须写成{base32[$(( 10#$i ))]}.

$ ./sql_id.sh "select * from emp where deptno=10"
sql_text = select * from emp where deptno=10\0
full_hash_value(16) = 8bb974871a4f8c88529ea4885efe0842
hash_value(10) = 1593706562
sql_id = 557p4j1ggw222

--//再测试一个例子:
scott@test01p> select /*+ 12345678abdef */ sysdate from dual ;
sysdate
-------------------
2019-10-11 22:34:56

scott@test01p> @ dpc '' ''
plan_table_output
-------------------------------------
sql_id  0p0rzks2gkrj6, child number 0
-------------------------------------
select /*+ 12345678abdef */ sysdate from dual

plan hash value: 1388734953

------------------------------------------------------------------
| id  | operation        | name | e-rows | cost (%cpu)| e-time   |
------------------------------------------------------------------
|   0 | select statement |      |        |     2 (100)|          |
|   1 |  fast dual       |      |      1 |     2   (0)| 00:00:01 |
------------------------------------------------------------------
--//sql_id=0p0rzks2gkrj6,主要要找一个sql_id前面是0的情况.注意dual后面有1个空格.

$ ./sql_id.sh "select /*+ 12345678abdef */ sysdate from dual "
sql_text = select /*+ 12345678abdef */ sysdate from dual \0
full_hash_value(16) = ef5a2c4876c9e93d0a82ff9604f95e26
hash_value(10) = 83451430
sql_id(32) = 0p0rzks2gkrj6

--//完成能对上.
scott@test01p> select name c70,hash_value,full_hash_value from v$db_object_cache where  hash_value=83451430;
c70                                           hash_value full_hash_value
--------------------------------------------- ---------- --------------------------------
select /*+ 12345678abdef */ sysdate from dual   83451430 ef5a2c4876c9e93d0a82ff9604f95e26
select /*+ 12345678abdef */ sysdate from dual   83451430 ef5a2c4876c9e93d0a82ff9604f95e26


4.总结:
--//我几乎是一气呵成写成脚本,当我回过头看我写的脚本,感觉原来如此简单.
--//自己真没想到短短几行代码,就能实现这个功能.

5.脚本如下:
$ cat sql_id.sh
#! /bin/bash
# calcucate sql_text of full_hash_value(16),hash_value(10),sql_id(32).
odebug=${odebug:-0}

sql_text=${1}'\0'
v1=$(echo -e -n "$sql_text" | md5sum | sed 's/  -//' | xxd -r -p | od -t x4 |  sed   -n  -e 's/^0\+ //' -e 's/ //gp' | tr 'a-z' 'a-z')
v2=${v1:(-16):16}
v3=${v2:(-8):8}
# v2=$(echo "obase=16;ibase=16; $v1 % 10000000000000000" | bc| tr -d '\\\r\n')
# v3=$(echo "obase=10;ibase=16; $v1 % 100000000" | bc| tr -d '\\\r\n')

if [ $odebug -eq 1 ] ; then
    echo v1=$v1 v2=$v2 v3=$v3
fi

echo "sql_text = $sql_text"
echo "full_hash_value(16) = $v1 "
echo "hash_value(10) = $(( 16#$v3 )) "

base32=($(echo {0..9} {a..z} | tr -d 'eilo'))
res=''
for i in $(echo "obase=32;ibase=16; $v2" | bc| tr -d '\\\r\n')
do
    res=${res}${base32[$(( 10#$i ))]}
done
echo "sql_id(32) = $(printf "%13s" $res | tr ' ' '0')"

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网