湯敏麗
(凱里學(xué)院,貴州 凱里 556011)
基于MySQL數(shù)據(jù)庫(kù)的物理存儲(chǔ)格式的研究與解析
湯敏麗
(凱里學(xué)院,貴州 凱里 556011)
M ySQL數(shù)據(jù)庫(kù)是一個(gè)開(kāi)源的數(shù)據(jù)庫(kù).M ySQL以其小巧靈活著稱,其內(nèi)部代碼都是開(kāi)源的,使用M ySQL不僅僅可以節(jié)約開(kāi)發(fā)成本,而且還可以從開(kāi)源的代碼中學(xué)到很多開(kāi)發(fā)精髓.為了更好的了解mysql的物理存儲(chǔ)結(jié)構(gòu),我們直接研究了M ySQL數(shù)據(jù)庫(kù)的內(nèi)核代碼.本文主要是講解MySQL數(shù)據(jù)庫(kù)是物理存儲(chǔ)格式以及如何進(jìn)行數(shù)據(jù)解析.
mysql;物理存儲(chǔ)格式;解析
隨著計(jì)算機(jī)開(kāi)源技術(shù)的不斷發(fā)展,目前開(kāi)發(fā)者越來(lái)越熱衷于使用開(kāi)源軟件.基于開(kāi)源的軟件的實(shí)現(xiàn)的所有代碼全部對(duì)外公開(kāi),且所有人員均可對(duì)開(kāi)源軟件進(jìn)行自定義的修改.這無(wú)疑是軟件開(kāi)發(fā)界的福音.本文重點(diǎn)研究的MySQL數(shù)據(jù)庫(kù)也是開(kāi)源的數(shù)據(jù)庫(kù)軟件.同樣,它的所有代碼也都是開(kāi)源的.
MySQL數(shù)據(jù)庫(kù)是一種關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng).它不是將所有數(shù)據(jù)存放到一個(gè)大倉(cāng)庫(kù)內(nèi),而是將具有一定意義的數(shù)據(jù)相對(duì)獨(dú)立的存放到不同的表中.而表與表之間建立關(guān)聯(lián)關(guān)系.它由于其體積小,速度快,成本低等特點(diǎn),成為很多中小型網(wǎng)站的絕佳選擇.MySQL是使用C/C++編寫的,并使用了多種編譯器進(jìn)行測(cè)試,保證源代碼的可移植性.還可以處理?yè)碛猩锨f(wàn)條記錄大型數(shù)據(jù)庫(kù).
MySQL數(shù)據(jù)庫(kù)的一個(gè)顯著的特點(diǎn)就是插件式的表存儲(chǔ)引擎.它的好處是:每個(gè)存儲(chǔ)引擎都有各自的特點(diǎn),能夠根據(jù)具體的應(yīng)用建立不同的存儲(chǔ)引擎表.在windows下,默認(rèn)使用InnoDB的數(shù)據(jù)存儲(chǔ)引擎.如果你的表只有*.frm文件,則存儲(chǔ)引擎是innodb.同樣,*.frm這個(gè)文件也是表定義文件,數(shù)據(jù)信息和索引信息放在ibdata1文件里.Ibdata1是InnoDB存儲(chǔ)引擎默認(rèn)情況下的共享表空間文件,即所有的數(shù)據(jù)都放在這個(gè)表空間內(nèi).本文主要是針對(duì)MyISAM存儲(chǔ)引擎做解析.MySQL的體系結(jié)構(gòu)圖如圖1所示.
圖1 MySQL的體系結(jié)構(gòu)圖
安裝MySQL.打開(kāi)mysql后輸入密碼.執(zhí)行如下的語(yǔ)句:
創(chuàng)建數(shù)據(jù)庫(kù)maqianli
mysql>Create database maqianli;
更改數(shù)據(jù)庫(kù)
mysql>Use maqianli;
創(chuàng)建表
mysql>create table mytest(t1 varchar(10),t2 varchar(10),t3 char(10),t4 varchar(10));
往表中插入數(shù)據(jù)
mysql>insert into mytest values('a','bb','bb','cc');
mysql>insert into mytest values('d','ee','ee','fff');
這樣我們會(huì)發(fā)現(xiàn)在MySQL的安裝路徑下data目錄下生成了一個(gè)maqianli的文件夾,mysql文件夾是系統(tǒng)安裝時(shí)默認(rèn)生成的.在maqianli文件夾下有一個(gè)mytest.frm的文件.這個(gè)文件中記錄了mytest表結(jié)構(gòu)定義的信息.和data同層的有個(gè)ibdata1文件,里面記錄了表數(shù)據(jù)信息.我們生成的文件默認(rèn)是InnoDB存儲(chǔ)引擎生成的,我們可以將其改變?yōu)镸yISAM存儲(chǔ)引擎.用如下語(yǔ)句
mysql>alter table mytest engine=myisam;
我們發(fā)現(xiàn)在MyISAM存儲(chǔ)引擎下,會(huì)生成如下三個(gè)文件.Frm擴(kuò)展名結(jié)尾的是表定義文件.Myd擴(kuò)展名結(jié)尾的是數(shù)據(jù)文件,myi擴(kuò)展名結(jié)尾的是索引文件.
圖2 MyISAM存儲(chǔ)引擎生成的文件
3.2.1 下載MySQL源碼.下載地址是:http://www.mysql.com/downloads/mysql/文件名是mysql-5.5.12.tar.gz.
3.2.2 生成工程文件
安裝CMake軟件,下載地址是:http://www.cmake.org.然后安裝 Bison:下載地址是 http://gnuwin32.sourceforge.net/packages/bison.htm.安裝完成后,運(yùn)行CMake.第一個(gè)edit里面選擇源文件目錄,第二個(gè)選擇要生成的目錄.下面的“Configur“e按鈕可以選擇你要生成的編譯環(huán)境的版本,我們選擇VC6作為我們的開(kāi)發(fā)環(huán)境,然后點(diǎn)擊“Generate”就開(kāi)始生成工程文件.這樣就生成了MySQL.dsw的工程,我們打開(kāi)這個(gè)工程,然后搜索讀取frm文件的主要內(nèi)容及其其他相關(guān)代碼.
MyISAM存儲(chǔ)引擎一個(gè)表生成了3個(gè)文件,擴(kuò)展名分別是.frm,.myd,.myi.Frm擴(kuò)展名結(jié)尾的是表定義文件.Myd擴(kuò)展名結(jié)尾的是數(shù)據(jù)文件,myi擴(kuò)展名結(jié)尾的是索引文件.下面我們一一介紹三個(gè)文件的文件格式.
在源碼中我們能夠找到FRM創(chuàng)建文件的代碼,sql/table.cc,create_frm()里記錄了如何創(chuàng)建一個(gè)FRM文件的詳細(xì)過(guò)程.open_table_def函數(shù)是讀取frm表定義信息的函數(shù).其中調(diào)用了open_binary_frm函數(shù)是其主要的實(shí)現(xiàn)關(guān)鍵.該函數(shù)在sql able.cc文件里.函數(shù)原型如下:static int open_binary_frm(THD*thd,TABLE_SHARE*share,uchar*head,File file).在sql able.cc創(chuàng)建frm的文件的函數(shù)create_frm.函數(shù)原型如下:
create_frm(THD*thd,const char*name,const char*db,const char *table, uint reclength, uchar *fileinfo,HA_CREATE_INFO*create_info,uint keys,KEY*key_info)
下面我們羅列出FRM文件格式.由于文件中每個(gè)字節(jié)所代表的含義很多.所以我們只羅列關(guān)鍵字節(jié)含義.
表1 FRM文件格式
由上表我們可以看出,F(xiàn)RM文件里面存儲(chǔ)了MySQL版本,存儲(chǔ)引擎名,列等等信息.由于我們只是讀取表中字段,我們只需要關(guān)注相關(guān)信息即可.
表列信息:由表可以發(fā)現(xiàn),從2152開(kāi)始記錄了表列頭信息.根據(jù)我們對(duì)照生成frm的原始文件和上表格式,發(fā)現(xiàn)2152記錄的是第一個(gè)列名的大小,緊接著記錄的是列名,其次空了三個(gè)字段又是列名大小+列名.如下所示:
圖3 MYTEST.FRM文件二進(jìn)制格式-列信息
“06”表示的是sname的長(zhǎng)度,后面的“05”表示的是ssex的長(zhǎng)度.圖3中的2102處記錄了列數(shù).有了列數(shù),有了列信息,我們就很容易得讀出表的列信息.
表行信息:圖3中2168字節(jié)處記錄了表行的字段類型,由于一個(gè)表可能有很多列.每列的類型都有可能不同,所以結(jié)合圖3,讀源碼,和我們生成的原始文件做了如下分析:
圖4 MYTEST.FRM文件二進(jìn)制格式-行信息
紅色標(biāo)記的是記錄的字段大小信息,藍(lán)色標(biāo)記記錄的是字段類型信息.我們創(chuàng)建表的時(shí)候sql語(yǔ)句是:create table info(sname char(3),ssex char(2),sclass char(3));可以看出sname是char型,大小為3.ssex是 char型,大小為 2,sclass是char型,大小為3.和我們剛分析的一致.
綜上所述,我們知道的信息有:列數(shù),列名,字段大小,字段類型.
MYI文件格式比較復(fù)雜,下面是一部分myi格式的信息,我們?cè)谧x文件的時(shí)候只使用了行數(shù)這個(gè)信息,讀myi文件的代碼我們直接用的是mysql的源碼:
我們讀源碼,得知在0033字節(jié)記錄了行數(shù)信息.源碼中保存在了MI_STATUS_INFO結(jié)構(gòu)體中的records成員里.MySQL讀寫MYI文件的函數(shù)在storagemyisammi_open.c文件里,函數(shù)原型分別是:
uchar*mi_state_info_read(uchar*ptr,MI_STATE_INFO*state);// 讀
uint mi_state_info_write(File file,MI_STATE_INFO*state,uint pWrite);// 寫
由于任務(wù)要求只讀出表字段便可,我們對(duì)這個(gè)文件的其他key信息沒(méi)有關(guān)注.僅僅通過(guò)MYI文件得到了行數(shù)信息.
表2 MYI文件格式
得到了上面所有的行列信息,下面我們開(kāi)始根據(jù)這些信息,找到字段值信息.Myd文件可以分為固定大小字段格式和可變大小字段格式,目前我們只研究了固定格式的.可變大小字段格式的需要根據(jù)總大小和未使用大小信息相減得到所用的大小來(lái)讀取字段值.
由于myd需要根據(jù)數(shù)據(jù)類型的格式來(lái)確定每個(gè)字節(jié)的信息.下表我們只是羅列出第一列為int型,第二列為char型的格式.其他格式類似:
表3 myd文件格式
MySQL中支持很多種類型,這些類型在include/mysql_com.h里枚舉enum_field_types定義.每種類型所占用的字節(jié)數(shù)不同,int為4位,char為1位.Float為4位,double為8位等等.
我們讀取MYD文件的時(shí)候,跳過(guò)第一字節(jié)后就開(kāi)始記錄字段值信息了.如果為int型,我們讀4個(gè)字節(jié)的信息,如果為char型,我們讀?。?*字段大小)字節(jié)個(gè)信息.
本文我們主要分析了MySQL數(shù)據(jù)庫(kù)的物理存儲(chǔ)格式,由于MySQL是可插入的存儲(chǔ)引擎方式,本文重點(diǎn)研究了MyISAM存儲(chǔ)引擎的物理存儲(chǔ)格式.其他存儲(chǔ)引擎物理存儲(chǔ)格式的研究與本文方法類似,都是需要查看MySQL的開(kāi)源代碼和相關(guān)文檔介紹.
〔1〕Baron Scbwartz,王小東,等.高性能 M ySQL(High Performance M ySQL).電子工業(yè)出版社,2010.
〔2〕張萍.M yISAM存儲(chǔ)引擎的分析與改進(jìn)[A].全國(guó)第20屆計(jì)算機(jī)技術(shù)與應(yīng)用學(xué)術(shù)會(huì)議(CACIS?2009)暨全國(guó)第1屆安全關(guān)鍵技術(shù)與應(yīng)用學(xué)術(shù)會(huì)議論文集(下冊(cè))[C].2009.
〔3〕鮑麗春.可插式數(shù)據(jù)存儲(chǔ)引擎:M ySQL走向企業(yè)級(jí)的保障[N].計(jì)算機(jī)世界,2007.
〔4〕姜承堯.MySQL技術(shù)內(nèi)幕-InnoDB存儲(chǔ)引擎.機(jī)械工業(yè)出版社,2011.
〔5〕顧治華,忽朝儉.MySQL存儲(chǔ)引擎與數(shù)據(jù)庫(kù)性能[J].計(jì)算機(jī)時(shí)代,2006(10).
〔6〕M ichael Kofler, 楊曉云, 等.MySQL5權(quán)威指南(The Definitive Guide to M ySQL5).人民郵電出版社,2006.
〔7〕馬永成,肖詩(shī)斌,王弘蔚,施水才.M ySql嵌入式存儲(chǔ)引擎的研究和實(shí)現(xiàn)[A].第三屆全國(guó)信息檢索與內(nèi)容安全學(xué)術(shù)會(huì)議論文集[C].2007.
TP3-05
A
1673-260X(2012)07-0028-03