一、行 有哪些格式?
你可以像下面這樣看一下你的MySQL行格式設(shè)置。
其實MySQL的數(shù)據(jù)行有兩種格式,一種就是圖中的 Compact格式,還有一種是Redundant格式。
Compact是一種緊湊的行格式,設(shè)計的初衷就是為了讓一個數(shù)據(jù)頁中可以存放更多的數(shù)據(jù)行。
你品一品,讓一個數(shù)據(jù)頁中可以存放更多的數(shù)據(jù)行是一個多么激動人心的事,MySQL以數(shù)據(jù)頁為單位從磁盤中讀數(shù)據(jù),如果能做到讓一個數(shù)據(jù)頁中有更多的行,那豈不是使用的空間變少了,且整體的效率直線飆升?
官網(wǎng)介紹:Compact能比Redundant格式節(jié)約20%的存儲。
Compact從MySQL5.0引入,MySQL5.1之后,行格式默認(rèn)設(shè)置成 Compact 。所以本文描述的也是Compact格式。
二、緊湊的行格式長啥樣?
你肯定曉得表中有的列允許為null,有的列是變長的varchar類型。
那Compact行格式是如何組織描述這些信息的呢?如下圖:
每部分包含的數(shù)據(jù)可能要比我上面標(biāo)注的1、2、3還要多。
為了給大家更直觀的感受和理解我只是挑了一部分展示給大家看。
三、MySQL單行能存多大體量的數(shù)據(jù)?
在MySQL的設(shè)定中,單行數(shù)據(jù)最大能存儲65535byte的數(shù)據(jù)(注意是byte,而不是字符)
但是當(dāng)你像下面這樣創(chuàng)建一張數(shù)據(jù)表時卻發(fā)生了錯誤:
MySQL不允許創(chuàng)建一個長度為65535byte的列,因為數(shù)據(jù)頁中每一行中都有我們上圖提到的隱藏列。
所以將varchar的長度降低到65532byte即可成功創(chuàng)建該表
注意這里的65535指的是字節(jié),而不是字符。
所以如果你將charset換成utf8這種編碼格式,那varchar(N)中的N其實指的N個字符,而不是N個byte。所以如果你像下面這樣創(chuàng)建表就會報錯。
假如encode=utf8時三個byte表示一個字符。那么65535 / 3 = 21845個字符。
四、Compact格式是如何做到緊湊的?
MySQL每次進(jìn)行隨機(jī)的IO讀
默認(rèn)情況下,數(shù)據(jù)頁的大小為16KB。數(shù)據(jù)頁中存儲著數(shù)行。
那就意味著一個數(shù)據(jù)頁中能存儲越多的數(shù)據(jù)行,MySQL整體的進(jìn)行的IO次數(shù)就越少?性能就越快?
Compact格式的實現(xiàn)思路是:當(dāng)列的類型為VARCHAR、 VARBINARY、 BLOB、TEXT時,該列超過768byte的數(shù)據(jù)放到其他數(shù)據(jù)頁中去。
如下圖:
看到這里來龍去脈是不是很清晰了呢?
MySQL這樣做,有效的防止了單個varchar列或者Text列太大導(dǎo)致單個數(shù)據(jù)頁中存放的行記錄過少而讓IO飆升的窘境且占內(nèi)存的。
五、什么是行溢出?
那什么是行溢出呢?
如果數(shù)據(jù)頁默認(rèn)大小為16KB,換算成byte: 16*1024 = 16384 byte
那你有沒有發(fā)現(xiàn),單頁能存儲的16384byte和單行最大能存儲的 65535byte 差了好幾倍呢?
也就是說,假如你要存儲的數(shù)據(jù)行很大超過了65532byte那么你是寫入不進(jìn)去的。假如你要存儲的單行數(shù)據(jù)小于65535byte但是大于16384byte,這時你可以成功insert,但是一個數(shù)據(jù)頁又存儲不了你插入的數(shù)據(jù)。這時肯定會行溢出!
其實在MySQL的設(shè)定中,發(fā)生行溢出并不是達(dá)到16384byte邊緣才會發(fā)生。
對于varchar、text等類型的行。當(dāng)這種列存儲的長度達(dá)到幾百byte時就會發(fā)生行溢。
六、行 如何溢出?
還是看這張圖:
在MySQL設(shè)定中,當(dāng)varchar列長度達(dá)到768byte后,會將該列的前768byte當(dāng)作當(dāng)作prefix存放在行中,多出來的數(shù)據(jù)溢出存放到溢出頁中,然后通過一個偏移量指針將兩者關(guān)聯(lián)起來,這就是行溢出機(jī)制。
七、思考一個問題
不知道你有沒有想過這樣一個問題:
首先你肯定知道,MySQL使用的是B+Tree的聚簇索引,在這棵B+Tree中非葉子節(jié)點是只存索引不存數(shù)據(jù),葉子節(jié)點中存儲著真實的數(shù)據(jù)。同時葉子結(jié)點指向數(shù)據(jù)頁。
那當(dāng)單行存不下的時候,為啥不存儲在兩個數(shù)據(jù)頁中呢?就像下圖這樣~。
單個節(jié)點存儲下,我用多個節(jié)點存總行吧!說不定這樣我的B+Tee還能變大長高(這其實是錯誤的想法)
這個錯誤的描述對應(yīng)的腦圖如下:
那MySQL不這樣做的原因如下:
MySQL想讓一個數(shù)據(jù)頁中能存放更多的數(shù)據(jù)行,至少也得要存放兩行數(shù)據(jù)。否則就失去了B+Tree的意義。B+Tree也退化成一個低效的鏈表。
你可以品一下這句藍(lán)色的話,他說的每個數(shù)據(jù)頁至少要存放兩行數(shù)據(jù)的意思不是說 數(shù)據(jù)頁不能只存一行。你確確實實可以只往里面寫一行數(shù)據(jù),然后去吃個飯,干點別的。一直讓這個數(shù)據(jù)頁中只有一行數(shù)據(jù)。
這句話的意思是,當(dāng)你往這個數(shù)據(jù)頁中寫入一行數(shù)據(jù)時,即使它很大將達(dá)到了數(shù)據(jù)頁的極限,但是通過行溢出機(jī)制。依然能保證你的下一條數(shù)據(jù)還能寫入到這個數(shù)據(jù)頁中。
正確的腦圖如下:
參考:
https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format.html
https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html
作者: 賜我白日夢
出處:https://www.cnblogs.com/ZhuChangwu/p/14035330.html
以上就是詳解MySQL的數(shù)據(jù)行和行溢出機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于MySQL 數(shù)據(jù)行和行溢出的資料請關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- PHP使用mysql_fetch_row查詢獲得數(shù)據(jù)行列表的方法
- 5個MySQL GUI工具推薦,幫助你進(jìn)行數(shù)據(jù)庫管理
- 簡單了解操作mysql數(shù)據(jù)庫的命令行神器mycli
- 為什么說MySQL單表數(shù)據(jù)不要超過500萬行
- php使用mysqli和pdo擴(kuò)展,測試對比mysql數(shù)據(jù)庫的執(zhí)行效率完整示例
- MySQL執(zhí)行update語句和原數(shù)據(jù)相同會再次執(zhí)行嗎
- IDEA使用properties配置文件進(jìn)行mysql數(shù)據(jù)庫連接的教程圖解
- mysql如何利用binlog進(jìn)行數(shù)據(jù)恢復(fù)詳解
- MySQL數(shù)據(jù)庫Event定時執(zhí)行任務(wù)詳解
- 解決Windows10下mysql5.5數(shù)據(jù)庫命令行中文亂碼問題
- Java對MySQL數(shù)據(jù)庫進(jìn)行連接、查詢和修改操作方法