共計 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 的支持。