MySQL資料庫存儲varchar時多大長度會出現行遷移?

2021-01-14 濟南小老虎

最近客戶現場有人問過mysql資料庫的一些參數配置的問題, 這邊資料庫需要將strict 嚴格模式關掉, 目的是為了保證資料庫在插入欄位時不會出現8126的長度限制錯誤問題. 但是一直很困惑, mysql的默認安裝的page 是 16kb 大小, 理論上一個頁不可能超過 16000 個bytes 長度, 很多文檔資料裡面都有 說法是 text和blob的類型都會出現行遷移, 但是對varchar 都沒有明確的說法, 今天趁著周六下了一個電子書, 將姜承堯老師的<MySQL技術內幕InnoDB存儲引擎第2版> 翻了 100多頁 也沒翻到具體的資料, 沒辦法只能夠進行嘗試.

先說寫一下結論. 

varchar 在 8099 的長度時會出現行溢出遷移的現象 將字符存儲到第六個數據頁

varchar 8098 時 還是在當前數據也存儲的, 而且應該是在第五個數據頁存儲.

姜老師的書裡面 mysql5.6 初始化時 是 6個數據頁,大小是96KB, 但是mysql 8.0.21 的版本初始一個ibd文件時 是初始化7個數據頁. 大小是 112KB


1. 本來想使用 姜老師寫的python腳本. 但是發現可能他的腳本僅支持mysql5.6 的版本. mysql8的版本是不支持. 無法直接使用. 

會報錯. 

git clone https://github.com/happieme/py_innodb_page_info
cd py_innodb_page_info/
chmod 777 * -R
./py_innodb_page_info.py /var/lib/mysql/zhaobsh/test001.ibd

報錯信息為:

[root@CentOS76 py_innodb_page_info]# ./py_innodb_page_info.py /var/lib/mysql/zhaobsh/test001.ibd
Total number of page: 7:
Insert Buffer Bitmap: 1
File Segment inode: 1
B-tree Node: 1
Traceback (most recent call last):
File "./py_innodb_page_info.py", line 12, in <module>
mylib.get_innodb_page_type(myargv)
File "/root/mysql/py_innodb_page_info/mylib.py", line 72, in get_innodb_page_type
print "%s: %s"%(innodb_page_type[type],ret[type])
KeyError: '45bd'
[root@CentOS76 py_innodb_page_info]#

沒辦法僅能夠退而求其次. 

先通過一個網頁找到了一些關於mysql 數據頁page含義的內容

來源:

http://www.blog.chinaunix.net/uid-29170515-id-5747112.html


#數據頁具體內容分析

#一行代表16位元組
[root@master ~]# head -n 3094 ilvtu_block.txt|tail -n 22
#u前38位元組為文件頭
#前4個節a1 a3 c2 67為checksum
#第5-8個字節00 00 00 03,指定頁的偏移量,表明為第4個頁
#第9-12個字節ff ff ff ff,當前頁的上一個頁,只有為數據頁時,才有具體意義值
#第13-16個節ff ff ff ff,當前頁的下一個頁,同上
#第17-24個字節代表該頁最近被修改的日誌序列位置LSN,00 00 00 00 85 69 9e a4
#第25-26位元組,表示頁的類型,45 bf表示為數據頁
#第27-34位元組,共8位元組,00 00 00 00 00 00 00 00,只有屬於系統表空間時才有意義
#第35-38位元組,共4位元組,00 00 00 69,代表屬於哪個表空間,SPACE_ID



#第39-40位元組,共2位元組,代表存儲頁目錄中的槽位(slot)數,00 02,代表2個slot
#第41-42位元組,00 e9,代表空閒空間偏移量0000c000+00c9=0000c0e9
#第43-44位元組,00 05,表示行數,因為表的格式為COMPAT,初始後為00 02,因些相減為3條記錄
#第45-46位元組,00 00,共2位元組,存放可重用空間的首指針
#第47-48位元組,00 00,共2位元組,
#第49-50位元組,00 cb, 0000c000+00cb=0000c0cb,代表最後一條記錄插入的位置偏移量
#第51-52字共,共2位元組,代表最後插入的方向00 02,代表向右增長
#第53-54位元組,共2位元組,代表連續插入的記錄數,00 02,代表連續插入2條
#第55-56位元組,共2位元組,代表頁中記錄數,00 03代表有3條記錄
#第57-64位元組,共8位元組,00 00 00 00 00 00 00 00
#第65-66位元組,共2位元組,00 00 代表葉子節點
#第67-74位元組,共8位元組,索引ID,00 00 00 00 00 00 00 dd
#第65-84位元組,共10位元組, 00 00 00 69 00 00 00 02 00 f2 代表B+樹數據頁非葉子節點所在段的段頭
#第84-95位元組,共10位元組,代表B+樹數據頁所在段的段頭,00 00 00 69 00 00 00 02 00 32

