共计 5693 个字符,预计需要花费 15 分钟才能阅读完成。
怎么理解 MYSQL 数据类型存储中数值型,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面丸趣 TV 小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
探索 MYSQL 数值类型的存储, 以及解读方法.on Engine of myisam[@more@]1. 环境版本:
OS : LINUX AS4
MYSQL: 5.0.51a-log
ENGINE : Myisam DEFAULT CHARSET=latin1
2. 本章研究的数值类型对象:
TINYINT 1 个字节 FIXED
SMALLINT 2 个字节 FIXED
MEDIUMINT 3 个字节 FIXED
INT, INTEGER 4 个字节 FIXED
BIGINT 8 个字节 FIXED
DECIMAL(M,N) = 4 字节 FIXED
3. 数值类型: TINYINT SMALLINT MEDIUMINT INT BIGINT
这几种数据存取方式都是一样的: 高位优先存储, 符号位(0 正,1 负)
drop table if exists heyf ;
create table heyf (id TINYINT) type myisam DEFAULT CHARSET=latin1;
insert into heyf values (10),(-10) ;
system hexdump /opt/mysql/data/test/heyf.MYD
——————————————
0000000 0afd 0000 0000 fd00 00f6 0000 0000
000000e
——————————————
其中:
ROW1:
——————————–
fd : 行 header
0a : 值 10
———————————
ROW2:
——————————–
fd : 行 header
f6 : 值 -10 的补码
———————————
如果是正数, 第 1 位为 0 , 直接读出来即可;
如果是负数, 第 1 位为 1 , 则按常规办法将值 取反 +1.
比如:
原值 原二进制 取反 加 1 十进制
——————————————————-
f6 — gt 1111 0110 — gt 0000 1001 — gt 0000 1010 — gt 10
其他几个类型请读者举一反三.
4. 数值类型: DECIMAL(M,N) 或 DECIMAL(M)
4.1 存储位计算
最小分配 4 个字节空间, 比如 decimal(4,2), 实际用两个字节就可以表示. 但 MYSQL 在分配空间时还是用了 4 个字节. 空闲部分用 0 填充
DECIMAL(M,N), 如果 9 M 17, 至需要 5~8 个以上字节. 如果 18 M 36, 则会需要 8~12 个字节.
(这里为什么要这样算, 详见 4.2 中的实例解释)
4.2 如何读取数据.
4.2.1 读取步骤
按照定义, 从磁盘读出该 DECEMAL 字段的所有数据 (N 位) 后:
4.2.1.1 正数, 带小数,DECIMAL(4,2)
0)以 1 开头, 如果定义为 UNSIGNED, 则都为 1
1)去掉第一位符号位,
2)用小数将剩余的位数分开, 前面 (M 位) 是整数部分, 后面 (N 位) 是小数部分
(在这一步是怎么分 M 和 N 的, 我们能根据字段的定义计算出来)
3) 去掉小数点后面 (整个字节) 为 0 的情况,
4)将二进制转换成十进制, 即可读出原值.
(注意, 小数的读取方法与整数的方法一样, 按二进制向十进制转换即可)
4.2.1.2 负数, 带小数 DECIMAL(4,2)
0)以 0 开头,
1)去掉第一位符号位,
2)剩余的数取反 +1 ,
3)用小数将剩余的位数分开, 前面 (M 位) 是整数部分, 后面 (N 位) 是小数部分
(在这一步是怎么分 M 和 N 的, 我们能根据字段的定义计算出来)
4) 去掉小数点后面 (整个字节) 为 0 的情况,
5)将二进制转换成十进制, 即可读出原值.
(注意, 小数的读取方法与整数的方法一样, 按二进制向十进制转换即可)
4.2.1.3 正数, 不带小数, DECIMAL(N)
0)以 1 开头, 如果定义为 UNSIGNED, 则都为 1
1)去掉第一位符号位,
2)将剩余的数位直接按二进制向十进制转换即可
4.2.1.4 负数, 不带小数, DECIMAL(N)
0)以 0 开头
1)去掉第一位符号位,
2)将剩余的数取反 +1
3)按二进制向十进制转换即可读到原值
4.2.1.5 超长数值, 如何读取
当需要表示的数值超过某个限值后, 如果你按以上的方法去读取数据, 会发现读出来的数值是不对的.
资料写道:
********************************************************************
high byte first, four-byte chunks.
We call the four-byte chunks *decimal* digits .
Since 2**32 = There is an implied decimal point. Details are in /strings/decimal.c.
Example: a MySQL 5.0 DECIMAL(21,9) column containing 111222333444.555666777
looks like: hexadecimal 80 6f 0d 40 8a 04 21 1e cd 59 — (flag + 111 , 222333444 , 555666777).
********************************************************************
但经过测试, 似乎是当数值 =999999999 时, 我们还可以用原来的方法去读取.
一旦数值 999999999, 我们就需要按 CHUNK(4 个字节)来读取.
详见 4.2 章节中的测试实例.
4.2.2 实例验证
4.2.2.1 带符号位的 DECIMAL(M,N).
Drop table if exists heyf ;
create table heyf (id DECIMAL(4,2) ) type myisam ;
insert into heyf values (65),(-65),(23.34),(-23.34);
system hexdump /opt/mysql/data/test/heyf.MYD
———————————————-
0000000 c1fd 0000 0000 fd00 ff3e 0000 0000 97fd
0000010 0022 0000 fd00 dd68 0000 0000
———————————————-
ROW1: c1 00 00 00 : 1 1000001 00000000 00000000 00000000
ROW2: 3e ff 00 00 : 0 0111100 ffffffff 00000000 00000000
ROW3: 97 22 00 00 : 1 0010111 00100010 00000000 00000000
ROW4: 68 dd 00 00 : 0 1101000 11011101 00000000 00000000
————————————————————
磁盘数据 符号 整数 小数 空闲 空闲
我们来看上面的方法进行读取:
ROW1:
符号位 : 1, 正数.
整数部分: 1000001 = 65
小数部分: 0
原值 : 65
ROW2:
符号位 : 0, 负数
取反 +1 : 1000100 00000000
整数部分: 1000001 = 65
小数部分: 0
原值 : -65
ROW3:
符号位 : 1, 正数
整数部分: 0010111 = 23
小数部分: 00100010 = 34
原值 : 23.34
ROW4:
符号位 : 0, 负数
取反 +1 : 0010111 00100010
整数部分: 0010111 = 23
小数部分: 00100010 = 34
原值 : -23,34
4.2.2.2 不带符号位的,DECIMAL(M,N)UNSIGNED.
Drop table if exists heyf ;
create table heyf (id DECIMAL(4,2) UNSIGNED ) type myisam ;
insert into heyf values (65),(23.34);
system hexdump /opt/mysql/data/test/heyf.MYD
———————————————-
0000000 c1fd 0000 0000 fd00 2297 0000 0000
000000e
———————————————-
ROW1: c1 00 00 00 : 1 1000001 00000000 00000000 00000000
ROW3: 97 22 00 00 : 1 0010111 00100010 00000000 00000000
————————————————————
磁盘数据 符号 整数 小数 空闲 空闲
注意: 符号位都为 1 .
整数部分和小数部分, 该实例与 4.2.2.1 中实例的取值一样, 在这里不再赘述.
4.2.2.3 带符号位的, DECIMAL(M)
Drop table if exists heyf ;
create table heyf (id DECIMAL(10)) type myisam ;
insert into heyf values (65),(-65);
system hexdump /opt/mysql/data/test/heyf.MYD
———————————————-
0000000 80fd 0000 4100 fd00 ff7f ffff 00be
———————————————-
ROW1: 80 00 00 00 41 — gt 10000000 00000000 00000000 00000000 01000001
ROW2: 7f ff ff ff be — gt 01111111 11111111 11111111 11111111 10111110
到这里, 如果你认真地读完了 4.2.2.1 和 4.2.2.2 小节, 那么下面的转换对你来说将不再是难事了.
正数, 去符号位后直接转换成十进制;
负数, 去符号位, 剩余取反 + 1 后, 转换成十进制;
4.2.2.4 不带符号位的 DECIMAL(M) UNSIGNED .
Drop table if exists heyf ;
create table heyf (id DECIMAL(10) UNSIGNED ) type myisam ;
insert into heyf values (65),(200000);
system hexdump /opt/mysql/data/test/heyf.MYD
———————————————-
0000000 80fd 0000 4100 fd00 0080 0d03 0040
———————————————-
ROW1: 80 00 00 00 41
ROW2: 80 00 03 0d 40
在这里用了五个字节来表示 DECIMAL(10). 关于原数值, 我想大家应该都能看出来了.
0X41 — gt 65
0X30d40 — gt 20000
4.2.2.5 超长数值的读取(999999999)
Drop table if exists heyf ;
create table heyf (id DECIMAL(10) UNSIGNED ) type myisam ;
insert into heyf values (999999999),(1000000000),(2147483648);
system hexdump /opt/mysql/data/test/heyf.MYD
———————————————-
0000000 80fd 9a3b ffc9 fd00 0081 0000 0000 82fd
0000010 ca08 006c
———————————————-
ROW1: 80 3b 9a c9 ff — gt 10000000 00111011 10011010 11001001 11111111
ROW2: 81 00 00 00 00 — gt 10000001 00000000 00000000 00000000 00000000
ROW2: 82 08 ca 6c 00 — gt 10000010 00001000 11001010 01101100 00000000
试着用原来的方法将数据进行转换:
ROW1: select conv(000000000111011100110101100100111111111,2,10) ;
— gt 999999999 正确
ROW2: select conv(000000100000000000000000000000000000000,2,10) ;
— gt 4294967296 与原值不符
ROW3: select conv(000001000001000110010100110110000000000,2,10) ;
— gt 8737418240 与原值不符
其实, 正如上面所说的, 如果数值超过 999999999, 那么需要按 CHUNK(4 个字节)来读取, 并在最后将数拼起来.
比如我们读第三行数据:
从右到左读:
1)先读 4 个字节:00001000 11001010 01101100 00000000 — gt 147483648
2)再读剩余的 1 个字节:0000010 — gt 2
把以上两个结果拼起来: 2 || 147483648 = 2147483648 这里才与原值相符
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注丸趣 TV 行业资讯频道,感谢您对丸趣 TV 的支持。