精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

mysql的varchar字段最大長度為什么不是65535而是65533呢?

dyquk4xk2p3d ? 來源:小白debug ? 2023-04-19 11:30 ? 次閱讀

在mysql建表sql里,我們經常會有定義字符串類型的需求。

CREATETABLE`user`(
`name`varchar(100)NOTNULLDEFAULT''COMMENT'名字'
)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

比方說user表里的名字,就是個字符串。mysql里有兩個類型比較適合這個場景。

char和varchar。

聲明它們都需要在字段邊上加個數組,比如char(100)varchar(100),這個100是指當前字段能放的最大字符數

char和varchar的區別在于,varchar雖然聲明了最大能放100個字符,但一開始不需要分配100個字符的空間,可以根據需要慢慢增加空間。而char一開始聲明是多少,就固定預留多少空間。

所以,varchar比起char更省空間,一般沒啥大事,大家都愛用varchar

那問題來了,聲明varchar字段時,它的最大長度是多少呢?

相信大家應該聽說過varchar字段的最大長度是65535吧。

沒聽過也沒關系,你現在聽到了。

但實際上是這樣嗎?

我們來做個實驗。

varchar最大值是多少

我們直接拿65535來試一下。

e4041d80-de60-11ed-bfe3-dac502259ad0.png長度為65535的varchar報錯

很明顯報錯了。

報錯內容也說了,由于列長度過大導致報錯,最長是16383

把上面的65535改成 16383,確實是成功了。

哦?所以說varchar最大值是16383?

當然不是。

這其實還有好幾個因素影響這這個最大值。

不同字符集的影響

varchar里放的是字符串,而字符串看起來可以是英文字母,也可以是數字或中文。但不管怎么樣,都可以把這樣的中英文數字轉成二進制的01串。

按照一定規則把符號和二進制碼對應起來,這就是編碼。而把n多這種已經編碼的字符聚在一起,就是我們常說的字符集

建表語句里有個CHARSET,這里填的是字符集。

不同的字符集要求使用的字節個數也不同,我們可以通過show charset;看到mysql支持哪些字符集,以及這些字符集里存儲一個字符所需的最大字節數(Maxlen)。

e4162098-de60-11ed-bfe3-dac502259ad0.png查看mysql支持哪些charset

我們嘗試下把建表sql語句里的CHARSET改一改,比如改成utf8mb3

我們再執行下,會發現,最大值又不一樣了。

e428a72c-de60-11ed-bfe3-dac502259ad0.pngutf8mb3下的報錯

并且,上面雖然提示max=21845,但要是真執行起來會發現還是報錯。在改為21844之后才成功。

不講武德。

再把字符集改為 latin1。會發現,最大值會是 65533

e43aa242-de60-11ed-bfe3-dac502259ad0.pngvarchar為65533時創建成功

這里漸漸可以發現規律。

utf8mb4的maxlen=4,對應varchar最大長度=16383。4*16383 = 65532。

utf8mb3的maxlen=3,對應varchar最大長度=21844。3*21844 = 65532。

latin1的maxlen=1,對應varchar最大長度=65533。 1 * 65533 = 65533。

也就是說varchar邊上的長度代表的是這一列能放的最大字符數,而maxlen代表單個字符占用的最大字節數。相乘的結果很接近65535。說明65535是指的字節數,而不是字符數

也就是說varchar的最大長度,根據選擇的字符集的不同,會有區別。

總的來說接近于 65535 除以 字符集的maxlen。

但其實這樣還不夠嚴謹。還有其他影響因素。

是否可以為NULL的影響

上面的建表語句里聲明了test字段都是NOT NULL,也就是非空,如果我們將這個改成可以為NULL,再用CHARSET=latin1去試試。這時候就會發現,前面NOT NULL的時候最大能使用65533去建表,現在報錯了。

改成65532,就能成功了,也就是最長長度少了1個字節

e450aec0-de60-11ed-bfe3-dac502259ad0.png是否為NULL的影響

這是因為一個字段是否為NULL這件事情,是需要一個字節去記錄下來的。

而當字段為NOT NULL的時候,則可以省下這個字節。

