Oracle的学习心得和知识总结(三十三)|Oracle数据库数据库的SQL ID的底层计算原理分析

注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:《Oracle Database SQL Language Reference》
2、参考书籍:《PostgreSQL中文手册》
3、EDB Postgres Advanced Server User Guides,点击前往
4、PostgreSQL数据库仓库链接,点击前往
5、PostgreSQL中文社区,点击前往


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)
2、本文目的:开源共享 抛砖引玉 一起学习
3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关
4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)


Oracle数据库数据库的SQL ID的底层计算原理分析

  • 文章快速说明索引
  • 背景说明案例展示
  • 底层实现案例分析



文章快速说明索引

学习目标:

目的:接下来这段时间我想做一些兼容Oracle数据库Real Application Testing (即:RAT)上的一些功能开发,本专栏这里主要是学习以及介绍Oracle数据库功能的使用场景、原理说明和注意事项等,基于PostgreSQL数据库的功能开发等之后 由新博客进行介绍和分享!


学习内容:(详见目录)

1、Oracle数据库数据库的SQL ID的底层计算原理分析


学习时间:

2025年02月09日 18:06:19


学习产出:

1、Oracle数据库数据库的SQL ID的底层计算原理分析
2、CSDN 技术博客 1篇


注:下面我们所有的学习环境是Centos7+PostgreSQL15.0+Oracle19c+MySQL5.7

postgres=# select version();version                                   
-----------------------------------------------------------------------------PostgreSQL 15.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 7.1.0, 64-bit
(1 row)postgres=##-----------------------------------------------------------------------------#SQL> select * from v$version; BANNER									    BANNER_FULL 								BANNER_LEGACY									CON_ID
--------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- ----------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	    Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production		     0Version 19.3.0.0.0SQL>
#-----------------------------------------------------------------------------#mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.19    |
+-----------+
1 row in set (0.06 sec)mysql>

背景说明案例展示

在使用Oracle数据库的时候经常会看到SQL ID这样的东西,如下:

在这里插入图片描述

或者是如下SQL语句:

[oracle@local64 ~]$ sqlplus '/as sysdba'SQL*Plus: Release 11.2.0.1.0 Production on Fri Feb 7 14:10:57 2025Copyright (c) 1982, 2009, Oracle.  All rights reserved.Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing optionsSQL> select 'SONG BAOBAO' from dual;'SONGBAOBAO
-----------
SONG BAOBAOSQL> select 'SONGBAobao' from DUAL;'SONGBAOBA
----------
SONGBAobaoSQL> select sql_id, sql_text from v$sql where sql_text like '%SONG%';SQL_ID		     SQL_TEXT
-------------------- ----------------------------------------------------------------------------------------------------
dfrun6x61sj3g	     select 'SONGBAobao' from DUAL
2fsps80qfadc3	     select sql_id, sql_text from v$sql where sql_text like '%SONG%'
dgs6n0z31avcp	     select 'SONG BAOBAO' from dualSQL>

或者通过package函数,如下:

SQL> select dbms_sqltune_util0.sqltext_to_sqlid('select ''SONG BAOBAO'' from dual'||chr(0)) sql_id from dual;SQL_ID
--------------------
dgs6n0z31avcpSQL> select dbms_sqltune_util0.sqltext_to_sqlid('select ''SONGBAobao'' from DUAL'||chr(0)) sql_id from dual;SQL_ID
--------------------
dfrun6x61sj3gSQL>

如上都是简单SQL语句,下面看一下上面AWR图的一个例子,如下:

7r7636982atn9	UPDATE INVENTORIES SET QUANTITY_ON_HAND = QUANTITY_ON_HAND - :B1 WHERE PRODUCT_ID = :B3 AND WAREHOUSE_ID = :B2 

在这里插入图片描述


接下来,我们今天分析一下Oracle SQL_ID的生成过程以及相关注意事项,如下:

