欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

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

程序员文章站 2022-10-29 20:42:32
[20191011]通过bash计算sql语句的sql_id.txt--//当我知道如何通过bash计算sql语句的full_hash_value ,就很想通过bash编程计算sql_id.当时受限自己能力--//感觉不好实现.--//链接: http://blog.itpub.net/267265 ......

[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')"