MySQL字符之char、varchar類型簡(jiǎn)析
前言
我們都知道,MySQL中關(guān)于字符,有char和varchar兩種常用的類型,可能在平時(shí)的使用過程中,大家不會(huì)去關(guān)心這兩種類型的區(qū)別,只是會(huì)用就可以了,或者說看到過一些它們的區(qū)別,但是沒有時(shí)間去測(cè)試,今天有時(shí)間了,我將這兩種類型的具體情況實(shí)驗(yàn)一把,讓大家直觀感受下,純屬分享,大神請(qǐng)繞道。
? 先說說理論吧。
? char類型為固定長(zhǎng)度的字符串,比如說char(10),它定義了指定的字符串長(zhǎng)度最大為10個(gè)字符,如果你現(xiàn)在輸入一個(gè)字符串為’12345678’,那么它在char類型中到底會(huì)占用多少個(gè)字符呢?答案是10個(gè),后面缺少的2個(gè)字符,MySQL會(huì)自動(dòng)補(bǔ)充為空值,然后進(jìn)行存放。在取這個(gè)記錄的時(shí)候,char類型的會(huì)使用trim()函數(shù)去掉多余的空格,所以我們看到的還是8個(gè)字符的記錄。當(dāng)輸入的字符長(zhǎng)度大于最大的長(zhǎng)度時(shí),MySQL會(huì)自動(dòng)報(bào)錯(cuò)。
? varchar類型是長(zhǎng)度可變的字符串,varchar(M)表示最大長(zhǎng)度是M個(gè)字符,varchar的最大實(shí)際長(zhǎng)度由最大的行的大小和使用的字符集確定。例如varchar(50)定義了一個(gè)最大長(zhǎng)度為50的字符串,如果插入的字符串只有20個(gè)字符,那么實(shí)際存儲(chǔ)的字符串具有21個(gè)字符,因?yàn)関archar會(huì)自動(dòng)包含一個(gè)字符串結(jié)束字符。varchar在值保存和檢索時(shí),尾部的空格仍然保留。
? 介紹完概念,我們來(lái)看具體的實(shí)踐過程,本文中使用的測(cè)試版本為MySQL5.7.22版本。
1.測(cè)試char的trim()功能
? 首先創(chuàng)建一個(gè)表,這個(gè)表里面包含兩個(gè)字段,d_char和d_varchar,設(shè)定初始的字符長(zhǎng)度都為4,如下:

查看一下,

此時(shí),我們插入兩條記錄,每條記錄都是’ab ',注意,ab后面有2個(gè)空格,

然后我們使用mysql里面的concat函數(shù)進(jìn)行字符連接,給每條記錄的左右分別添加小括號(hào),

此時(shí)我們可以看到,d_char的ab后面的空格被取消掉了,而d_varchar后面的空格還依舊存在。
2.測(cè)試兩種字符類型的最大長(zhǎng)度
首先看看char的最大長(zhǎng)度,我們?cè)O(shè)置的值為256,結(jié)果如下

所以,char類型的長(zhǎng)度取值范圍為0~255個(gè)字符
上面提到了varchar的最大實(shí)際長(zhǎng)度由最大的行的大小和使用的字符集確定,這里我們進(jìn)行實(shí)驗(yàn):

可以看到,字符集不一樣,最后的max的值也是不一樣的,
utf8模式下是0~21845,一個(gè)字符占三個(gè)字節(jié),最多能存 21844 個(gè)字符
latin1模式下是0~65535,一個(gè)字符占一個(gè)字節(jié),最多能存放 65532 個(gè)字符
gbk模式下是0~32767,一個(gè)字符占兩個(gè)字節(jié),最多能存 32766 個(gè)字符
若定義的時(shí)候超過上述限制,則varchar字段會(huì)被強(qiáng)行轉(zhuǎn)為text類型,并產(chǎn)生warning。
可能這里有人要問了,為什么最大值是32767,而最多只能放32766個(gè)字符呢?
舉兩個(gè)例說明一下實(shí)際長(zhǎng)度的計(jì)算。
a) 若一個(gè)表只有一個(gè)varchar類型,如定義為
create table t4(c varchar(N)) charset=gbk;
則此處N的最大值為(65535-1-2)/2= 32766 個(gè)字符。
減1的原因是實(shí)際行存儲(chǔ)從第二個(gè)字節(jié)開始’;
減2的原因是varchar頭部的2個(gè)字節(jié)表示長(zhǎng)度;
除2的原因是字符編碼是gbk。
b) 若一個(gè)表定義為
create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;
則此處N的最大值為 (65535-1-2-4-30*3)/3=21812
減1和減2與上例相同;
減4的原因是int類型的c占4個(gè)字節(jié);
減30*3的原因是char(30)占用90個(gè)字節(jié),編碼是utf8。
如果被varchar超過上述的b規(guī)則,被強(qiáng)轉(zhuǎn)成text類型,則每個(gè)字段占用定義長(zhǎng)度為11字節(jié),當(dāng)然這已經(jīng)不是“varchar”了。
則此處N的最大值為 (65535-1-2-4-30*3)/3=21812
3.MySQL的字段長(zhǎng)度模式
? 字段長(zhǎng)度的模式分為嚴(yán)格模式和不嚴(yán)格模式,在嚴(yán)格模式下,如果我們想給一個(gè)字段中插入一個(gè)大于規(guī)定長(zhǎng)度的字符串,MySQL會(huì)給出錯(cuò)誤提示,例如我們的表:

