【数据库字段类型】MySQL与Oracle数据类型底层设计原理对比(上)
📖 目录
上篇:数值类型与字符类型底层原理
-
提问一:MySQL和Oracle所有支持数据类型按日期、字符串、数字、二进制对比列举
-
提问二:Oracle的NUMBER和MySQL的DECIMAL数字类型的底层原理对比,都是如何保证小数位精度的
-
提问三:Oracle LONG是数字还是文本类型?MySQL的DOUBLE和Oracle BINARY_DOUBLE区别对比
中篇:大对象(LOB)类型与字符集编码
-
提问四:Oracle的CLOB/BLOB和MySQL的BLOB/TEXT字段底层存储原理区别
-
提问五:Oracle的CLOB和MySQL的TEXT字段使用流读取数据有何区别?是现读取到JVM内存再字符流读取,还是分段读取数据库
-
提问六:Oracle的VARCHAR2和NVARCHAR2的字符集存储区别(数据库字符集 vs 国家字符集)
下篇:日期时间类型与时区处理
-
提问七:Oracle的TIMESTAMP带时区和本地时区,使用场景对比
-
提问八:MySQL的TIMESTAMP和Oracle的DATE、TIMESTAMP有何区别
作者介绍
大家好,我是 CodeStats。
一个在底层技术上“考古”了四年的硬核爱好者,也是 WWAIC(全周项目 AI 编程)范式的提出者和实践者。我曾手写过一个完整的 Java Web 框架(从 IoC 容器到嵌入式 Tomcat,代码全开源),也喜欢用通俗的语言拆解 CPU、JVM、操作系统的运行本质。
本文延续《从内核到应用:操作系统与六大编程语言底层原理完全指南》的底层视角,将目光转向数据库内核——聚焦 MySQL 和 Oracle 两大关系型数据库的数据类型底层存储原理。无论你使用哪种数据库,理解数据在磁盘上的真实面貌,都会让你写出更高效的 SQL、设计更合理的表结构。
提问一:MySQL和Oracle所有支持数据类型按日期、字符串、数字、二进制对比列举
1.1 数值类型
| 分类 | MySQL | Oracle | 说明 |
|---|---|---|---|
| 整数(精确) | TINYINT(1B)、SMALLINT(2B)、MEDIUMINT(3B)、INT(4B)、BIGINT(8B) | NUMBER(p) 变长1-22字节 | Oracle无独立整数类型,统一用NUMBER |
| 定点数(精确) | DECIMAL(p,s) / NUMERIC(p,s) | NUMBER(p,s) | 都是精确十进制,MySQL精度65位,Oracle38位 |
| 浮点数(近似) | FLOAT(4B)、DOUBLE(8B) | BINARY_FLOAT(4B)、BINARY_DOUBLE(8B) | 都遵循IEEE 754 |
| 位类型 | BIT(n) | — | MySQL专用 |
| 布尔 | BOOLEAN / BOOL(实际为TINYINT(1)) | — | Oracle用CHAR(1)或NUMBER(1)模拟 |
1.2 字符串类型
| 分类 | MySQL | Oracle | 说明 |
|---|---|---|---|
| 定长字符 | CHAR(n)(最大255字符) | CHAR(n)、NCHAR(n) | 都用空格填充尾部 |
| 变长字符 | VARCHAR(n)(最大65535字节) | VARCHAR2(n)(最大4000字节)、NVARCHAR2(n) | MySQL按字节计,Oracle可指定CHAR或BYTE |
| 大文本 | TEXT系列(TINYTEXT 255B / TEXT 64KB / MEDIUMTEXT 16MB / LONGTEXT 4GB) | CLOB(4GB)、NCLOB(4GB) | 都有字符集,NCLOB用国家字符集 |
| 二进制定长 | BINARY(n) | — | MySQL专用 |
| 二进制变长 | VARBINARY(n) | RAW(n)(最大2000字节) | 无字符集转换 |
| 大二进制 | BLOB系列(TINYBLOB / BLOB / MEDIUMBLOB / LONGBLOB) | BLOB(4GB) | 纯二进制 |
| 遗留类型 | — | LONG(2GB文本)、LONG RAW(2GB二进制) | Oracle已弃用,推荐CLOB/BLOB替代 |
1.3 日期时间类型
| 分类 | MySQL | Oracle | 说明 |
|---|---|---|---|
| 日期(无时间) | DATE(3B) | — | Oracle的DATE包含时间 |
| 时间(无日期) | TIME(3B) | — | — |
| 日期时间 | DATETIME(5-8B) | DATE(7B) | Oracle DATE精确到秒 |
| 时间戳 | TIMESTAMP(4-7B) | TIMESTAMP(7-11B) | MySQL存UTC,Oracle存本地时间(可带时区) |
| 年份 | YEAR(1B) | — | — |
| 带时区 | — | TIMESTAMP WITH TIME ZONE(13B)TIMESTAMP WITH LOCAL TIME ZONE(11B) | Oracle专有时区支持 |
| 间隔 | — | INTERVAL YEAR TO MONTH(5B)INTERVAL DAY TO SECOND(11B) | 时间跨度类型 |
1.4 大对象(LOB)类型
| 分类 | MySQL | Oracle | 说明 |
|---|---|---|---|
| 文本大对象 | TEXT系列 | CLOB | 有字符集,支持SQL字符串函数 |
| 二进制大对象 | BLOB系列 | BLOB | 无字符集,按字节存储 |
| 国家字符集大对象 | — | NCLOB | 用国家字符集(AL16UTF16/UTF8) |
| 外部文件指针 | — | BFILE | 只读外部操作系统文件 |
| JSON | JSON(二进制优化格式) | JSON(Oracle 21c+) | 都支持JSON路径查询 |
1.5 特殊类型
| 分类 | MySQL | Oracle | 说明 |
|---|---|---|---|
| 枚举 | ENUM(数值索引存储) | — | MySQL专用 |
| 集合 | SET(位图存储) | — | MySQL专用 |
| 空间几何 | GEOMETRY系列 | SDO_GEOMETRY | 都支持R-Tree索引 |
| 行标识 | — | ROWID / UROWID | Oracle物理行地址,访问最快 |
提问二:Oracle的NUMBER和MySQL的DECIMAL数字类型的底层原理对比,都是如何保证小数位精度的
2.1 MySQL DECIMAL底层原理
MySQL的DECIMAL采用二进制压缩格式存储,核心规则是每9个十进制数字压缩到4个字节。
数据结构(源码 strings/decimal.h):
c
typedef struct st_decimal_t {
int intg; // 整数部分数字个数
int frac; // 小数部分数字个数
int sign; // 符号(0正,1负)
decimal_digit_t buf[DECIMAL_BUFF_LENGTH]; // int32数组,每个元素存0~999999999
} decimal_t;
存储空间计算:
-
整数部分和小数部分分别计算存储空间
-
满9位 → 4字节;不足9位按表:1-2位→1字节,3-4位→2字节,5-6位→3字节,7-9位→4字节
-
总字节 = 整数部分存储 + 小数部分存储(符号在首位用
sign标记,不占额外存储字节)
示例:DECIMAL(18,9)
-
整数部分9位 → 9/9=1组 → 4字节
-
小数部分9位 → 9/9=1组 → 4字节
-
总计:8字节
精度保证:由于使用decimal_digit_t(int32)数组精确存储每个十进制数位,所有运算在内存中以十进制整数进行,不存在二进制浮点误差。
2.2 Oracle NUMBER底层原理
Oracle的NUMBER采用100进制科学计数法存储,可变长度1-22字节。
物理结构(DUMP可查看):
-
指数字节(1字节):存储指数偏移量(正数:指数+193;负数:62-指数)
-
尾数字节(1-20字节):每个字节代表一个100进制数字(0-99),每字节存2位十进制数
-
零:固定存为单字节
0x80
编码规则详解:
-
正数:指数+193,尾数每位数字+1后存储
-
负数:62-指数,尾数用101减去每位数字后存储,末尾加
102(0x66)作为终止符 -
排序优化:这种编码使得正数/负数的字节序天然对应数值大小,可直接用
memcmp比较
示例:123.456 的DUMP
sql
SELECT DUMP(123.456) FROM DUAL; -- Typ=2 Len=4: 195,2,24,46,7 -- 195=193+2(指数2),2=1+1,24=23+1,46=45+1,7=6+1
精度保证:所有运算基于100进制整数尾数进行十进制运算,完全精确,最大精度38位。
2.3 对比总结
| 对比维度 | MySQL DECIMAL | Oracle NUMBER |
|---|---|---|
| 最大精度 | 65位十进制 | 38位十进制 |
| 存储方式 | 9位→4字节压缩 | 每字节存2位(100进制) |
| 编码进制 | 10^9进制 | 100进制 |
| 符号处理 | sign字段(单独标记) | 指数偏移+尾数反转(正负数编码不同) |
| 排序优化 | 不支持直接memcmp(需特殊转换) | 支持直接memcmp(字节序=数值序) |
| 存储空间 | 固定按精度分配(但计算时动态) | 严格变长,只存有效数字 |
| 小数精度 | 完全精确(十进制整数运算) | 完全精确(十进制尾数运算) |
| 类型独立 | 独立的DECIMAL类型 | NUMBER统一涵盖整数、定点、浮点 |
核心结论:两者都通过“避免二进制浮点”来保证精度,但实现路径不同——MySQL用更大的整数数组(int32)追求更高精度(65位),Oracle用更紧凑的变长字节(100进制)追求存储效率和排序性能(38位)。
提问三:Oracle LONG是数字还是文本类型?MySQL的DOUBLE和Oracle BINARY_DOUBLE区别对比
3.1 Oracle LONG是数字还是文本类型?
LONG不是数字类型,而是文本类型。
-
存储可变长度字符串,最大2GB(2^31-1字节)
-
具有
VARCHAR2的许多特征,但受到诸多限制:-
每表只能有1个LONG列
-
不能用于
WHERE子句(除非使用LONG函数) -
不能分组(
GROUP BY)、不能排序(ORDER BY) -
不能通过SQL标准函数(如
SUBSTR)直接处理 -
不能创建索引
-
不能在
INSERT时使用DEFAULT值
-
-
已弃用(Oracle 8i开始推荐使用CLOB),Oracle官方强烈建议新系统不要使用LONG。
-
对应二进制版本为
LONG RAW(已弃用,推荐BLOB)。
3.2 MySQL DOUBLE vs Oracle BINARY_DOUBLE
两者底层完全一致,都严格遵循 IEEE 754 双精度浮点标准。
| 对比维度 | MySQL DOUBLE | Oracle BINARY_DOUBLE |
|---|---|---|
| 存储字节 | 8字节 | 8字节 |
| 标准 | IEEE 754 | IEEE 754 |
| 精度 | 约15-16位十进制有效数字 | 约15-16位十进制有效数字 |
| 计算方式 | 硬件FPU(浮点运算单元)直接执行 | 硬件FPU直接执行 |
| 取值范围 | ±1.7976931348623157E+308 | ±1.7976931348623157E+308 |
| 特殊值 | 支持Infinity、-Infinity、NaN | 支持Infinity、-Infinity、NaN |
| 类型名称 | DOUBLE 或 DOUBLE PRECISION | BINARY_DOUBLE |
| 近似误差 | 0.1无法精确表示(二进制浮点固有缺陷) | 0.1无法精确表示(二进制浮点固有缺陷) |
结论:两者底层二进制存储完全相同,只是在SQL语法层面名称不同。Oracle用BINARY_前缀强调其二进制浮点特性,以区别于十进制的NUMBER类型。
📚 参考文章链接
-
【编程语言】从内核到应用:操作系统与六大编程语言底层原理完全指南(上)
【编程语言】从内核到应用:操作系统与六大编程语言底层原理完全指南(上)-CSDN博客 -
【编程语言】从内核到应用:操作系统与六大编程语言底层原理完全指南(下)
https://blog.csdn.net/qq_41652036/article/details/xxxxxxx -
MySQL :: MySQL 8.0 Reference Manual :: 13.1.3 Fixed-Point Types (Exact Value)
https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html -
Oracle Database SQL Language Reference - Data Types
Data Types -
MySQL :: InnoDB Row Formats and Externally Stored Fields
https://dev.mysql.com/doc/refman/8.0/en/innodb-row-format.html -
Oracle AskTOM - What is lobsegment and lobindex
https://asktom.oracle.com/pls/apex/asktom.search?tag=what-is-lobsegment-lobindex -
MySQL :: MySQL Connector/J Developer Guide :: 6.6.1 Preserving Time Instants
https://dev.mysql.com/doc/connector-j/en/connector-j-time-instants.html -
Oracle Database Globalization Support Guide - Datetime Data Types
https://docs.oracle.com/en/database/oracle/oracle-database/19/nlspg/datetime-data-types.html -
Oracle Database Globalization Support Guide - NCHAR and NVARCHAR2
https://docs.oracle.com/en/database/oracle/oracle-database/19/nlspg/nchar-nvarchar2-data-types.html
如果觉得本文有帮助,欢迎点赞、收藏、关注!你的支持是我持续输出硬核技术内容的动力。有任何疑问或想深入了解的方向,欢迎在评论区留言讨论。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)