mysql的varchar大字段性能研究

咱們知道,innodb的一個頁是16K(16*1024=16384字節),若是一條記錄佔的字節數大於16K,意味着一個頁沒法裝下一條記錄,這種狀況下mysql是如何處理的呢?mysql

  在回答這個問題以前咱們先來作一個實驗:sql

  咱們建立了兩張表,分別是T1和T2,T1和T2惟一的區別是在於b字段一個是varchar(8094),另外一個是varchar(8095),而後咱們有一個T1_test.sql文件,該文件包含有10W行「insert into T1 values(1,repeat('a',8094));」條sql語句,咱們導入到表裏花費了4分24秒。工具

  接着咱們把T2_test.sql導入T2表中(T2.test.sql一樣也包含了10W行相似的sql語句),花費了9分58秒!google

  咱們再來看這兩個表文件的空間佔用狀況(本實例開啓了innodb_file_per_talbe):code

  能夠看到T1表佔用804M,T2表佔用空間1.9G,空間及時間差別均超過2倍。blog

  爲何相差一個字符時間和空間相差會如此巨大呢?下面咱們一塊兒剖析下。索引

  在innodb存儲引擎裏,將一條記錄中的某些數據存儲在真正的數據頁面以外稱之爲行溢出數據,通常認爲blob、text這類的大對像列的存儲會把數據存放在數據頁面以外。但從上述咱們的實驗看出,除了blob、text這類大對像列之外,varchar類型彷佛也會採用行溢出的方法來存儲數據。get

  Innodb存儲引擎表是索引組織的,即B+樹的結構,所以每一個頁中至少應該有兩個行記錄(不然失去了B+樹的意義,變成鏈表了),若是頁中只能存放下一條記錄,那麼InnoDB存儲引擎會自動將行數據存放到溢出頁中,以使每一個頁最少能存放兩個行記錄或以上。innodb

  下面藉助姜承堯先生寫的py_innodb_page_info工具來證明T2發生了行溢出(點擊這裏可取得該工具源代碼table

  爲了更清晰的分析緣由,下面咱們分別建立T1_1和T2_1表,其b字段也相差1字符,而後分別往這兩個表插入一條記錄,以下圖所示:

  

  此時咱們經過py_innodb_page_info工具分析T1_1表的狀況

上圖說明表T1_1只包含了一個B-tree,咱們再看看T2_1的狀況:

   咱們看到T2_1表比T1_1表多了一頁「Uncompressed BLOB Page」的頁,這也充分說明了插到T2_1個的記錄分了兩頁存儲,其中一頁是BLOB頁。

  在上述的實驗中,咱們故意採起了兩個字段,一個字段是4字節的int,另外一個字段是varchar(8094),二者加起來即8098,也就說,當一個表的字段總大小數大於8098時,插入一條記錄即會分裂成兩頁存儲,故不管時間仍是空間方面都大打折扣,有興趣的讀者可嘗試下用一個或多個字段大小總和<=8098及>8098來作對比。

  你們在實驗過程當中要注意一點的是,當varchar小於255時,會額外用1個字節來記錄該記錄的實際長度,當varchar大於255時會用2個字節,由於時使用多個變長字段實驗時,要注意其總大小要加上該空間。例如:「create table A1(a int, b varchar(2000), c varchar(3000), d varchar(3090));」那麼此時的臨界值就是4+2000+3000+3090=8090,由於相對於咱們上述的實驗,A1這個表多了兩個大於255的varchar字段,所以須要額外的2+2=4字節來記錄變長字段。

相關文章
相關標籤/搜索