Oracle如何根据SQL_TEXT生成SQL_ID
本文纯属八卦,基本没有任何实用价值。Oracle总是都会通过SQL_ID来标志一个唯一的SQL。SQL_ID与SQL_TEXT一一对应。如果两个SQL文本有任何不同,包括空格等任何不可见字符,都会导致SQL_ID不同。本文八卦的内容是:Oracle如何根据SQL_TEXT内容散列成一个13位
本文纯属八卦,基本没有任何实用价值。Oracle总是都会通过SQL_ID来标志一个唯一的SQL。SQL_ID与SQL_TEXT一一对应。如果两个SQL文本有任何不同,包括空格等任何不可见字符,都会导致SQL_ID不同。本文八卦的内容是:Oracle如何根据SQL_TEXT内容散列成一个13位的字符串。为什么这个字符串会是13位?为什么这个字符经常以数字开头?
本文参考TANEL PODER和Slavik的两篇介绍(1,2),详细介绍转换原理,顺便给出PHP/Perl实现代码。
0. 概述
Oracle先计算SQL_TEXT的md5散列值;取散列值的低64位(bits),每次取5位(最后一次4位),使用Base32将其依次转换成可见字符,就是你最终看到的SQL_ID。原理就是这样。
不过实际转换过程中有一些要注意的事项:
(a) Oracle在计算md5散列时,会在SQL_TEXT末尾加一个不可见字符\0,AWR报表中经常有这样的SQL_TEXT
(b) 注意little-endian的问题
(c) Base32转码的可见字符为0123456789abcdfghjkmnpqrstuvwxyz
(d) 编写程序的时候需要注意大数精度的问题,本文中Perl/PHP程序都使用了数学大数处理函数
1. 详细过程
1.1 示例
我们考虑如下给定SQL:
select sysdate from dual;
在Oracle 10g中执行并查询v$SQL,可以看到这个SQL的SQL_ID是
SQL > select sql_id, hash_value from v$sql where sql_text = 'select sysdate from dual'; SQL_ID HASH_VALUE ------------- ---------- h35uxf5uhmm1 2343063137
1.2 SQL_ID计算的详细过程
1.2.1 散列值的计算
将SQL_TEXT末尾加上一个空字符\0,然后进行md5散列:
use Digest::MD5 qw(md5 md5_hex md5_base64); $stmt = "select sysdate from dual\0"; $hash = md5 $stmt;
select sysdate from dual\0的MD5散列值为abd4dbb3096b15f1ebba0c78614ea88b,共128位(明明是32位,怎么说128位?),取低64位为:"ebba0c78 614ea88b"。
md5散列的字节码如下(128位):
|10101011|11010100|11011011|10110011| |00001001|01101011|00010101|11110001| |11101011|10111010|00001100|01111000| |01100001|01001110|10101000|10001011|
1.2.2 取低64位整数
md5散列值的低64位为:
|11101011|10111010|00001100|01111000| |01100001|01001110|10101000|10001011|
分为两部分,高32位和低32位,分别为:ebba0c78 614ea88b,对应二进制字节流为:|11101011|10111010|00001100|01111000|和|01100001|01001110|10101000|10001011|。可以直接使用unpack函数将散列值解开。这里需要注意,取模运算为整数运算,而我这里的环境是x86_64 little-endian,所以取模运算时对应的整数字节序(人读取的时候):
|01111000|00001100|10111010|11101011| |10001011|10101000|01001110|01100001|
perl代码:
my($a,$b,$msb,$lsb) = unpack("V*",$hash);
1.2.3 Base32转换为可见字符
Oracle使用了Base32将字节流转换为可见字符。
一个Base32字符对应字节流的5位(bits),这里总计64位,所以是64/5,一共13个字符。其中12个字符为5位,有一个字符总是四位(SQL_ID的第一位)。
我们来看本案例的字节流,每五位转换为一个Base32的编码,取最后5为00001(十进制1),对应Base32编码为1;取倒数第二个五位10011(十进制19),取倒数第三个五位为010011(十进制19)...
Oracle使用的Base32对应编码字符为:
abcdfghjkmnpqrstuvwxyz
编码和字符对应关系
编码 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 字符 0 1 2 3 4 5 6 7 8 9 a b c d f g ----------------------------------------------------- 编码 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 字符 h j k m n p q r s t u v w x y z
所以,上面编码1、19、19对应的字符为1、m、m,这也正是SQL_ID对应的最后三位:
h35uxf5uhmm1
3 代码片段
3P程序代码如下:
3.1 Perl
#!/usr/bin/perl -w use Digest::MD5 qw(md5 md5_hex md5_base64); use Math::BigInt; my $stmt = "select sysdate from dual\0"; my $hash = md5 $stmt; my($a,$b,$msb,$lsb) = unpack("V*",$hash); my $sqln = $msb*(2**32)+$lsb; my $stop = log($sqln) / log(32) + 1; my $sqlid = ''; my $charbase32 = '0123456789abcdfghjkmnpqrstuvwxyz'; my @chars = split '', $charbase32; for($i=0; $i new($sqln); my $seq = $x->bdiv(32**$i)->bmod(32); $sqlid = $chars[$seq].$sqlid; } print "SQL is:\n $stmt \nSQL_ID is\n $sqlid\n";
3.2 PHP
function stmt_2_sqlid($stmt){ $h = md5($stmt."\0",TRUE); $un = unpack("V*",$h); $msb = $un[3] + 0; if($msb <h4 id="Python">3.3 Python</h4> <p>参考:Oracle sql_id and hash value</p> <h3 id="最后">4. 最后</h3> <p>一个略有趣的事实,SQL_ID的第一位经常会是数字。这是因为是64位(bits),按照5位一个字符划分,最后一个字符总是只有4位,范围总是0到15,对应字符为0123456789abcdfg,也就是说超过50%的SQL_ID都是以数字开头的。</p> <p>好了,八卦结束。</p> <p class="copyright"> 原文地址:Oracle如何根据SQL_TEXT生成SQL_ID, 感谢原作者分享。 </p>

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

解決 Oracle 游標關閉問題的方法包括:使用 CLOSE 語句顯式關閉游標。在 FOR UPDATE 子句中聲明游標,使其在作用域結束後自動關閉。在 USING 子句中聲明游標,使其在關聯的 PL/SQL 變量關閉時自動關閉。使用異常處理確保在任何異常情況下關閉游標。使用連接池自動關閉游標。禁用自動提交,延遲游標關閉。

Oracle 中,FOR LOOP 循環可動態創建游標, 步驟為:1. 定義游標類型;2. 創建循環;3. 動態創建游標;4. 執行游標;5. 關閉游標。示例:可循環創建游標,顯示前 10 名員工姓名和工資。

在CentOS系統上搭建Hadoop分佈式文件系統(HDFS)需要多個步驟,本文提供一個簡要的配置指南。一、前期準備安裝JDK:在所有節點上安裝JavaDevelopmentKit(JDK),版本需與Hadoop兼容。可從Oracle官網下載安裝包。環境變量配置:編輯/etc/profile文件,設置Java和Hadoop的環境變量,使系統能夠找到JDK和Hadoop的安裝路徑。二、安全配置:SSH免密登錄生成SSH密鑰:在每個節點上使用ssh-keygen命令

Oracle不僅是數據庫公司,還是雲計算和ERP系統的領導者。 1.Oracle提供從數據庫到雲服務和ERP系統的全面解決方案。 2.OracleCloud挑戰AWS和Azure,提供IaaS、PaaS和SaaS服務。 3.Oracle的ERP系統如E-BusinessSuite和FusionApplications幫助企業優化運營。

Oracle 日誌文件寫滿時,可採用以下解決方案:1)清理舊日誌文件;2)增加日誌文件大小;3)增加日誌文件組;4)設置自動日誌管理;5)重新初始化數據庫。在實施任何解決方案前,建議備份數據庫以防數據丟失。

要停止 Oracle 數據庫,請執行以下步驟:1. 連接到數據庫;2. 優雅關機數據庫(shutdown immediate);3. 完全關機數據庫(shutdown abort)。

可以通過 EXP 實用程序導出 Oracle 視圖:登錄 Oracle 數據庫。啟動 EXP 實用程序,指定視圖名稱和導出目錄。輸入導出參數,包括目標模式、文件格式和表空間。開始導出。使用 impdp 實用程序驗證導出。

在CentOS系統上配置WebLogic數據庫連接,需要完成以下步驟:JDK安裝與環境配置:確保服務器已安裝與WebLogic版本兼容的JDK(例如,WebLogic14.1.1通常需要JDK8)。正確設置JAVA_HOME、CLASSPATH和PATH環境變量。 WebLogic安裝與解壓:從Oracle官方網站下載適用於CentOS系統的WebLogic安裝包,並將其解壓到指定目錄。 WebLogic用戶與目錄創建:創建一個專用的WebLogic用戶賬戶,並設置安全密碼
