最近工作的時(shí)候突然想到一個(gè)關(guān)于大對(duì)象存儲(chǔ)的問題。先看看這個(gè)問題的背景。
背景1:在mysql數(shù)據(jù)庫(innodb引擎)中,我們有這樣的業(yè)務(wù)場(chǎng)景,在一個(gè)表(下面我們稱為tmp表)中有一個(gè)字段(我們稱為describe字段)可能存儲(chǔ)的內(nèi)容會(huì)特別的大,假設(shè)describe字段的業(yè)務(wù)大小上限為64KB,使用TEXT類型來存儲(chǔ)(文章最下方有字段參考)。
背景2:我們都知道innodb把所有的字段都存儲(chǔ)在聚簇索引的葉子節(jié)點(diǎn)上,而在數(shù)據(jù)庫的存儲(chǔ)設(shè)計(jì)中,innodb的一個(gè)page(默認(rèn)為16K)是希望能存儲(chǔ)多個(gè)葉子節(jié)點(diǎn),這樣在讀一個(gè)page頁的時(shí)候能讀到更多的葉子節(jié)點(diǎn),減少查詢的磁盤io。
那么問題來了:
那么tmp表中的describe字段大小都一靜超過了16k了,一個(gè)page頁已經(jīng)存儲(chǔ)不下了,innodb是怎么解決這個(gè)問題的呢?**
innodb是不是這么干的呢?
猜測(cè)1:是不是會(huì)擴(kuò)展一個(gè)page的大小或者說把兩個(gè)page頁當(dāng)做一個(gè)page頁。
猜測(cè)2:會(huì)不會(huì)大字段就不放在葉子節(jié)點(diǎn)所在的頁了,而是單獨(dú)存儲(chǔ)了。
好吧,下面就是通過查找資料來驗(yàn)證自己的猜測(cè)了。
問題探索
我們先來看一個(gè)概念。
數(shù)據(jù)行溢出: Innodb會(huì)將一條記錄中的某些數(shù)據(jù)存儲(chǔ)在真正的數(shù)據(jù)page之外
它的物理存儲(chǔ)結(jié)構(gòu)其實(shí)是這樣的,在page頁面中只會(huì)保留describe字段的前768個(gè)字節(jié)的前綴數(shù)據(jù),之后是偏移量,偏移量指向存儲(chǔ)完整數(shù)據(jù)的行溢出頁。

到這里,其實(shí)對(duì)文章開頭提出來的問題是有一個(gè)解答了。但是我們繼續(xù)深入探索一下,什么樣的數(shù)據(jù)會(huì)出現(xiàn)行溢出的這種現(xiàn)象呢?
行溢出的條件
有一些人認(rèn)為像BLOB、LONGBLOB這類的大對(duì)象數(shù)據(jù)類型會(huì)把數(shù)據(jù)存放在數(shù)據(jù)頁面之外。但是如果BLOB只存放了10個(gè)字段的數(shù)據(jù),這時(shí)候還會(huì)把數(shù)據(jù)丟到其他頁面嗎?想來不會(huì)這么蠢,看資料別人的實(shí)驗(yàn)也證明了這一點(diǎn)。然后像varchar這樣的類型,如果它存儲(chǔ)了16K的內(nèi)容,這些內(nèi)容會(huì)存儲(chǔ)在葉子節(jié)點(diǎn)內(nèi)嗎?事實(shí)證明也不合理。innodb是b+樹的存儲(chǔ)結(jié)構(gòu),在一個(gè)page中不希望只存儲(chǔ)1條記錄,是否發(fā)生行溢出這與page的大小有關(guān)系,一切都是為了保證一個(gè)page中存儲(chǔ)多條數(shù)據(jù),如果因?yàn)橐粭l記錄的超大導(dǎo)致了這個(gè)page存儲(chǔ)不下其他的記錄,顯然在搜索效率上是無法容忍的。至于具體到怎樣的數(shù)據(jù)級(jí)別,是超過9000個(gè)字節(jié)會(huì)存儲(chǔ)或者其他,我個(gè)人認(rèn)為這個(gè)和innodb 定義的page有關(guān)系。(個(gè)人理解,僅供參考,歡迎指正、探討與交流)

字段類型大小表
| 字段類型 | 存儲(chǔ)大小 | 解釋 |
|---|---|---|
| CHAR | 0-255字節(jié) | 定長(zhǎng)字符串 |
| VARCHAR | 0-65535 字節(jié)(64KB) | 變長(zhǎng)字符串 |
| TINYBLOB | 0-255字節(jié) | 不超過 255個(gè)字符的二進(jìn)制字符串 |
| TINYTEXT | 0-255字節(jié) | 短文本字符串 |
| BLOB | 0-65 535字節(jié)(64KB) | 二進(jìn)制形式的長(zhǎng)文本數(shù)據(jù) |
| TEXT | 0-65 535字節(jié)(64KB) | 長(zhǎng)文本數(shù)據(jù) |
| MEDIUMBL | OB 0-16 777 215字節(jié)(16M) | 二進(jìn)制形式的中等長(zhǎng)度文本數(shù)據(jù) |
| MEDIUMTE | XT 0-16 777 215字節(jié)(16M) | 中等長(zhǎng)度文本數(shù)據(jù) |
| LONGBLOB | 0-4 294 967 295字節(jié)(4G) | 二進(jìn)制形式的極大文本數(shù)據(jù) |
| LONGTEXT | 0-4 294 967 295字節(jié)(4G) | 極大文本數(shù)據(jù) |