一、SQL_ID生成过程

  1. 计算MD5散列值

    • Oracle会对SQL_TEXT计算MD5散列值,并在SQL_TEXT末尾添加一个不可见字符\0(空字符)如上所述。
    • 这个步骤确保了即使SQL_TEXT内容相同,生成的SQL_ID也会因为末尾的空字符而不同。
  2. 取MD5散列值的低64位(请注意大小端的问题)

    • MD5散列值是一个128位的值,Oracle只取其中的低64位(即最后8个字节)。
    • 由于MD5是128位的,低64位就是最后64位(即最后8个字节)。
  3. 将64位分成5位一组(最后一组4位)

    • 将这64位分成13组,前12组每组5位,最后一组4位。
    • 每组5位的值范围是0到31,最后一组4位的值范围是0到15。
  4. Base32编码

    • 使用Base32将每组5位(或4位)的值转换为可见字符。
    • Oracle使用的Base32字符集为:0123456789abcdfghjkmnpqrstuvwxyz
    • 注意:这个字符集与标准的Base32字符集不同,标准的Base32字符集通常包含字母A-Z和数字2-7。

二、注意事项

(a) MD5散列时的空字符

  • 在计算MD5时,Oracle会在SQL_TEXT末尾添加一个空字符\0。这意味着即使两个SQL_TEXT内容相同,生成的SQL_ID也会不同,因为末尾的空字符会导致MD5散列值不同。

(b) Little-endian问题

  • 在处理字节序时,Oracle使用的是小端序(Little-endian)。这意味着在读取字节时,低位字节在前,高位字节在后。
  • 在编写程序时,需要确保正确处理字节序,特别是在处理64位值时。

© Base32字符集

  • Oracle使用的Base32字符集为:0123456789abcdfghjkmnpqrstuvwxyz
  • 这个字符集与标准的Base32字符集不同,因此在编写程序时需要特别注意使用正确的字符集。

(d) 大数精度问题

  • 在处理64位值时,可能会遇到大数精度问题。特别是在一些编程语言中,默认的整数类型可能无法处理64位值。
  • 在Perl、PHP等语言中,可以使用大数处理函数(如GMPBCMath扩展)来确保精度。

底层实现案例分析

SQL> select dbms_sqltune_util0.sqltext_to_sqlid('select ''SONG BAOBAO'' from dual'||chr(0)) sql_id from dual;SQL_ID
--------------------
dgs6n0z31avcpSQL>

我的环境,如下:

[oracle@local64 mydata]$ lscpu | grep -i byte
Byte Order:            Little Endian
[oracle@local64 mydata]$

第一步,计算散列值

  • Digest::MD5 相关函数说明,点击前往

先计算一下其md5值,如下:

[oracle@local64 mydata]$ cat mytest3.pl 
use Digest::MD5 qw(md5_hex);
$stmt = "select 'SONG BAOBAO' from dual\0";
$hash_hex = md5_hex $stmt;
print "$hash_hex\n";[oracle@local64 mydata]$ perl mytest3.pl 
10131690c894385807d4e0d7956d15c6
[oracle@local64 mydata]$10131690c8943858
07d4e0d7956d15c6
  • 进制转换在线,点击前往

其二进制转换为:

00010000000100110001011010010000110010001001010000111000010110000000011111010100111000001101011110010101011011010001010111000110

第二步,取低64位

07d4e0d7956d15c60000011111010100111000001101011110010101011011010001010111000110

第三步,转换为易读字符串

Oracle使用了Base32将字节流转换为可见字符,一一对应如下:

字节流十进制00010203040506070809101112131415
字符0123456789abcdfg
字节流十进制16171819202122232425262728293031
字符hjkmnpqrstuvwxyz

注: 这里给大家推荐一个好用的网站(可以直接复制粘贴到markdown):

  • 表格转换工具,点击前往

0000011111010100111000001101011110010101011011010001010111000110# 划分一下,如下:
00000111 11010100 11100000 11010111
10010101 01101101 00010101 11000110# 因为是小端11010111 11100000 11010100 00000111
11000110 00010101 01101101 10010101# 合并
1101011111100000110101000000011111000110000101010110110110010101# 其十六进制
d7e0d407c6156d95

然后切分,以及转换 如下:

1101 01111 11000 00110 10100 00000 11111 00011 00001 01010 11011 01100 10101
13   15    24    6     20    0     31    3     1     10    27    12    21 
d    g     s     6     n     0     z     3     1     a     v     c     pdgs6n0z31avcp

最后看一下转换一个SQL的SQLID逻辑,如下:

