Mysql原始碼分析(7): MYISAM的資料檔案處理–轉載

來源:互聯網
上載者:User
文章目錄
  • 基本知識
  • record處理介面
  • Fixed類型
好久沒寫分析文章了,一個是比較忙,另一個是因為餘下的內容都是硬骨頭,需要花時間慢慢理解。剩下的比較有意思的內容有:
  • select語句的執行和最佳化過程。大家關心資料庫的查詢效能,主要是對著部分比較感興趣,特別是其中的查詢最佳化部分。
  • Mysql的replication。Mysql的master/slave架構是大部分使用mysql的高效能網站架構的不二選擇,replication則是這個架構的基礎。
  • 具體資料庫引擎的實現。這部分也是很多關心mysql效能的人會比較感興趣的部分,不過這個工作比較複雜,特別是流行的innodb,這個工作量尤其浩大,而且難度頗高。其中涉及到transaction的部分,也是特別複雜。
另外,我發現我寫的文章被一些地方轉摘了,感謝大家的閱讀,但是我也希望轉摘要註明出處,至少給個原文連結吧,也不枉我幸苦一場。

今天主要寫寫Myisam的資料檔案的處理。

Myisam是最早實現的Mysql資料庫引擎,也是人們心中的效能最好的引擎(雖然不是功能最強的,沒辦法,現實往往要求效能和功能做權衡)。這裡選擇 分析它,主要原因是其實現還算比較簡單明了,而且最近我對資料檔案的格式比較感興趣,特別是變長資料的處理。要注意的是本文不會介紹myisam的索引文 件格式。
基本知識

對於每一個以Myisam做資料引擎的表,在<%data_dir%>/<database>目錄下會有如下幾個檔案來儲存其相關資訊:

  • .frm檔案。 這個檔案是跨引擎的,描述了該表的元資訊,其中最重要的是表定義和表的資料庫引擎。
  • .MYD檔案。這是我們要看的重點檔案,包含了資料庫record資訊,就是資料庫中的每個行。
  • .MYI檔案。索引檔案,用來加速尋找。

而對於MYD中的每個record,可以是fixed,dynamic以及packed三種類型之一。fixed表示record的大小是固定的,沒有VARCHAR, blob之類的東東。dynamic則剛好相反,有變長資料類型。packed類型是通過myisampack處理過的record。參見:http://dev.mysql.com/doc/refman/5.1/en/myisam-table-formats.html。 需要注意的是record類型是針對錶的設定,而不是對每個column的設定。
record處理介面

record的類型是表層級的設定,所以在一個表被開啟的時候,myisam會檢查中繼資料的選項,看該表的record是什麼類型,然後設定對應的處理函 數,具體處理在storage/myisam/mi_open.c的mi_setup_functions中,我們看其中的一個片段:

