您好,登錄后才能下訂單哦!
怎么理解MYSQL數(shù)據(jù)類型存儲中數(shù)值型,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
探索MYSQL 數(shù)值類型的存儲,以及解讀方法.on Engine of myisam[@more@]1. 環(huán)境版本:
OS : LINUX AS4
MYSQL: 5.0.51a-log
ENGINE : Myisam DEFAULT CHARSET=latin1
2. 本章研究的數(shù)值類型對象:
TINYINT 1個字節(jié) FIXED
SMALLINT 2個字節(jié) FIXED
MEDIUMINT 3個字節(jié) FIXED
INT, INTEGER 4個字節(jié) FIXED
BIGINT 8個字節(jié) FIXED
DECIMAL(M,N) >=4字節(jié) FIXED
3. 數(shù)值類型: TINYINT SMALLINT MEDIUMINT INT BIGINT
這幾種數(shù)據(jù)存取方式都是一樣的: 高位優(yōu)先存儲,符號位(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的補碼
---------------------------------
如果是正數(shù),第1位為"0", 直接讀出來即可;
如果是負數(shù),第1位為"1", 則按常規(guī)辦法將值 取反+1.
比如:
原值 原二進制 取反 加1 十進制
-------------------------------------------------------
f6 --> 1111 0110 --> 0000 1001 --> 0000 1010 --> 10
其他幾個類型請讀者舉一反三.
4. 數(shù)值類型: DECIMAL(M,N) 或 DECIMAL(M)
4.1 存儲位計算
最小分配4個字節(jié)空間,比如decimal(4,2),實際用兩個字節(jié)就可以表示.但MYSQL在分配空間時還是用了4個字節(jié).空閑部分用0填充
DECIMAL(M,N),如果9<M<17,至需要5~8個以上字節(jié).如果18<M<36,則會需要8~12個字節(jié).
(這里為什么要這樣算,詳見4.2中的實例解釋)
4.2 如何讀取數(shù)據(jù).
4.2.1 讀取步驟
按照定義,從磁盤讀出該DECEMAL字段的所有數(shù)據(jù)(N位)后:
4.2.1.1 正數(shù),帶小數(shù),DECIMAL(4,2)
0)以1開頭,如果定義為UNSIGNED,則都為1
1)去掉第一位符號位,
2)用小數(shù)將剩余的位數(shù)分開, 前面(M位)是整數(shù)部分,后面(N位)是小數(shù)部分
(在這一步是怎么分M和N的,我們能根據(jù)字段的定義計算出來)
3)去掉小數(shù)點后面(整個字節(jié))為0的情況,
4)將二進制轉換成十進制,即可讀出原值.
(注意,小數(shù)的讀取方法與整數(shù)的方法一樣,按二進制向十進制轉換即可)
4.2.1.2 負數(shù),帶小數(shù) DECIMAL(4,2)
0)以0開頭,
1)去掉第一位符號位,
2)剩余的數(shù)取反+1 ,
3)用小數(shù)將剩余的位數(shù)分開, 前面(M位)是整數(shù)部分,后面(N位)是小數(shù)部分
(在這一步是怎么分M和N的,我們能根據(jù)字段的定義計算出來)
4)去掉小數(shù)點后面(整個字節(jié))為0的情況,
5)將二進制轉換成十進制,即可讀出原值.
(注意,小數(shù)的讀取方法與整數(shù)的方法一樣,按二進制向十進制轉換即可)
4.2.1.3 正數(shù),不帶小數(shù), DECIMAL(N)
0)以1開頭,如果定義為UNSIGNED,則都為1
1)去掉第一位符號位,
2)將剩余的數(shù)位直接按二進制向十進制轉換即可
4.2.1.4 負數(shù),不帶小數(shù), DECIMAL(N)
0)以0開頭
1)去掉第一位符號位,
2)將剩余的數(shù)取反+1
3)按二進制向十進制轉換即可讀到原值
4.2.1.5 超長數(shù)值,如何讀取
當需要表示的數(shù)值超過某個限值后,如果你按以上的方法去讀取數(shù)據(jù),會發(fā)現(xiàn)讀出來的數(shù)值是不對的.
資料寫道:
********************************************************************
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').
********************************************************************
但經(jīng)過測試, 似乎是當數(shù)值<=999999999 時,我們還可以用原來的方法去讀取.
一旦數(shù)值>999999999,我們就需要按CHUNK(4個字節(jié))來讀取.
詳見4.2章節(jié)中的測試實例.
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
------------------------------------------------------------
磁盤數(shù)據(jù) 符號 整數(shù) 小數(shù) 空閑 空閑
我們來看上面的方法進行讀取:
ROW1:
符號位 : 1,正數(shù).
整數(shù)部分: 1000001 = 65
小數(shù)部分: 0
原值 : 65
ROW2:
符號位 : 0,負數(shù)
取反+1 : 1000100 00000000
整數(shù)部分: 1000001 = 65
小數(shù)部分: 0
原值 : -65
ROW3:
符號位 : 1,正數(shù)
整數(shù)部分: 0010111 = 23
小數(shù)部分: 00100010 = 34
原值 : 23.34
ROW4:
符號位 : 0,負數(shù)
取反+1 : 0010111 00100010
整數(shù)部分: 0010111 = 23
小數(shù)部分: 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
------------------------------------------------------------
磁盤數(shù)據(jù) 符號 整數(shù) 小數(shù) 空閑 空閑
注意:符號位都為"1".
整數(shù)部分和小數(shù)部分,該實例與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 --> 10000000 00000000 00000000 00000000 01000001
ROW2: 7f ff ff ff be --> 01111111 11111111 11111111 11111111 10111110
到這里,如果你認真地讀完了4.2.2.1和4.2.2.2小節(jié),那么下面的轉換對你來說將不再是難事了.
正數(shù),去符號位后直接轉換成十進制;
負數(shù),去符號位,剩余取反+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
在這里用了五個字節(jié)來表示DECIMAL(10).關于原數(shù)值,我想大家應該都能看出來了.
0X41 --> 65
0X30d40 --> 20000
4.2.2.5 超長數(shù)值的讀取(>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 --> 10000000 00111011 10011010 11001001 11111111
ROW2: 81 00 00 00 00 --> 10000001 00000000 00000000 00000000 00000000
ROW2: 82 08 ca 6c 00 --> 10000010 00001000 11001010 01101100 00000000
試著用原來的方法將數(shù)據(jù)進行轉換:
ROW1: select conv(000000000111011100110101100100111111111,2,10) ;
--> 999999999 正確
ROW2: select conv(000000100000000000000000000000000000000,2,10) ;
--> 4294967296 與原值不符
ROW3: select conv(000001000001000110010100110110000000000,2,10) ;
--> 8737418240 與原值不符
其實,正如上面所說的,如果數(shù)值超過999999999,那么需要按CHUNK(4個字節(jié))來讀取,并在最后將數(shù)拼起來.
比如我們讀第三行數(shù)據(jù):
從右到左讀:
1)先讀4個字節(jié):00001000 11001010 01101100 00000000 --> 147483648
2)再讀剩余的1個字節(jié):0000010 --> 2
把以上兩個結果拼起來: "2" || "147483648" = "2147483648" 這里才與原值相符
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。