關於這個問題,村長我查過很多信息,有説來自官方,有自己分析的,莫衷一是,要麼太發散,要麼有幾分牽強,現在村長試解答一下。
這個問題其實挺有意思,理論上來説,可以存一條數據,那為啥要有這麼個規則呢?
我們知道,一頁的大小默認為 16*1024=16384 字節,但是,MySQL 允許的一行數據的存儲上限卻為 65535!
當然了,這 65535 個字節除了列本身的數據外,還包括一些其他數據(storage overhead),比如 變長字段長度列表、NULL值列表、記錄頭信息 等,但歸根結底,還是遠大於 16384 的。
如果至少要存儲兩條記錄,簡單做個除法,16384/2=8192,這遠小於上限值啊!
有意思吧?
如果我們設置行類型為 text, 理論上會出現一頁可能存不下一行數據的情況誒。
比如,超過 一頁大小的二分之一,8192,那怎麼辦?
這種情況稱之為 行溢出,和內存溢出類似
MySQL 是怎麼處理行溢出的呢?
這涉及到 行格式 問題,MySQL 支持4種不同類型的行格式:Compact、Redundant(比較老)、Dynamic、Compressed。
Compact和Redundant行格式中,記錄的真實數據處會存儲該列的一部分數據(前768個字節), 剩餘數據存儲在其他頁(溢出頁),再使用20個字節存儲指向溢出頁的地址;
Dynamic(MySQL默認)和Compressed行格式中,不會在記錄的真實數據處存放前768個字節,而是將所有字節都存儲在其它頁面中,自身只存儲一個指向溢出頁的地址;略有不同的是,Compressed 行格式會採用壓縮算法對頁面進行壓縮,以節省空間。
言而總之,要麼存 前綴+溢出頁地址,要麼只存 溢出頁地址。
現在問題來了,我們假設一個場景:
某一行數據,佔 10000 個字節,加上額外信息,一頁也是可以存下的,為啥非得搞個溢出頁存放,這不給自己找事兒嗎?
我們再繼續假設,如果允許存放一行,且所有數據都是 10000 個字節,那就變成有多少行就有多少頁了。
這種情況有啥問題呢?
我們要知道,MySQL 是以頁作為磁盤和內存之間交互的基本單位的,也就是,一般情況下一次最少從磁盤中讀取16KB的內容到內存中;
如果我們執行 select * from tbl, 連個篩選條件也不加,而且是讀取全量字段,感覺一頁存幾條都沒啥區別,就是可勁兒造唄;
但實際情況中,千萬量級的表,不可能出現這麼傻叉的查詢邏輯,別問村長為啥,你自己試試就知道多麼痛的領悟了。
通常來講,大量級的表,我們查詢數據,一般要設定篩選條件,也就是根據索引來縮小查詢範圍,以達到只取必要數據的目的;
而造成行溢出的,基本都是 text 或 超長的 varchar 字段,這類字段一般是不會被高頻次查詢的;
假如有一個學生表,裏邊有學生ID、名稱、班級、專業等信息,還有一個興趣愛好的字段,被設定為 text,且大家為了交朋友,都很踴躍填寫,興趣愛好都超過了 10000 個字節,但小於一頁數據大小;
現在問題又來了:
MySQL 允許一頁存一行數據,一共存了 2000 條學生記錄,也就是 2000 頁;
大領導來視察了,想查詢學生基本信息,不用帶上 興趣愛好 描述啥的,領導沒興趣看,就學生自己玩兒的;
假設一次從磁盤讀取16kb,也就是一頁數據,那就得從磁盤讀取 2000 次吧?
如果記錄數擴展為 2000萬 呢?那就得讀取 2000萬 次吧?這效率可想而知。。。
但如果限制了一頁至少存兩條記錄呢?你會發現,讀取次數直接降了一半誒。
這就是二分邏輯的神奇之處,類似經濟學中的"荷塘效應", 假設池塘的荷葉一天增長一倍,那在在它鋪滿池塘之前的前一天,才只佔了池塘的一半面積呢。
分析到這裏,都有些心靈雞湯的玄學味道了;
這個限制,大約就是為了提早分離長文本數據,以實現更高效的查詢吧;
因為這個限制,提供了一種最壞情況擔保,保證了極端情況下的查詢效率可以至少提升一倍
可能有小夥伴會想到,為啥不直接限制3條,這樣效率不是更高嘛?
可以是可以,但限制3條並不能使得在限制2條的基礎上,效率再提升一倍;
如果是4條呢,不就可以了?
估計會涉及更多的信息存儲問題吧,比如額外信息的存儲,長文本的前綴存儲長度等等;
這得去問那行聰明的數據庫設計人員了。
附:行格式 小知識延伸
MySQL 中,若一張表裏面不存在varchar、text以及其變形、blob以及其變形的字段的話,比如只有 int、char 字段,那麼這張表其實也叫靜態表,即該表的row_format是 FIXED;
其特點是:每條記錄所佔用的字節一樣,讀取快,但浪費額外一部分空間;
反之如果存在,這張表就叫動態表,即該表的row_format是 DYNAMIC(當然還包括上面提到的COMPRESSED、COMPACT等),就是説每條記錄所佔用的字節是動態的;
其特點是:節省空間,但增加讀取的時間開銷;
所以,具有頻繁檢索場景的表,一般都以空間換時間,將其設計成靜態表!
參考文檔:
https://blog.csdn.net/weixin_39644325/article/details/110587235