面試官:MySQL 中 varchar(n) 中 n 最大取值為多少?
上週發了一篇位元組一面:MySQL 的 NULL 值是怎麼存放的?,文章裡面有提及這個問題:「varchar(n) 中 n 最大取值為多少?」
當時這部分內容寫的不夠嚴謹,所以我重寫了這部分內容。
所以,這次就聊聊這個問題。
前置知識
要回答這個問題,首先我們得先知道 MySQL 儲存一條記錄的格式長什麼樣子。
以 Compact 行格式作為例子,它長這樣:
可以看到,一條完整的記錄分為「記錄的額外資訊」和「記錄的真實資料」兩個部分。
這裡重點講講記錄的額外資訊,它包含 3 個部分:變長欄位長度列表、NULL 值列表、記錄頭資訊。
變長欄位長度列表
用於儲存一行記錄中每個變長欄位的長度。
「變長欄位長度列表」所佔用的位元組數 = 所有「變長欄位長度」佔用的位元組數之和。
舉個例子,假設資料庫表中有 2 個 varchar(10) 型別的欄位,分別為 a 和 b,且資料庫表的字符集為 ascii 字符集(1 個字元佔用 1 位元組)。
那麼a和b欄位的資料值的長度分別只需要用1位元組表示就行了,因為1位元組能表示最大的位元組數是 255,而 varchar(10) 型別的欄位最大允許儲存的位元組數是 10 位元組,所以只需要用 1 位元組表示變長欄位的長度就行。
那麼這種情況下的 「變長欄位長度列表」所佔用的位元組數 = 1 位元組 + 1位元組 = 2 位元組。
「變長欄位長度列表」不是必須的,如果資料庫表沒有變長欄位,比如欄位型別都是int,那麼行格式中就不需要「變長欄位長度列表」。
NULL 值列表
用於標記一行記錄中欄位值為 NULL 的欄位,二進位制位的值為 1 時,代表該欄位的值為NULL,二進位制位的值為 0 時,代表該欄位的值不為 NULL。
另外,NULL 值列表必須用整數個位元組的位表示(1位元組8位),如果使用的二進位制位個數不足整數個位元組,則在位元組的高位補 0
。
如果表中允許為 NULL 值的記錄的個數小於等於 8 個,那麼 NULL 值列表就會用 1 位元組表示。
如果如果表中允許為 NULL 值的記錄的個數大於8 並且小於等於 16,那麼 NULL 值列表就會用 2 位元組表示,以此類推。
因此,如果表中有欄位允許為 NULL,那麼「NULL 值列表」至少佔用 1 位元組空間。
「NULL 值列表」不是必須的,如果資料庫表中的欄位都定義成 NOT NULL,那麼行格式中就不需要「NULL 值列表」。
記錄頭資訊
記錄頭資訊中包含的內容很多,比如記錄的刪除標記位,指向下一條記錄的指標等等,不是本文問題的重點,所以我就不細講了。
varchar(n) 中 n 最大取值為多少?
我們要清楚一點,MySQL 規定除了 TEXT、BLOBs 這種大物件型別之外,其他所有的列(不包括隱藏列和記錄頭資訊)佔用的位元組長度加起來不能超過 65535 個位元組。
也就是說,一行記錄除了 TEXT、BLOBs 型別的列,限制最大為 65535 位元組,注意是一行的總長度,不是一列。
知道了這個前提之後,我們再來看看這個問題:「varchar(n) 中 n 最大取值為多少?」
varchar(n) 欄位型別的 n 代表的是最多儲存的字元數量,並不是位元組大小哦。
要算 varchar(n) 最大能允許儲存的位元組數,還要看資料庫表的字符集,因為字符集代表著,1個字元要佔用多少位元組。
比如 ascii 字符集, 1 個字元佔用 1 位元組,那麼 varchar(100) 意味著最大能允許儲存 100 位元組的資料。
單欄位的情況
前面我們知道了,一行記錄最大隻能儲存 65535 位元組的資料。
那假設資料庫表只有一個 varchar(n) 型別的列且字符集是 ascii,在這種情況下, varchar(n) 中 n 最大取值是 65535 嗎?
不著急說結論,我們先來做個實驗驗證一下。
我們定義一個 varchar(65535) 型別的欄位,字符集為 ascii 的資料庫表。
CREATE TABLE test (
`name` VARCHAR(65535) NULL
) ENGINE = InnoDB DEFAULT CHARACTER SET = ascii ROW_FORMAT = COMPACT;
看能不能成功建立一張表:
結果顯示,建立失敗了。
從報錯資訊就可以知道一行資料的最大位元組數是 65535(不包含 TEXT、BLOBs 這種大物件型別),其中包含了 storage overhead。
問題來了,這個 storage overhead 是什麼呢?其實就是「變長欄位長度列表」和 「NULL 值列表」。
也就是說一行資料的最大位元組數 65535,其實是包含「變長欄位長度列表」和 「NULL 值列表」所佔用的位元組數的。
所以, 我們在算 varchar(n) 中 n 最大值時,需要減去 storage overhead 佔用的位元組數。
這是因為我們儲存欄位型別為 varchar(n) 的資料時,其實分成了三個部分來儲存:
真實資料 真實資料佔用的位元組數 NULL 標識,如果不允許為NULL,這部分不需要
本次案例中,「NULL 值列表」所佔用的位元組數是多少?
前面我建立表的時候,欄位是允許為 NULL 的,所以會用 1 位元組來表示「NULL 值列表」。
本次案例中,「變長欄位長度列表」所佔用的位元組數是多少?
「變長欄位長度列表」所佔用的位元組數 = 所有「變長欄位長度」佔用的位元組數之和。
所以,我們要先知道每個變長欄位的「變長欄位長度」需要用多少位元組表示?具體情況分為:
條件一:如果變長欄位允許儲存的最大位元組數小於等於 255 位元組,就會用 1 位元組表示「變長欄位長度」; 條件二:如果變長欄位允許儲存的最大位元組數大於 255 位元組,就會用 2 位元組表示「變長欄位長度」;
我們這裡欄位型別是 varchar(65535) ,字符集是 ascii,所以代表著變長欄位允許儲存的最大位元組數是 65535,符合條件二,所以會用 2 位元組來表示「變長欄位長度」。
因為我們這個案例是隻有 1 個變長欄位,所以「變長欄位長度列表」= 1 個「變長欄位長度」佔用的位元組數,也就是 2 位元組。
因為我們在算 varchar(n) 中 n 最大值時,需要減去 「變長欄位長度列表」和 「NULL 值列表」所佔用的位元組數的。
所以,在資料庫表只有一個 varchar(n) 欄位且字符集是 ascii 的情況下,varchar(n) 中 n 最大值 = 65535 - 2 - 1 = 65532。
我們先來測試看看 varchar(65533) 是否可行?
可以看到,還是不行,接下來看看 varchar(65532) 是否可行?
可以看到,建立成功了。說明我們的推論是正確的,在算 varchar(n) 中 n 最大值時,需要減去 「變長欄位長度列表」和 「NULL 值列表」所佔用的位元組數的。
當然,我上面這個例子是針對字符集為 ascii 情況,如果採用的是 UTF-8,varchar(n) 最多能儲存的資料計算方式就不一樣了:
在 UTF-8 字符集下,一個字串最多需要三個位元組,varchar(n) 的 n 最大取值就是 65532/3 = 21844。
上面所說的只是針對於一個欄位的計算方式。
多欄位的情況
如果有多個欄位的話,要保證所有欄位的長度 + 變長欄位位元組數列表所佔用的位元組數 + NULL值列表所佔用的位元組數 <= 65535。
這裡舉個多欄位的情況的例子。
實驗結果:
總結
varchar(n) 中 n 最大取值為多少?
一行記錄最大能儲存 65535 位元組的資料,但是這個是包含「變長欄位位元組數列表所佔用的位元組數」和「NULL值列表所佔用的位元組數」。所以, 我們在算 varchar(n) 中 n 最大值時,需要減去這兩個列表所佔用的位元組數。
如果一張表只有一個 varchar(n) 欄位,且允許為 NULL,字符集為 ascii。varchar(n) 中 n 最大取值為 65532。
計算公式:65535 - 變長欄位位元組數列表所佔用的位元組數 - NULL值列表所佔用的位元組數 = 65535 - 2 - 1 = 65532。
如果有多個欄位的話,要保證所有欄位的長度 + 變長欄位位元組數列表所佔用的位元組數 + NULL值列表所佔用的位元組數 <= 65535。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2927960/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【MySQL】淺談varchar(N)MySql
- 【MySQL】淺談 varchar(N)MySql
- MySQL中資料型別(char(n)、varchar(n)、nchar(n)、nvarchar(n)的區別)MySql資料型別
- char(n)和varchar2(n)區別
- mysql的varchar(N)和int(N)的含義及其與char區別MySql
- VARCHAR2(N CHAR)與VARCHAR2(N)的區別[Oracle基礎]Oracle
- MySQL 中 VARCHAR 最大長度及 CHAR 和 VARCHAR 的區別MySql
- mysql中varchar型別最大長度測試MySql型別
- MySQL中欄位型別與合理的選擇欄位型別;int(11)最大長度是多少?varchar最大長度是多少?MySql型別
- 在MySQL中,如何實現Top N及M至N段的記錄查詢?MySql
- 小於n的最大數
- matlab中怎樣隨機生成一個最大值為N的正整數??Matlab隨機
- 最大矩形;及第n杯水分析
- 介面測試的N中玩法
- 計算2的N次冪n 可輸入,n為自然數
- MySQL中CHAR和VARCHAR區別MySql
- 談MySQL中char varchar區別MySql
- 劍指offer面試題12 列印1到最大的n位數面試題
- 小於n的最大數,記一道位元組面試題面試題
- 尋找陣列中的最大值和最小值O(1.5*N)陣列
- 面試中的MySQL主從複製|手撕MySQL|對線面試官面試MySql
- 從面試題中學演算法(2)---求陣列中唯一n個出現1次的數字(n=1,2,3)面試題演算法陣列
- python中n角星畫法Python
- Mysql中varchar與char的區別以及varchar(30)中的30代表的涵義MySql
- N-API中的Promise功能的使用APIPromise
- Java 中拼接 String 的 N 種方式Java
- mysql id從n 開始MySql
- MySQL中int、char、varchar的效能淺談MySql
- Dynamics CRM實體系列之1:N、N:1以及N:N關係
- 吊打面試官!MySQL靈魂100問,你能答出多少?面試MySql
- 從陣列中找出N個數,其和為M的所有可能陣列
- HTML中嵌入SVG圖片的N種方式HTMLSVG
- 演算法 1~n中1的次數演算法
- python3去除str中的n、rPython
- 在JavaScript中判斷整型的N種方法JavaScript
- 『非1~2^n的互換機制』(中)
- MySQL 分組排序後 → 如何取前N條或倒數N條MySql排序
- 【MySQL】我這樣分析MySQL中的事務,面試官對我刮目相看!!MySql面試