? 當(dāng)我們插入一個(gè)大于4字符的記錄時(shí),

? 如果在非嚴(yán)格模式下,mysql會(huì)自動(dòng)截?cái)喑鲎畲箝L(zhǎng)度的字符,

? 上面的操作是,我們先把字段模式改為非嚴(yán)格模式,然后查詢更改,確保更改生效,接著我們插入’abcde’字符串,發(fā)現(xiàn)它可以被成功執(zhí)行,但是包含兩個(gè)警告,查看警告可以發(fā)現(xiàn),一些數(shù)據(jù)被截?cái)嗔耍?/p>

實(shí)驗(yàn)部分的內(nèi)容基本就完成了,這里我們進(jìn)行幾點(diǎn)分析:
1.MySQL為什么要設(shè)置這兩種類型?它們各自有什么優(yōu)點(diǎn)?
? char是固定長(zhǎng)度的,它的存取速度比varchar快,方便程序的存儲(chǔ)于查找,但是它需要浪費(fèi)一定的空間,可以看做是一種以空間換時(shí)間的方法。
? 而varchar的特點(diǎn)是可變長(zhǎng),當(dāng)定義一個(gè)varchar(10)而只存入了4個(gè)字符,此時(shí)varchar會(huì)直接將字符記錄的長(zhǎng)度變?yōu)?,從而節(jié)省空間,它可以看做是一種用時(shí)間換取空間的方法。
? char的存儲(chǔ)方式是,對(duì)英文字符(ASCII)占用1個(gè)字節(jié),對(duì)一個(gè)漢字占用兩個(gè)字節(jié);而varchar的存儲(chǔ)方式是,對(duì)每個(gè)英文字符占用2個(gè)字節(jié),漢字也占用2個(gè)字節(jié),兩者的存儲(chǔ)數(shù)據(jù)都非unicode的字符數(shù)據(jù)。
2.兩種類型適應(yīng)的情況分析。
關(guān)于char:
? CHAR適合存儲(chǔ)很短的字符串,或者所有值都接近同一個(gè)長(zhǎng)度。
? 對(duì)于經(jīng)常變更的數(shù)據(jù),CHAR也比VARCHAR更好,因?yàn)槎ㄩL(zhǎng)的CHAR類型不容易產(chǎn)生碎片。
對(duì)于非常短的列,CHAR在存儲(chǔ)空間上也更有效率。例如用char(1)來(lái)存儲(chǔ)只有Y和N的值,只需要一個(gè)字節(jié),但是varchar卻需要兩個(gè)字節(jié),因?yàn)檫€一個(gè)記錄長(zhǎng)度的額外字節(jié)。
關(guān)于varchar
? VARCHAR類型用于存儲(chǔ)可變長(zhǎng)字符串,是最常見的字符串?dāng)?shù)據(jù)類型。它比定長(zhǎng)類型 更節(jié)省空間,因?yàn)樗鼉H使用必要的空間(例如,越短的字符串使用越少的空間)。
? VARCHAR節(jié)省了存儲(chǔ)空間,所以對(duì)性能也有幫助。但是,由于行是變長(zhǎng)的,在UPDATE時(shí)可能使行變得比原來(lái)更長(zhǎng),這就導(dǎo)致需要做額外的工作。如果一個(gè)行占用 的空間增長(zhǎng),并且在頁(yè)內(nèi)沒有更多的空間可以存儲(chǔ),在這種情況下,不同的存儲(chǔ)引擎的處理方式是不一樣的。例如,MyISAM會(huì)將行拆成不同的片段存儲(chǔ),InnoDB 則需要分裂頁(yè)來(lái)使行可以放進(jìn)頁(yè)內(nèi)。
? VARCHAR需要使用1或2個(gè)額外字節(jié)記錄字符串的長(zhǎng)度:如果列的最大長(zhǎng)度小于或等于255字節(jié),則只使用1個(gè)字節(jié)表示,否則使用2個(gè)字節(jié)。假設(shè)采用latinl字符集 ,一個(gè)varchar(10)的列需要11個(gè)字節(jié)的存儲(chǔ)空間。varchar(1000)的列則需要1002個(gè)字節(jié),因?yàn)樾枰?個(gè)字節(jié)存儲(chǔ)長(zhǎng)度信息。
適用情況:
? 1、對(duì)于MyISAM表,盡量使用Char,對(duì)于那些經(jīng)常需要修改而容易形成碎片的myisam和isam數(shù)據(jù)表就更是如此,它的缺點(diǎn)就是占用磁盤空間;
? 2、對(duì)于InnoDB表,因?yàn)樗臄?shù)據(jù)行內(nèi)部存儲(chǔ)格式對(duì)固定長(zhǎng)度的數(shù)據(jù)行和可變長(zhǎng)度的數(shù)據(jù)行不加區(qū)分(所有數(shù)據(jù)行共用一個(gè)表頭部分,這個(gè)標(biāo)頭部分存放著指向各有關(guān)數(shù)據(jù)列的指針),所以使用char類型不見得會(huì)比使用varchar類型好。事實(shí)上,因?yàn)閏har類型通常要比varchar類型占用更多的空間,所以從減少空間占用量和減少磁盤i/o的角度,使用varchar類型反而更有利;
? 3、存儲(chǔ)很短的信息,比如門牌號(hào)碼101,201……這樣很短的信息應(yīng)該用char,因?yàn)関archar還要占個(gè)byte用于存儲(chǔ)信息長(zhǎng)度,本來(lái)打算節(jié)約存儲(chǔ)的現(xiàn)在得不償失。
? 4、固定長(zhǎng)度的。比如使用uuid作為主鍵,那用char應(yīng)該更合適。因?yàn)樗潭ㄩL(zhǎng)度,varchar動(dòng)態(tài)根據(jù)長(zhǎng)度的特性就消失了,而且還要占個(gè)長(zhǎng)度信息。
? 5、十分頻繁改變的column。因?yàn)関archar每次存儲(chǔ)都要有額外的計(jì)算,得到長(zhǎng)度等工作,如果一個(gè)非常頻繁改變的,那就要有很多的精力用于計(jì)算,而這些對(duì)于char來(lái)說是不需要的。
關(guān)于MySQL之char、varchar,你學(xué)廢了么?
總結(jié)
到此這篇關(guān)于MySQL字符之char、varchar類型簡(jiǎn)析的文章就介紹到這了,更多相關(guān)MySQL之char、varchar類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql聚合統(tǒng)計(jì)數(shù)據(jù)查詢緩慢的優(yōu)化方法
這篇文章主要給大家介紹了關(guān)于mysql聚合統(tǒng)計(jì)數(shù)據(jù)查詢緩慢的優(yōu)化方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
navicat連接mysql報(bào)錯(cuò)10060的解決辦法
最近在學(xué)習(xí)中遇到了個(gè)小問題,現(xiàn)在將解決的辦法分享給同樣遇到這個(gè)問題的同學(xué),這篇文章主要給大家介紹了關(guān)于navicat連接mysql報(bào)錯(cuò)10060的解決辦法,需要的朋友可以參考下2023-03-03
com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver&n
大家在連接mysql的時(shí)候,啟動(dòng)項(xiàng)目,會(huì)警告你推薦使用com.mysql.cj.jdbc.Driver?而不是com.mysql.jdbc.Driver,本文主要介紹了com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver 的區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
mysql導(dǎo)入csv的4種報(bào)錯(cuò)的解決方法
這篇文章主要介紹了mysql導(dǎo)入csv的4種報(bào)錯(cuò)的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
MySQL數(shù)據(jù)庫(kù)基本SQL語(yǔ)句教程之高級(jí)操作
對(duì)MySQL數(shù)據(jù)庫(kù)的查詢,除了基本的查詢外,有時(shí)候需要對(duì)查詢的結(jié)果集進(jìn)行處理,下面這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫(kù)基本SQL語(yǔ)句教程之高級(jí)操作的相關(guān)資料,需要的朋友可以參考下2022-06-06
Mysql中TIMESTAMPDIFF函數(shù)的語(yǔ)法與練習(xí)案例
在應(yīng)用時(shí)經(jīng)常要使用這兩個(gè)函數(shù)TIMESTAMPDIFF和TIMESTAMPADD,下面這篇文章主要給大家介紹了關(guān)于Mysql中TIMESTAMPDIFF函數(shù)的語(yǔ)法與練習(xí)案例的相關(guān)資料,需要的朋友可以參考下2022-09-09
linux(Centos7)下安裝mysql8.0.18的教程圖解
這篇文章主要介紹了linux(Centos7)安裝mysql8.0.18的教程,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11

