通过oracle类比MySQL中的字节字符问题

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 在几个月前写过一篇博文 MySQL数据类型 http://blog.itpub.net/23718752/viewspace-1371434/  当时写完以后有同事朋友就提出了一些疑问,对于汉字在MySQL和Oracle中的存放情况希望我能够详细的说说。
在几个月前写过一篇博文 MySQL数据类型 http://blog.itpub.net/23718752/viewspace-1371434/
 当时写完以后有同事朋友就提出了一些疑问,对于汉字在MySQL和Oracle中的存放情况希望我能够详细的说说。
 关于MySQL中的varchar字符类型,自己的操作都是基于字符集UTF-8。
 对于存放汉字,涉及到字符,字节,编码的一些知识,我查了一下,自己先补补,发现有一个帖子已经描述的很详细了。直接引用过来。
 http://www.regexlab.com/zh/encoding.htm
从编码的发展来看,大致可以分为三个阶段。系统内码  说明                          系统
阶段一     ASCII                       计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。
阶段二     ASCII(本地化)         为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。
                                              然后不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312                                               编码,在日文操作系统下,ANSI 编码代表 JIS 编码。
阶段三    UNICODE(国际化)    为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。
 因为对Oracle中的一些细节略为熟悉,所以能够旁敲侧击出MySQL中的一些相通的地方。
在编码的基础上,字符,字节的关系就很重要了。
字符是一个抽象意义的符号,一个汉字或一个字母都是一个字符。
而字节是计算机中存储数据的单元,一个8位的二进制数
如果对Oracle接触长了,再用MySQL,一个很纠结的地方就是汉字的存放,在MySQL中,汉字和字母都是平等对待的,都是按照字符来存放的。
但是Oracle中却不然,可以聚个简单的例子。
SQL> create table test (name varchar2(6));
Table created.
SQL> insert into test values('123456');
1 row created.
SQL> insert into test values('一二三');
insert into test values('一二三')
                        *
ERROR at line 1:
ORA-12899: value too large for column "SYS"."TEST"."NAME" (actual: 9, maximum:6)
SQL> insert into test values('一二');
1 row created.
在Oracle中有一个dump函数能够很清晰的查看出数据的存储情况。
比如下面的情况,查看汉字和字母,每个汉字是按照3个字节来存放的,每个字母则是一个字节。
SQL> select dump('你好') from dual;
DUMP('你好')
-------------------------------------
Typ=96 Len=6: 228,189,160,229,165,189
SQL> select dump('a') from dual;
DUMP('A')
----------------
Typ=96 Len=1: 97
这一点和MySQL存在着明显的差别,Oracle中其实也可以得到和MySQL同样的效果。
这就涉及到一个数据库参数NLS_LENGTH_SEMANTICS,这个参数用于指定CHAR列或VARCHAR2列的长度定义方式,默认值为BYTE。当设置该参数为BYTE时,定义CHAR列或VARCHAR2列采用字节长度方式;当设置该参数为CHAR时,定义CHAR列或VARCHAR2列采用字符个数方式。
为了不伤筋动骨,我就在session级别做一些变更来说明这个问题。首先把它从byte变更为char(注意这个参数在oracle中是作为基本的初始化参数,一般不需要修改)
SQL>ALTER SESSION SET nls_length_semantics=char;
创建一个测试表,指定字段长度为varchar2(6)
SQL> create table test_char (name varchar2(6));
Table created.
SQL> insert into test_char values('北京');
1 row created.
SQL> insert into test_char values('北京欢迎你'); --插入5个字符也没有问题,情况和之前明显不同。
1 row created.
SQL> insert into test_char values('北京欢迎你啊'); --插入6个字符也没有问题。
1 row created.
SQL> insert into test_char values('北京欢迎你哈哈');   
insert into test_char values('北京欢迎你哈')
                             *
ERROR at line 1:
ORA-12899: value too large for column "N1"."TEST_CHAR"."NAME" (actual: 8, maximum: 6)
然后我们为了对别插入两组数字看看效果。
SQL> insert into test_char values('1234');
1 row created.
SQL> insert into test_char values(123456);
1 row created.
SQL> select name,dump(name) text from test_char;
NAME                     TEXT
------------------------ ----------------------------------------------------------------------------------------------------
北京                     Typ=1 Len=6: 229,140,151,228,186,172
北京欢迎你               Typ=1 Len=15: 229,140,151,228,186,172,230,172,162,232,191,142,228,189,160
北京欢迎你啊             Typ=1 Len=18: 229,140,151,228,186,172,230,172,162,232,191,142,228,189,160,229,149,138
1234                     Typ=1 Len=4: 49,50,51,52
123456                   Typ=1 Len=6: 49,50,51,52,53,54