#第96-100位元組,共5位元組,01 00 02 00 1c,infimun記錄頭
#第101-108位元組,共8位元組,69 6e 66 69 6d 75 6d 00,infimun字節

第108-112位元組,共5位元組,04 00 0b 00 00,suprenum記錄頭
第113-120位元組,共8位元組,73 75 70 72 65 6d 75 6d,suprenum記錄



0000c000 a1 a3 c2 67 00 00 00 03 ff ff ff ff ff ff ff ff |...g............|
0000c010 00 00 00 00 85 69 9e a4 45 bf 00 00 00 00 00 00 |.....i..E.......|
0000c020 00 00 00 00 00 69 00 02 00 e9 80 05 00 00 00 00 |.....i..........|
0000c030 00 cb 00 02 00 02 00 03 00 00 00 00 00 00 00 00 |................|
0000c040 00 00 00 00 00 00 00 00 00 dd 00 00 00 69 00 00 |.............i..|
0000c050 00 02 00 f2 00 00 00 69 00 00 00 02 00 32 01 00 |.......i.....2..|
0000c060 02 00 1c 69 6e 66 69 6d 75 6d 00 04 00 0b 00 00 |...infimum......|
0000c070 73 75 70 72 65 6d 75 6d

##往後行記錄內容
#從121位元組開始

#第一條記錄
#第121位元組,08變長欄位長度為8,NAME欄位值『YANGYANG』為變長欄位,8位元組
#第122位元組,00,NULL標記
#第123-127位元組,共5位元組,00 00 10 00 26,記錄頭
#第128-133位元組,共6位元組,ROWID,00 00 00 04 c2 00
#第134-139字共,共6位元組,事務ID,00 00 00 00 75 0a
#第140-146位元組,共7位元組,8a 00 00 01 b8 01 10,回滾段ID,指向UNDO回滾段地址
#第147-150位元組,共4節,ID欄位所佔固定長度,80 00 00 01
#第151-158位元組,共8位元組,變長欄位NAME佔用,『59 41 4e 47 59 41 4e 47』,轉換成字符串,為'YANGYANG'

0000c070 08 00 00 00 10 00 26 00 |supremum......&.|
0000c080 00 00 04 c2 00 00 00 00 00 75 0a 8a 00 00 01 b8 |.........u......|
0000c090 01 10 80 00 00 01 59 41 4e 47 59 41 4e 47

#第二條記錄
0000c090 08 00 |......YANGYANG..|
0000c0a0 00 00 18 00 26 00 00 00 04 c2 01 00 00 00 00 75 |....&..........u|
0000c0b0 0b 8b 00 00 01 99 01 10 80 00 00 01 44 4f 4e 47 |............DONG|
0000c0c0 58 55 41 4e 07 00 00 00 20 ff a5 00 00 00 04 c2 |XUAN.... .......| //20位元組所在位置為
0000c0d0 02 00 00 00 00 75 10 8e 00 00 01 4e 01 10 80 00 |.....u.....N....|
0000c0e0 00 01 46 45 4e 47 48 55 41 00 00 00 00 00 00 00 |..FENGHUA.......| //46 45 4e 47 48 55 41 對應『FENGHUA


文章很長, 但是我用到了裡面的一個方法. 


第一步是初始化表,並且插入數據. 根據表名可以看出來我進行過了很多次嘗試.

create table test014 (a varchar(16000));

insert into test014 values ((select repeat('a',8098)));

create table test015 (a varchar(16000));

insert into test015 values ((select repeat('a',8099)));


然後使用hexdump的方式將ibd文件導成 文本文檔 

hexdump -Cv /var/lib/mysql/zhaobsh/test014.ibd > test014.txt
hexdump -Cv /var/lib/mysql/zhaobsh/test015.ibd > test015.txt

然後查看兩個文件 

vim test014.txt

比較簡單的方式

在命令模式下輸入 4096 輸入大寫的G 調準到 第五個數據頁