746 void mi_setup_functions(register MYISAM_SHARE *share)747 {   ....759 else if (share->options & HA_OPTION_PACK_RECORD)760 {761 share->read_record=_mi_read_dynamic_record;762 share->read_rnd=_mi_read_rnd_dynamic_record;763 share->delete_record=_mi_delete_dynamic_record;764 share->compare_record=_mi_cmp_dynamic_record;765 share->compare_unique=_mi_cmp_dynamic_unique;766 share->calc_checksum= mi_checksum;767768 /* add bits used to pack data to pack_reclength for faster allocation */769 share->base.pack_reclength+= share->base.pack_bits;770 if (share->base.blobs)771 {772 share->update_record=_mi_update_blob_record;773 share->write_record=_mi_write_blob_record;774 }775 else776 {777 share->write_record=_mi_write_dynamic_record;778 share->update_record=_mi_update_dynamic_record;779 }780 }   ...

這是針對pack類型的處理函數設定。設定了 share結構中的一堆函數介面。順便說一句,這種方式是C語言編程中常用的實現”多態“的辦法:申明函數介面,動態設定介面實現,思想上和C++的動態 綁定是一致的。這段代碼對於dynamic類型的表的record處理函數做了設定。比較有趣的是HA_OPTION_PACK_RECORD用來指定 dynamic類型。 看到這些函數名大家可以猜想出他們都是幹嘛的,下面主要看看fixed類型和dynamic類型的具體處理。

Fixed類型顧名思義,fixed類型的表中的所有欄位都是定長的,不能出現TEXT, VARCHAR之類的東東。這種嚴格限制帶來的好處就是更快更直接的資料record操作,想想也知道,每個資料都是定長的,在檔案操作的時候多方便啊。
看看一個資料的函數_mi_write_static_record,它在mi_statrec.c中,所有對於fixed record的操作的實現都定義在這個檔案中。21 int _mi_write_static_record(MI_INFO *info, const uchar *record)22 {   ...24 if (info->s->state.dellink != HA_OFFSET_ERROR &&25 !info->append_insert_at_end)26 {   檢查dellink中是否有record。dellink是所有被刪除的資料構成的鏈表。當一個record被刪除的時候,它所佔的檔案大小不是被馬上釋放,而是被放入dellink中,等候下次使用。27 my_off_t filepos=info->s->state.dellink;   讀入dellink所指向的資料空間的資訊。33 更新dellink,將使用了的資料空間移除。   將record寫入找到的已刪除的資料的空間中。40 }41 else42 {43 檢查資料檔案是否過大。49 如果使用的寫緩衝,則寫入寫緩衝。   將新資料寫入檔案最後。   更新中繼資料。   ...86 }

因為所有的資料都是一樣大小,處理起來很簡單。特別是當一個資料被刪除的時候,它所佔的空間被放入一個回收鏈表中,下次要寫入新資料的時候,如果回收鏈表不為空白,直接從其中找一個寫入新資料即可,不用分配新的儲存空間。 Fixed類型的其他處理也都很簡單,這裡不再多 說了。需要提出的是,不管用的什麼類型的資料,當資料被刪除的時候,其所佔的空間並不是馬上被釋放的,那樣操作代價太大,要把該資料後面的所有資料向前移 位,肯定無法忍受。一般的做法都是將這些空間用鏈表穿起來,供以後使用,所以資料檔案一般是不會主動縮小的.....即使是innodb也是這樣。 Dynamic類型

Dynamic類型是相對於fixed的類型而言,這種類型可以容忍變長資料類型的存在。隨之而來的是更複雜的資料檔案的操作。Dynamic類型中被刪 除的資料區塊也不是馬上被釋放,也被鏈表連起來。下次要寫入新資料的時候,還是優先從這個鏈表中找。不同於fixed類型的處理在於新來的資料和鏈表中的空 間的大小可能不一樣。如果新資料大了,就會找好幾個空餘空間,將資料分散於多個資料區塊中,如果新資料小了,則會將空餘資料區塊分成兩個,一個寫入新資料,一 個還是放在空餘鏈表中供後來者使用。 看一下mi_dynrec.c中的write_dynamic_record函數。320 static int write_dynamic_record(MI_INFO *info, const uchar *record,321 ulong reclength)322 {   檢查是否有足夠的空間來存放新資料,空間滿了返回錯誤。351352 do353 {   // 找一個可以寫入資料的地方。注意這裡是在一個迴圈裡面,也就是說每次找到的   // 空間不一定能夠寫入整個資料,只能寫入部分的話,剩下的還要繼續找地方寫。354 if (_mi_find_writepos(info,reclength,&filepos,&length))355 goto err;   // 寫入能夠放入找到的空間的資料。356 if (_mi_write_part_record(info,filepos,length,357 (info->append_insert_at_end ?358 HA_OFFSET_ERROR : info->s->state.dellink),359 (uchar**) &record,&reclength,&flag))360 goto err;361 } while (reclength);   ...   }其中的迴圈說明了一切,很有可能一個資料會被分成幾塊兒,寫到不同的地方,但是他們合起來才構成了整個資料。 再看_mi_find_writepos。371 static int _mi_find_writepos(MI_INFO *info,372 ulong reclength, /* record length */373 my_off_t *filepos, /* Return file pos */374 ulong *length) /* length of block at filepos */375 {376 MI_BLOCK_INFO block_info;   ...   // 先檢查dellink中是否有空餘的空間。380 if (info->s->state.dellink != HA_OFFSET_ERROR &&381 !info->append_insert_at_end)382 {383 /* Deleted blocks exists; Get last used block */   存在空餘空間,那就把鏈表中的頭找出來,把其中的空間用來寫入新資料。   將這塊空間的描述返回給調用者。   ....398 }399 else400 {401 /* No deleted blocks; Allocate a new block */   沒有已刪除的空間,那就在資料檔案的最後分配空間,並返回給調用者。421 }   ...

   }如果有已刪除的空間的話,那就直接把鏈表頭描述的 空間返回。這個演算法很簡單,但是我覺得這樣簡單的演算法可能會趙成一些問題,比如儲存的片段化,一塊兒大空間被切的越來越小,到後來寫入一個資料要使用好幾 個空間。這些問題在作業系統的記憶體管理中也同樣存在,所以產生了大量的記憶體管理演算法,這裡也應該可以借用吧。 具體的寫入是在_mi_write_part_record中完成的。這個函數比較長,我就直接簡寫如下了。int _mi_write_part_record(MI_INFO *info,   my_off_t filepos, /* points at empty block */   ulong length, /* length of block */   my_off_t next_filepos,/* Next empty block */   uchar **record, /* pointer to record ptr */   ulong *reclength, /* length of *record */   int *flag) /* *flag == 0 if header */{   如果給出的空間空間大於資料長度的話,計算填完資料後剩餘的空間。   如果空間剛好,準備一些中繼資料。   如果空間太小,則找到下一個寫入空間的位置(要麼是下一個dellink,要麼是檔案末尾),並準備這些中繼資料。如果是第一部分的資料的話,要寫入更多的資訊。   如果空間太大,有剩餘空間的話,先看這個空間能否與和下一個空閑空間串連起來形成一個大空間,如果能的話就合并。將其相關的中繼資料,比如空間的位置,大小之類的,準備好。   開始寫資料羅,如果啟用了寫緩衝,則寫入緩衝,否則寫入找出來的空間。   更新dellink的相關資訊。}

邏輯很清楚,主要是要處理空間過大或者過小帶來的複雜性。 好了,到了這裡大部分的處理都很清楚了,還是很直 接的。剩下的就是在刪除一個資料的時候,將其所佔的空間放到dellink中,要注意的是,如果其資料區塊可以和dellink中的其他資料區塊合并,合并操 作也是在刪除資料的操作中調用的,而且合并出來的資料區塊還可能和其他資料區塊繼續合并。有興趣的自己看看delete_dynamic_record吧,我 就不寫了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.