#!/usr/bin/perl -w
use Digest::MD5  qw(md5 md5_hex md5_base64);
use Math::BigInt;
my $stmt = "select 'SONG BAOBAO' from dual\0";
my $hash = md5 $stmt;
my($a,$b,$msb,$lsb) = unpack("V*",$hash);
print "a is $a, b is $b; msb is $msb, lsb is $lsb\n";my $sqln = $msb*(2**32)+$lsb;
my $stop = log($sqln) / log(32) + 1;
print "sqln is $sqln, stop is $stop\n";my $sqlid = '';
my $charbase32 = '0123456789abcdfghjkmnpqrstuvwxyz';
my @chars = split '', $charbase32;
for($i=0; $i < $stop-1; $i++){my $x = Math::BigInt->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"; 

执行一下,如下:

[oracle@local64 mydata]$ perl mytest1.pl 
a is 2417365776, b is 1480103112; msb is 3621835783, lsb is 3323293077
sqln is 15555666242790845845, stop is 13.7508147978182
SQL is:select 'SONG BAOBAO' from dual 
SQL_ID isdgs6n0z31avcp
[oracle@local64 mydata]$

解释一下,上面sqln = 15555666242790845845,该十进制的十六进制转换,如下:

在这里插入图片描述

[oracle@local64 mydata]$ cat convert_uint64_to_str.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>int main()
{const char *map = "0123456789abcdfghjkmnpqrstuvwxyz";int i = 0;char str[14] = {0};uint64_t sqlid = (uint64_t)15555666242790845845ULL;for(; i<13;++i){int j = (sqlid >> (60 - i * 5)) & 0x1F;str[i] = map[j];}printf("str is %s\n", str);return 0;
}
[oracle@local64 mydata]$
[oracle@local64 mydata]$ gcc -o convert convert_uint64_to_str.c -g -O0
[oracle@local64 mydata]$ 
[oracle@local64 mydata]$ ./convert 
str is dgs6n0z31avcp
[oracle@local64 mydata]$

若是用C语言实现上面perl的效果,如下:

[oracle@local64 mydata]$ cat mytest2.c 
#include <stdio.h>
#include <string.h>
#include <openssl/md5.h>
#include <math.h>
#include <stdint.h>// 用于计算 MD5 的函数
void md5_hash(const unsigned char *input, size_t length, unsigned char *output)
{MD5_CTX mdContext;MD5_Init(&mdContext);MD5_Update(&mdContext, input, length);MD5_Final(output, &mdContext);
}int main()
{int step = 0;// 包含 \0 的原始字节数组const unsigned char stmt[] = "select 'SONG BAOBAO' from dual\0";size_t stmt_len = sizeof(stmt) - 1; // 计算不包括末尾 \0 的实际长度// 用于存放 MD5 哈希结果unsigned char hash[MD5_DIGEST_LENGTH];md5_hash(stmt, stmt_len, hash); // 计算 MD5// 解包 MD5 哈希值uint32_t a = (hash[0] << 0) | (hash[1] << 8) | (hash[2] << 16) | (hash[3] << 24);uint32_t b = (hash[4] << 0) | (hash[5] << 8) | (hash[6] << 16) | (hash[7] << 24);uint32_t msb = (hash[8] << 0) | (hash[9] << 8) | (hash[10] << 16) | (hash[11] << 24);uint32_t lsb = (hash[12] << 0) | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24);printf("a is %u, b is %u; msb is %u, lsb is %u\n", a, b, msb, lsb);// 计算 sqln 和 stopuint64_t sqln = ((uint64_t)msb << 32) + lsb;double stop = log((double)sqln) / log(32.0) + 1;printf("sqln is %llu, stop is %.06f\n", sqln, stop);// Base32 字符集char charbase32[] = "0123456789abcdfghjkmnpqrstuvwxyz";char sqlid[100] = {0};step = (int)ceil(stop);// 生成 SQL_IDfor (int i = 0; i < step - 1; i++){unsigned long long pow_result = pow(32, i);unsigned long long x = sqln;unsigned long long div_result = x / pow_result;unsigned int seq = div_result % 32;// 插入到 sqlid 字符串的前面memmove(sqlid + 1, sqlid, strlen(sqlid) + 1);sqlid[0] = charbase32[seq];}printf("SQL is:\n    %s\nSQL_ID is\n    %s\n", stmt, sqlid);return 0;
}
[oracle@local64 mydata]$ gcc -o test2 mytest2.c -lssl -lcrypto -lm -g -O0
[oracle@local64 mydata]$ 
[oracle@local64 mydata]$ ./test2 
a is 2417365776, b is 1480103112; msb is 3621835783, lsb is 3323293077
sqln is 15555666242790845845, stop is 13.750815
SQL is:select 'SONG BAOBAO' from dual
SQL_ID isdgs6n0z31avcp
[oracle@local64 mydata]$

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/15718.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将DeepSeek接入Excel实现交互式对话

引言 将DeepSeek接入Excel&#xff0c;为你带来前所未有的交互体验&#xff01;“哪里不懂&#xff0c;选中哪里”&#xff0c;然后直接在侧边栏对话框向DeepSeek发问&#xff0c;非常地方便&#xff01; 案例演示 设置接入方式 既可以通过本地部署的DeepSeek接入Excel&#…

在npm上传属于自己的包

最近在整理代码&#xff0c;上传到npm方便使用&#xff0c;所以学习了如何在npm发布一个包&#xff0c;整理写成一篇文章和大家一起交流。 1、注册npm账号 npm | Home 2、确保是登录状态 &#xff08;在包目录下&#xff0c;终端执行 npm login) 按enter键自动打开页面&…

JS宏进阶:XMLHttpRequest对象

一、概述 XMLHttpRequest简称XHR&#xff0c;它是一个可以在JavaScript中使用的对象&#xff0c;用于在后台与服务器交换数据&#xff0c;实现页面的局部更新&#xff0c;而无需重新加载整个页面&#xff0c;也是Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;…

【快应用】多语言适配案例

【关键词】 多语言,$t 【问题背景】 快应用平台的能力会覆盖多个国家地区,平台支持多语言的能力后,可以让一个快应同时支持多个语言版本的切换,开发者无需开发多个不同语言的源码项目,避免给项目维护带来困难。使用系统默认的语言,开发者配置多语言的方式非常简单,只…

PyQt学习记录

0. 安装配置 0.1 安装相关库 首先打开你的PyCharm程序&#xff0c;然后新建一个目录用于学习&#xff0c;其次在terminal中输入 pip install pyqt5如果你不具有科学上网能力&#xff0c;请改为国内源 pip install pyqt5 -i https://pypi.douban.com/simple然后安装pyqt相关…

【多模态大模型】系列3:语义分割(LSeg、GroupViT)

目录 1 LSeg2 Group ViT 1 LSeg LANGUAGE-DRIVEN SEMANTIC SEGMENTATION LSeg是第一篇将CLIP应用于语义分割的论文。它的分割的效果拔群&#xff0c;容错能力也很高&#xff1a; 模型总览图跟CLIP很像&#xff1a; 对于图像链路&#xff1a;输入一张图片&#xff0c;进入分割…

【深度学习】多目标融合算法(四):多门混合专家网络MMOE(Multi-gate Mixture-of-Experts)

目录 一、引言 二、MMoE&#xff08;Multi-gate Mixture-of-Experts&#xff0c;多门混合专家网络&#xff09; 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 2.3.1 业务场景与建模 2.3.2 模型代码实现 2.3.3 模型训练与推理测试 2.3.4 打印模型结构 三、总结 一、…

自动驾驶数据集三剑客:nuScenes、nuImages 与 nuPlan 的技术矩阵与生态协同

目录 1、引言 2、主要内容 2.1、定位对比&#xff1a;感知与规划的全维覆盖 2.2、数据与技术特性对比 2.3、技术协同&#xff1a;构建全栈研发生态 2.4、应用场景与评估体系 2.5、总结与展望 3、参考文献 1、引言 随着自动驾驶技术向全栈化迈进&#xff0c;Motional 团…

使用 AlexNet 实现图片分类 | PyTorch 深度学习实战

前一篇文章&#xff0c;CNN 卷积神经网络处理图片任务 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于 强化学习必修课&#xff1a;引领人工智能新时代【梗直哥瞿炜】 使用 AlexNet 实现图片分类…

C# Winform 使用委托实现C++中回调函数的功能

C# Winform 使用委托实现C中回调函数的功能 在项目中遇到了使用C#调用C封装的接口&#xff0c;其中C接口有一个回调函数的参数。参考对比后&#xff0c;在C#中是使用委托(delegate)来实现类似的功能。 下面使用一个示例来介绍具体的使用方式&#xff1a; 第一步&#xff1a;…

攻防世界33 catcat-new【文件包含/flask_session伪造】

题目&#xff1a; 点击一只猫猫&#xff1a; 看这个url像是文件包含漏洞&#xff0c;试试 dirsearch扫出来/admin&#xff0c;访问也没成功&#xff08;--delay 0.1 -t 5&#xff09; 会的那几招全用不了了哈哈&#xff0c;那就继续看答案 先总结几个知识点 1./etc/passwd&am…

ArgoCD实战指南:GitOps驱动下的Kubernetes自动化部署与Helm/Kustomize集成

摘要 ArgoCD 是一种 GitOps 持续交付工具,专为 Kubernetes 设计。它能够自动同步 Git 仓库中的声明性配置,并将其应用到 Kubernetes 集群中。本文将介绍 ArgoCD 的架构、安装步骤,以及如何结合 Helm 和 Kustomize 进行 Kubernetes 自动化部署。 引言 为什么选择 ArgoCD?…

尝试一下,交互式的三维计算python库,py3d

py3d是一个我开发的三维计算python库&#xff0c;目前不定期在PYPI上发版&#xff0c;可以通过pip直接安装 pip install py3d 开发这个库主要可视化是想把自己在工作中常用的三维方法汇总积累下来&#xff0c;不必每次重新造轮子。其实现成的python库也有很多&#xff0c;例如…

【愚公系列】《循序渐进Vue.js 3.x前端开发实践》070-商业项目:电商后台管理系统实战(商品管理模块的开发)

标题详情作者简介愚公搬代码头衔华为云特约编辑&#xff0c;华为云云享专家&#xff0c;华为开发者专家&#xff0c;华为产品云测专家&#xff0c;CSDN博客专家&#xff0c;CSDN商业化专家&#xff0c;阿里云专家博主&#xff0c;阿里云签约作者&#xff0c;腾讯云优秀博主&…

5 个释放 安卓潜力的 Shizuku 应用

Shizuku 软件推荐&#xff1a;释放安卓潜力的五款应用 Shizuku (日语&#xff1a;雫&#xff0c;意为“水滴”) 正如其名&#xff0c;是一款轻巧但功能强大的安卓工具。它无需 Root 权限&#xff0c;通过 ADB (Android Debug Bridge) 授权&#xff0c;即可让应用调用系统 API&…

前端权限控制和管理

前端权限控制和管理 1.前言2.权限相关概念2.1权限的分类(1)后端权限(2)前端权限 2.2前端权限的意义 3.前端权限控制思路3.1菜单的权限控制3.2界面的权限控制3.3按钮的权限控制3.4接口的权限控制 4.实现步骤4.1菜单栏控制4.2界面的控制(1)路由导航守卫(2)动态路由 4.3按钮的控制…

分布式kettle调度平台- web版转换,作业编排新功能介绍

介绍 Kettle&#xff08;也称为Pentaho Data Integration&#xff09;是一款开源的ETL&#xff08;Extract, Transform, Load&#xff09;工具&#xff0c;由Pentaho&#xff08;现为Hitachi Vantara&#xff09;开发和维护。它提供了一套强大的数据集成和转换功能&#xff0c…

Docker容器访问外网:启动时的网络参数配置指南

在启动Docker镜像时,可以通过设置网络参数来确保容器能够访问外网。以下是几种常见的方法: 1. 使用默认的bridge网络 Docker的默认网络模式是bridge,它会创建一个虚拟网桥,将容器连接到宿主机的网络上。在大多数情况下,使用默认的bridge网络配置即可使容器访问外网。 启动…

大语言模型RAG,transformer

1、RAG技术流总结 第一张图是比较经典的RAG知识图谱&#xff0c;第二张图是更加详细扎实的介绍图。 1.1 索引 坦白来说这部分的技术并不是大模型领域的&#xff0c;更像是之前技术在大模型领域的应用&#xff1b;早在2019年我就做过faiss部分的尝试&#xff0c;彼时索引技术已…

数据结构与算法(test3)

七、查找 1. 看图填空 查找表是由同一类型的数据元素&#xff08;或记录&#xff09;构成的集合。例如上图就是一个查找表。 期中&#xff08;1&#xff09;是______________. (2)是______________(3)是_____关键字_______。 2. 查找(Searching) 就是根据给定的某个值, 在查…