Myisam 靜態格式資料儲存結構

Steven1981發表於2009-03-07
Myisam 靜態格式 資料的物理儲存 行header 內部分析[@more@]
1. 從簡單的例子開始
1.1 建立測試資料
drop table if exists heyf_5 ;
create table heyf_5 (id int , name char(10),addr char(20)) engine myisam DEFAULT CHARSET=latin1;
insert into heyf_5 values (12,'hyf','street-1') ,(13,'steven','street-2') ;
system hexdump /opt/mysql/data/test/heyf_5.MYD
------------------------------------------------
0000000 0cf1 0000 6800 6679 2020 2020 2020 7320
0000010 7274 6565 2d74 2031 2020 2020 2020 2020
0000020 2020 f120 000d 0000 7473 7665 6e65 2020
0000030 2020 7473 6572 7465 322d 2020 2020 2020
0000040 2020 2020 2020
-----------------------------------------------


--由於我們這一節討論的是靜態格式,我們這裡取的資料型別都是固定長度的.
1.2 開始讀取資料
--根據我們所定義的資料特徵,我們能容易地從資料中分出各行:
ROW1: 0cf1 0000 6800 6679 2020 2020 2020 7320 7274 6565 2d74 2031 2020 2020 2020 2020 2020 20
ROW2: f1 000d 0000 7473 7665 6e65 2020 2020 7473 6572 7465 322d 2020 2020 2020 2020 2020 2020
我們拿第一行資料來分析:
由於資料儲存在硬碟裡時,雙位元組是低位先儲存,高位後儲存.所以我們讀資料的時候要反過來一下:
ROW1: f1 0c 00 00 00 68 79 66 20 20 20 20 20 20 20 73 74 72 65 65 74 2d 31 20 ... 20
其中: -----------------------------------------------------
f1 : Header (0>非NULL,1>NULL),
在這裡 1111 0001 ,其中三個"0"表示三個可空欄位,並且沒有為NULL的欄位.

--下面開始就是實際的值
0c 00 00 00 : COLUMN ID INT , 4個位元組,在這裡表示12.
68 79 66 20 20 20 20 20 20 20 : COLUMN name char(10) 20個位元組 ,這裡十六進位制轉換成字元剛好是"hyf",其它填空.
73 74 72 65 65 74 2d 31 20 ... 20 : COLUMN addr char(20) ,20個位元組
-----------------------------------------------------
有興趣的同學們同樣可以用同樣的方法分析一下ROW2的資料.
由於固定格式的資料,每個欄位的長度都是固定的,所以讀取資料的時候特別容易計算欄位的長度和行的長度.

2. 如果欄位的值為NULL (行Header和欄位值都發生變化)
2.1 建立測試資料
基於上面例子的資料,我們將第一行第三個欄位的資料更新為空:
update heyf_5 set addr = null where id=12 ;
system hexdump /opt/mysql/data/test/heyf_5.MYD ;
0000000 0cf9 0000 6800 6679 2020 2020 2020 2020
0000010 2020 2020 2020 2020 2020 2020 2020 2020
0000020 2020 f120 000d 0000 7473 7665 6e65 2020
0000030 2020 7473 6572 7465 322d 2020 2020 2020
0000040 2020 2020 2020
我們取出第一行的資料來看:
ROW1:0cf9 0000 6800 6679 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 20
轉換一下:
f9 0c 00 00 00 68 79 66 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
其中:
-------------------------------------------
f9 : 標誌位發生了變化: 1111 1001 ,其中的"100"表明第三個欄位為NULL.
0c 00 00 00 : 第1個欄位未發生變化
68 79 66 20 20 20 20 20 20 20 : 第2個欄位未發生變化
20 ....... 20 : 第3個欄位都被置為了空.
-------------------------------------------
3. 如果欄位型別為: NOT NULL
drop table if exists heyf_5 ;
create table heyf_5 (id int not null, name char(10) not null ,addr char(20) not null) engine myisam DEFAULT CHARSET=latin1;
insert into heyf_5 values (12,'hyf','street-1') ,(13,'steven','street-2') ;
system hexdump /opt/mysql/data/test/heyf_5.MYD
0000000 0cff 0000 6800 6679 2020 2020 2020 7320
0000010 7274 6565 2d74 2031 2020 2020 2020 2020
0000020 2020 ff20 000d 0000 7473 7665 6e65 2020
0000030 2020 7473 6572 7465 322d 2020 2020 2020
0000040 2020 2020 2020
對比1.1的測試資料,Header位發生了變化.
1111 0001 --&gt 1111 1111
查資料瞭解到:
固定格式行的Header,是用來標識那些可空欄位的實際值是否為NULL,如果是NULL,則填1.否則填0.
如果表中沒有"可NULL"欄位,那麼header="ff"
Header長度= (1 + number of NULL columns + 7) / 8 bytes

4. 如果行被刪除了
繼續3的例子,我們刪除第一行資料:
delete from heyf_5 where id=12;
system hexdump /opt/mysql/data/test/heyf_5.MYD
0000000 ff00 ffff ffff 66ff 2020 2020 2020 7320
0000010 7274 6565 2d74 2031 2020 2020 2020 2020
0000020 2020 ff20 000d 0000 7473 7665 6e65 2020
0000030 2020 7473 6572 7465 322d 2020 2020 2020
0000040 2020 2020 2020
我們發現header的值變成了"00",這就是一個行被DELETE的標誌.
但在我們同時注意到,第一行的資料,只有緊跟著Header後面6個位元組被置成了'ff',其它資料沒有變.
疑問1: 在這裡為什麼只置6個位元組? 為什麼需要置這6個位元組,光有header不能識別嗎?

5. 被刪除後,空間重複使用
繼續4的例子,
insert into heyf_5 values (23,'aaa','bbbb'),(34,'ccc','ddddd');
system hexdump /opt/mysql/data/test/heyf_5.MYD
0000000 17ff 0000 6100 6161 2020 2020 2020 6220
0000010 6262 2062 2020 2020 2020 2020 2020 2020
0000020 2020
ff20 000d 0000 7473 7665 6e65 2020
0000030 2020 7473 6572 7465 322d 2020 2020 2020
0000040 2020 2020 2020
22ff 0000 6300 6363 2020
0000050 2020 2020 6420 6464 6464 2020 2020 2020
0000060 2020 2020 2020 2020 0020
在這裡我們看到了,被刪除的空間馬上得到了填充.
疑問2: MYSQL是怎麼知道這行是可重複使用的,總不會每次INSERT的時候都去全表掃描吧?

6. 小結
透過上面的例項分析,我們對MYISAM這種引擎的固定長度資料儲存作了一個的瞭解.
(同時也留下了兩個疑問,有待於進一步的深入)
6.1 行組成
固定長度的行格式: 行Header + 資料部分

6.2 行的長度
行header的長度=(1 + number of NULL columns + 7) / 8 bytes
資料部分長度根據使用者的定義計算
6.3 行header的作用
在固定格式的行中,行header主要是用來標識
1) 該行是否被刪除,如果行被刪除會被置為"00"
2) 該行中"可NULL"欄位的實際值是否為NULL,(0>NOT NULL,1> NULL)

6.4 行資料部分的讀取
在行header後面就是資料部分,
所有欄位是根據使用者的定義順序來儲存的(記錄在.FRM檔案中).而且每個欄位的長度都是固定的.所以讀取應該相當容易.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/703656/viewspace-1018253/,如需轉載,請註明出處,否則將追究法律責任。

相關文章