这样来查看好像和最开始的情况没有任何的变化。可以看到还是按照三个字节来存放,但是代表的意义已经发生了变化。
在MySQL中的情况和在oracle 参数nls_length_semantics=char;的情况是类似的。
SQL>create table test(name varchar(10));
SQL>insert into test values('1234567890');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values('一二三四五六七八九十');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,12345678901);
ERROR 1406 (22001): Data too long for column 'name' at row 1
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> show warnings;
+---------+------+-------------------------------------------+
| Level   | Code | Message                                   |
+---------+------+-------------------------------------------+
| Warning | 1265 | Data truncated for column 'name' at row 1 | --最后这个地方直接给truncate掉了多余的部分。
+---------+------+-------------------------------------------+
1 row in set (0.00 sec)

这一点在数据迁移的时候如果不注意就是很严重的问题。不知道MySQL中是否也有和oracle中类似的dump函数,但是我们可以通过类似相通的部分来互相印证。
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
5月前
|
关系型数据库 MySQL Java
字节面试: MySQL 百万级 导入发生的 “死锁” 难题如何解决?“2序4拆”,彻底攻克
字节面试: MySQL 百万级 导入发生的 “死锁” 难题如何解决?“2序4拆”,彻底攻克
字节面试: MySQL 百万级 导入发生的 “死锁” 难题如何解决?“2序4拆”,彻底攻克
|
8月前
|
Oracle 关系型数据库 MySQL
Oracle linux 8 二进制安装 MySQL 8.4企业版
Oracle linux 8 二进制安装 MySQL 8.4企业版
317 1
|
10月前
|
SQL Oracle 关系型数据库
MySQL 和 Oracle 的区别?
本文对比了Oracle和MySQL数据库的多个方面。Oracle适用于大型数据库,支持高并发和大访问量,市场占有率为40%,安装占用空间较大,约3G;而MySQL适合中小型应用,是开源免费的,安装仅需152M。两者在主键生成、字符串处理、SQL语句、事务处理等方面存在差异。Oracle功能更为强大,尤其在企业级应用中表现突出,而MySQL则以简单易用见长。
1233 7
MySQL 和 Oracle 的区别?
|
9月前
|
Oracle 关系型数据库 MySQL
使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试
这篇文章是作者尚雷关于使用崖山YMP迁移Oracle/MySQL至YashanDB 23.2的验证测试分享。介绍了YMP的产品信息,包括架构、版本支持等,还详细阐述了外置库部署、YMP部署、访问YMP、数据源管理、任务管理(创建任务、迁移配置、离线迁移、校验初始化、一致性校验)及MySQL迁移的全过程。
|
11月前
|
监控 Oracle 关系型数据库
Mysql、Oracle审计日志的开启
通过上述步骤,可以在 MySQL 和 Oracle 数据库中启用和配置审计日志。这些日志对于监控数据库操作、提高安全性和满足合规性要求非常重要。确保正确配置审计参数和策略,定期查看和分析审计日志,有助于及时发现并处理潜在的安全问题。
678 11
|
Oracle NoSQL 关系型数据库
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
2565 3
|
存储 关系型数据库 MySQL
MySQL 字符字段长度设置详解:语法、注意事项和示例
MySQL 字符字段长度设置详解:语法、注意事项和示例
1102 0
|
Oracle 关系型数据库 MySQL
shell获取多个oracle库mysql库所有的表
请注意,此脚本假设你有足够的权限访问所有提到的数据库。在实际部署前,请确保对脚本中的数据库凭据、主机名和端口进行适当的修改和验证。此外,处理数据库操作时,务必谨慎操作,避免因错误的脚本执行造成数据损坏或服务中断。
205 0
|
存储 Oracle 关系型数据库
oracle 数据库 迁移 mysql数据库
将 Oracle 数据库迁移到 MySQL 是一项复杂的任务,因为这两种数据库管理系统具有不同的架构、语法和功能。
275 0
|
存储 Oracle 关系型数据库
oracle迁移mysql数据库注意(转)
oracle转mysql修改:1. substr() substr( string , 0, 10) 这里测试 必须从 第一位获取 既是 substr(string , 1 , 10)2. to_char() 只能用做oracle的函数,兼容oracle和mysql故 改为concat( … , ''); 这里 使用了两个, 一个 是将类似 int 转为 string 3.
1905 0

推荐镜像

更多