列數的影響

上面提到的情況都是在表里只有一列時的結果,當我們表里有更多的列時,我們會發現varchar的最大值還會有變化。比如同樣還是latin1字符集,我們再增加一列varchar類型,并且用的還是前面允許的最大值65533。

結果發現這次會失敗。

e45f3b8e-de60-11ed-bfe3-dac502259ad0.png兩個varchar列的情況

查了一下資料發現,原來65535是mysql單行的最大長度(不包含blob和text等類型的情況下)

mysql表里單行中的所有列加起來(不考慮其他隱藏列和記錄頭信息) ,占用的最大長度是65535個字節。

注意上面加粗的部分,加起來不超過65535。

比如如果還有int的列,那它占用4個字節,bigint占用8個字節,字段越多,留給單個varchar列的空間就越少。

因此,前面提到的 varchar 的最大長度,接近于 65535 除以 字符集的maxlen,但前提是只有一列not null 的varchar類型的字段。

為什么不是65535而是65533?

不過問題又來了,上面建表sql里,不管是那種字符集,最后得到的字符數都約等于65533。

但數據庫單行最大值應該是65535。65535 - 65533 = 2 。這里面還差了個2,為什么呢?

這就要聊一下mysql單行里數據到底是怎么存儲的。

數據表行存儲的格式

我們可以通過show table status命令,查看到當前表格使用的行格式。

e47537cc-de60-11ed-bfe3-dac502259ad0.png查看到當前表格使用的行格式

通過上面的Row_format字段可以看到這個表用的是Dynamic行格式。

事實上,現在的mysql數據表一般都是采用Dynamic行記錄格式。

我們來看下Dynamic行格式長什么樣子。

e487c68a-de60-11ed-bfe3-dac502259ad0.pngDynamic行記錄格式

Dynamic格式將行記錄分為兩部分,分為是行記錄的額外信息行記錄的真實數據

行記錄的額外信息:

變長字段長度列表:指的是varchar,text,blob這種類型,它們屬于變長字段,這里表示的就是這些字段的長度。

NULL值列表:用來記錄當前行里哪些列是為null的。如果全部列都是not null的話,那就不需要有這個字段。

記錄頭信息:這是固定5個字節,用來記錄一些特殊的信息,比如這一行是否被刪了,這一行在這個16k的數據頁內是不是最小的,以及指向下一條記錄的指針之類的一些信息,不需要太關注。

行記錄的真實數據:

里面放的就是一行里,每一列的真正內容。除了我們建表時里涉及到的列以外,還有一些隱藏列。

比如Row_ID,這個是在建表是沒有聲明主鍵時,數據表自動會生成的隱藏主鍵。另外還有trx_id字段,用于記錄當前這一行數據行是被哪個事務修改的,和一個roll_pointer字段,這個字段是用來指向當前這個數據行的上一個版本,通過這個字段,可以為這行數據形成一條版本鏈,從而實現多版本并發控制(MVCC)。有沒有很眼熟,這個在之前寫的文章里出現過。

e4a97cbc-de60-11ed-bfe3-dac502259ad0.png隱藏列有哪些

所以我們回過頭來看我們建的表,當只有一列not null的 varchar字段時,行記錄長下面這樣。

e4c02f2a-de60-11ed-bfe3-dac502259ad0.png單條varchar數據的Dynamic行記錄格式.drawio

前面提到,行最大值65535字節是不包含隱藏列和記錄頭信息的,所以其實是指上圖中紅色的部分。

而最左邊的變長字段長度列表中,為了表示varchar列的長度,占用了兩個字節,也就是16位,2的16次方,最大可以表示65535的長度,正好足夠用來表示varchar列當前的長度是65533。

所以65535 - 65533 = 2 。這里面差的2,是用來存varchar字段長度去了。

一個頁才16k,怎么保存65533(64k)數據?

之前的文章里其實多次提到了mysql底層是以頁的形式去存儲數據的,而一個頁固定16k,而一個varchar字段最大能放65533字節數據,換算一下大概是64k,整整4個16k的頁。