可以看到 底4098 行的 45bf 指代當前page 為 數據頁 然後可以看到 當插入為 8098行數據時 當前數據頁有很多 實際數據在裡面. 

 

 然後看一下 8099 的 test015.txt 就會發現不一樣的現象

 

 

 當前頁內 沒有任何 a 的跡象. 查看第六個數據頁

會發現遷移到了下一個數據頁裡面進行存儲. 

 

 本來還想驗證 多個數據列的遷移情況. 但是有點困了 

mysql的東西還是很深奧的 , 需要多學習掌握才可以. 暫時先這樣吧 mark一下. 

驗證了下 ascii 也會同樣的數據情況下行遷移 但是沒有嘗試中文. 改天再試試.

相關焦點

  • mysql varchar和int欄位解析
    mysql4.1前的varchar(20)是20個字節。最大的限制是255位元組。mysql5.0以後varchar(20)是20個字符。最大的限制是65535-3佔位符號=65532位元組。gbk:65532/2 字符utf-8:65532/3 字符如果超出了範圍,會轉為text類型來存儲。除了關注單個欄位的限制,還要關注行的限制。mysql一行最大是65535也就是64k。
  • Mysql Online DDL之VARCHAR欄位擴容探索
    從mysql5.6開始以後的版本,支持Online DDL,這個功能是mysql夢寐以求的功能,要知道在mysql5.6以前的版本,做DDL變更,可是會鎖表,業務無法做DML操作,只能查詢,其中痛苦,只有經歷過的同學才會知道。
  • 了解資料庫類型及MySQL資料庫常用命令行
    一、資料庫1、資料庫DataBase(DB):存儲數據的倉庫。2、資料庫的分類(1) 關係型資料庫(sql資料庫):中型:mysql(埠號3306)、sql server大型:Oracle(埠號1521)(2) 非關係型資料庫(no-sql資料庫)
  • mysql中varchar(n)中的n到底是指的什麼
    我們一般開發的系統基本都離不開資料庫。mysql就是我們經常會使用的一個關係型資料庫。關係型資料庫存儲的數據都是按照定義好的列的規則存放的行列形式的數據。varchar就是mysql資料庫中定義列為字符串的一種數據類型。
  • Mysql5.7的varchar類型欄位建索引竟然失敗
    在Mysql資料庫日常運維過程中,在表上創建索引是很常見的事情,可是一直沒有思考過,單列索引到底能有多長呢。如果varchar類型的欄位過長,創建單列索引會不會失敗呢,下面就來一起探索一下吧。---+1 row in set (0.02 sec)查看測試表的默認記錄格式在mysql5.7版本中,Innodb表的行記錄格式為Dynamic的。
  • 資料庫遷移搞炸了!沒用這款開源神器的鍋?
    來源:https://mp.weixin.qq.com/s/2IhoZ1rMy3Hi9zXvvxjF2Q當我們的應用升級時往往會伴隨著資料庫表結構的升級,此時就需要遷移資料庫的表結構。一般我們會使用工具或者腳本來實現,手動操作畢竟有一定風險,要是能在應用啟動時自動升級資料庫表結構就好了!
  • 如何將Oracle遷移至mysql?
    1)下載Navicat Premium版本,Navicat for mysql只支持連接mysql資料庫。如果需要支持oracle連接,還需要配置OCI,選擇工具—選項—OCI,選擇對應路徑下文件:配置完成後關閉Navicat再重新打開。
  • 針對mysql,資料庫乾貨分享,值得收藏
    (mysql 5.7後innodb支持全文索引)InnoDB不保存表的具體行數,執行select count(*) from table時需要全表掃描。而MyISAM用一個變量保存了整個表的行數,執行上述語句時只需要讀出該變量即可,速度很快(注意不能加有任何WHERE條件)清空整個表時,InnoDB是一行一行的刪除,效率非常慢。MyISAM則會重建表。
  • 三分鐘帶你分清Mysql 和Oracle之間的誤區
    MySQL是大小寫敏感的,如資料庫相對的存儲路徑、表對應的文件都是如此當把關鍵字用引號引起來時,Oracle和MySQL都允許把這些關鍵字用於模式對象。但MySQL對於一些關鍵字,不加引號也行。如果多個MySQL資料庫位於同一個資料庫服務上,支持遷移。
  • Java開發工程師如何在Mysql資料庫中創建表
    首先我們需要在資料庫中創建兩張表用來學習MyBatis對資料庫增刪改查的使用方法。如果是新安裝的資料庫可以直接複製我下面的sql進行表創建,如果是已使用中的資料庫可能表明會與我的表名衝突,需要創建一個新的database再執行sql,也可以直接刪除原來的表,如果表有外鍵關聯需要先解除外鍵約束再刪除。
  • MySQL的char與varchar詳解
    2 存儲CHAR是定長字符串類型,在聲明時指定其長度m,在進行數據寫入時,如果寫入的字符串未達到指定長度m,那麼會在左側使用空格補齊到長度m,所以,聲明為m長度的CHAR類型,不論其存放的字符串長短,統一都會佔用m字節。
  • 一千行 MySQL 詳細學習筆記
    字符串類型-- a. char, varchar ---------- char 定長字符串,速度快,但浪費空間 varchar 變長字符串,速度慢,但節省空間 M表示能存儲的最大長度,此長度是字符數,非字節數。 不同的編碼,所佔用的空間不同。 char,最多255個字符,與編碼無關。
  • MySQL客戶端功能及SQL
    導入數據示例:#使用Sock連接mysql -uroot -p -S /tmp/mysql.sock#使用TCP/IP連接mysql -uroot -p -h 10.0.0.1 -P3306#使用默認Sock連接,並且查看資料庫mysql -uroot -proot -e "show databases;"#############返回結果###############
  • 一千行MySQL學習筆記
    字符串類型-- a. char, varchar     char    定長字符串,速度快,但浪費空間    varchar    變長字符串,速度慢,但節省空間    M表示能存儲的最大長度,此長度是字符數,非字節數。    不同的編碼,所佔用的空間不同。    char,最多255個字符,與編碼無關。
  • mysql和php字符長度判斷
    問題最近工作中遇到一個問題,資料庫欄位設置的varchar(255),測試測的時候總是在臨界點那邊給我提bug,今天研究一下mysql和php字符長度判斷。環境php7.2.9mysql8.0.12測試時文件的編碼方式要是UTF8資料庫欄位類型大小為 varchar(255),php中用strlen()與mb_strlen()函數。
  • 將數據從MySQL遷移到Oracle的注意事項
    將數據從MySQL遷移到Oracle的注意事項 1.自動增長的數據類型處理 MYSQL有自動增長的數據類型,插入記錄時不用操作此欄位,會自動獲得數據值。
  • MySql基礎,MySql視圖&索引&存儲過程&觸發器
    行和列的數據來自於定義視圖的查詢中所使用的表,並且還是在使用視圖時動態生成的。資料庫中只存放了視圖的定義,並沒有存放視圖中的數據,這些數據都存放在定義視圖查詢所引用的真實表中。使用視圖查詢數據時,資料庫會從真實表中取出對應的數據。因此,視圖中的數據是依賴於真實表中的數據的。一旦真實表中的數據發生改變,顯示在視圖中的數據也會發生改變。
  • MySql面試題及答案大全
    隨著技術的進步和發展,面試官們對面試者的要求越來越高,現在只要是後端開發的職位,面試肯定會問資料庫的相關知識,而mysql作為目前最為流行的免費的關係型資料庫管理系統,肯定是很多公司面試必問的重點,今天阿偉就為大家總結一下mysql的面試題;事務的基本特徵原子性(atomicity
  • 您應該如何在資料庫(Java,MySQL和開發)中存儲格式化的欄位?
    有一種古老的資料庫格言說:「原始存儲,漂亮地顯示。」 關於存儲,這意味著數據應該以最佳格式存儲,以便在資料庫中使用,即搜索,排序,比較等。為說明起見,讓我們以存儲電話號碼的欄位為例。在我研究過的應用程式中,我們將在存儲到資料庫之前在應用程式級別去除特殊字符。然後,我們將電話號碼格式化為正式格式以進行顯示。在這種情況下,格式化電話號碼的處理器開銷是微不足道的,生產所需的時間不到一微秒。至於使用哪種數據類型,有人認為電話號碼適合使用數字類型。但是,我認為char或varchar會更好,因為非數字字符可以在電話號碼中有效。
  • 0064 關係資料庫的概念和安裝使用MySQL
    這節課開始學習關係資料庫的概念,以及如何安裝和使用MySQL資料庫。關係資料庫的概念資料庫就是對數據進行結構化存儲和管理的倉庫。關係資料庫就是資料庫中的表採用二維表格來存儲數據,是一種按行與列排列的具有相關信息的邏輯組,它類似於Excle工作表。表和表之間可以通過數據關係進行關聯。