e4d64332-de60-11ed-bfe3-dac502259ad0.png頁結構

這里面是怎么實現的?

對于這種情況,其實行數據里針對這個超大的varchar字段只保存個20字節的指針(實際上是個偏移量),這個指針會指向新的頁(off page),這些頁里保存的是實際的varchar字段里的65533字節數據。這種由于字段過長導致需要額外的頁來保存數據的現象叫行溢出

e4e9cdf8-de60-11ed-bfe3-dac502259ad0.png行溢出

大于64k的字符串該怎么處理?

如果離譜點,數據量更大,比64k還大,這時候就不能繼續用varchar了,需要改用text和blob類型字段。

而text和blob類型本身也是分TINY、MEDIUM,LONG三個檔位的,對應著不同的數據長度,最大到4G左右。

像下面這樣就可以將數據類型定義為LONGTEXT。

CREATETABLE`test_max_length`(
`test`LONGTEXTNOTNULLCOMMENT'測試長度字段'
)ENGINE=InnoDBDEFAULTCHARSET=latin1;

而他們的存儲方式也跟varchar的情況類似,只保存20個字節的指針,實際數據保存在其他溢出頁里。

以前我們查某一行數據,他們都在一個16k的數據頁里,查詢時只要一次磁盤IO就能將這個數據頁讀取出來。

當一個數據庫里某行數據里有個特別大的字符串時,我們如果還想把整行數據給讀出來,那我們還得把off page的數據給全部讀出來,這意味著更多的磁盤IO,性能就更差了

為了規避這個問題,我們寫select sql的時候,如果發現某列字段,是個特別長的字符串時,能不讀它就盡量不加到select里,這也是為什么大家不建議使用select * from table的原因。

blob和text的區別

一般來說,blob和text都可以用來放超長字符串。但它們會有一點點區別。

我們知道字符集(charset)下還有個校對規則(collation)的概念,比如同樣是a,大寫A和小寫a能不能算作是一個字符,這會影響比較和排序,collation就是定義這個規則用的。

blob沒有字符集的概念,而text有。這意味如果用blob來存文本的話,就沒法用字符集的校對規則來排序和做比較。

還有一個區別,blob還能保存二進制數據,比如壓縮過的文本數據,圖片或者視頻,別笑,雖然不合適,但我確實見過有人拿它來保存視頻。。。

總結

現在的mysql數據表一般采用Dynamic行記錄格式。它由行記錄的額外信息和行記錄的真實數據組成。

mysql表里單行中的所有列加起來(不考慮其他隱藏列和記錄頭信息) ,占用的最大長度是65535個字節。

如果數據表里只有一列 not null的varchar字段,它的最大長度,接近于65535 除以 字符集的maxlen

如果要存放大于64k的字段數據,可以考慮使用longtext和longblob等類型。

mysql的數據頁大小是16k,為了保存varchar或者text,blob這種長度可能大于16k的字段,在Dynamic行格式中,會只保留20個字節的指針,實際數據則放在其他溢出頁中。為了將它們讀取出來,會需要更多的磁盤IO。

blob和text很像,但blob沒有字符集的概念,并且還能存放二進制的數據,比如圖片或視頻,但實際上圖片和視頻更推薦放在對象存儲(ObjectStorageService,簡稱oss)中。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編碼器
    +關注

    關注

    45

    文章

    3597

    瀏覽量

    134174
  • MySQL
    +關注

    關注

    1

    文章

    802

    瀏覽量

    26446
  • MYSQL數據庫
    +關注

    關注

    0

    文章

    95

    瀏覽量

    9382

原文標題:mysql的varchar字段最大長度真的是65535嗎?

文章出處:【微信號:良許Linux,微信公眾號:良許Linux】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    DMA搬運的數據長度超過65535怎么處理?

    我有個問題請問下。我現在使用定時器更新事件觸發DMA,采集1次SPI數據,使用的是循環模式。但是我現在采集的數據長度需要超過了65535,現在應該怎么處理?DMA搬運的數據長度最多是65535
    發表于 03-29 08:57

    MySQL筆記和小練習

    一、MySQL數據庫系統MySQL數據庫系統就是用來對數據庫、數據的一些管理二、數據庫系統1.數據庫就是用來存儲各種數據的2.數據庫管理系統就是用來管理各種數據庫的數據的一個系統三、常見的一些
    發表于 06-27 08:45

    MySQL如何實現添加字段

    MySQL添加字段應該如何實現?這是很多剛剛接觸MySQL數據庫的新人都提到過的問題,下面就為您介紹MySQL添加
    發表于 07-11 07:17

    Mysql字段類型

    Mysql字段類型
    發表于 07-18 12:04

    請問mysql數據庫一個漢字到底占幾個字節?

    GBK 和 UTF-8 字符集我都測試了,漢字在 MYSQL 里都占一個字節,例如一個字段 varchar (2),就能存儲兩個漢字或兩個字母或兩個數字。但我在網上搜了半天,都說 MYSQL
    發表于 06-02 14:48

    MYSQL數據庫如何創建計算字段以及怎么樣從應用程序中使用別名

    計算字段存儲在數據庫表中的數據一般不是應用程序所需要的格式,例如:顯示兩個信息,但不是在用一個表不同列中,但程序需要把他們作為一個格式的字段檢索出來列數據是大小混合,但程序需要把所以數
    發表于 11-04 14:40

    最大單段長度/五類線是什么意思

    最大單段長度/五類線是什么意思 最大單段長度     最大單段長度
    發表于 03-26 09:23 ?1740次閱讀

    華為手機銷量最高的不是P9也不是榮耀8 而是這臺!

    目前出貨量最大的國產手機,不是高端手機,也不是不是中端手機,而是千元機。
    發表于 02-15 13:50 ?3131次閱讀

    MySQL字段選擇合適數據類型

    在使用MySQL創建數據表時,經常會遇到如何為字段選擇合適的數據類型的問題,接下來我們一起分析字符串、數值、日期數據類型的選擇。
    的頭像 發表于 05-03 17:38 ?2762次閱讀
    <b class='flag-5'>MySQL</b>為<b class='flag-5'>字段</b>選擇合適數據類型

    一百道關于MySQL索引解答

    數據庫 1. MySQL索引使用有哪些注意事項? 可以從三個維度回答這個問題:索引哪些情況會失效,索引不適合哪些場景,索引規則 索引哪些情況會失效 查詢條件包含or,可能導致索引失效 如何字段類型
    的頭像 發表于 06-13 15:51 ?2073次閱讀

    MySQLvarchar(n) 中 n 最大取值為多少?

    那么a和b字段的數據值的長度分別只需要用1字節表示就行了,因為1字節能表示最大的字節數是 255,而 varchar(10) 類型的字段
    的頭像 發表于 12-05 14:07 ?743次閱讀

    mysql經典面試題及答案

    char、varchar的區別是什么? varchar是變長而char的長度是固定的。如果你的內容是固定大小的,你會得到更好的性能。
    的頭像 發表于 10-20 09:47 ?990次閱讀
    <b class='flag-5'>mysql</b>經典面試題及答案

    clob類型轉varchar方法

    CLOB類型和VARCHAR類型是數據庫中常用的數據類型,用于存儲可變長度的字符數據。CLOB類型用于存儲大文本數據,而VARCHAR類型適用于存儲較短的字符串數據。在某些情況下,我們可能需要
    的頭像 發表于 11-21 10:33 ?6627次閱讀

    CLOB類型的數據轉換為VARCHAR類型

    VARCHAR字段則適用于存儲小于或等于某個長度的字符數據。當我們需要將CLOB類型的數據轉換為VARCHAR類型時,可以使用以下方法: 使用數據庫函數:不同的數據庫系統提供了不同的函
    的頭像 發表于 11-21 10:39 ?5382次閱讀

    oracle修改表字段長度語句

    Oracle 修改表字段長度可以通過使用 ALTER TABLE 語句來實現。在對表進行修改之前,我們需要先了解一些基本的概念。 表字段長度是指在數據庫表中用來存儲數據的列的最大容量。當我們需要存儲
    的頭像 發表于 11-21 11:34 ?1933次閱讀