MySql分層結(jié)構(gòu):

1.MySQL中InnoDB與MyISAM的區(qū)別:
a.InnoDB引擎是MySql的默認(rèn)引擎(從5.5.8版本開始),支持事務(wù),采用行級鎖,支持外鍵,默認(rèn)非鎖定讀,其設(shè)計主要作為OLTP(Online Transaction Processing,即在線事務(wù)處理)的應(yīng)用。
b.MyISAM引擎不支持事務(wù)和表鎖設(shè)計,但支持全文索引,主要面向OLAP(Online Analytical Processing,即在線分析處理)。
2.InnoDB的體系結(jié)構(gòu)

2.1.后臺線程
主要負(fù)責(zé)刷新內(nèi)存池中的數(shù)據(jù),保存緩存池中的內(nèi)存緩存的是最近的數(shù)據(jù),還負(fù)責(zé)將修改的數(shù)據(jù)文件刷新的磁盤文件,同時保證數(shù)據(jù)庫發(fā)生異常的情況下mysql能夠恢復(fù)到正常運(yùn)行狀態(tài)。
2.1.1 Master Thread
作為核心后臺線程,Master Thread 負(fù)責(zé)緩沖池中的數(shù)據(jù)異步刷新到磁盤,保證數(shù)據(jù)的一致性。
Master Thread的演進(jìn):
1.InnoDB 1.0.*之前
算法結(jié)構(gòu)
public void masterThread() {
while(true) {
for(int i=0;i<10;i++) {
/**
1.將重做日志緩存刷到磁盤里的重做日志文件,即使事務(wù)還沒有提交;
2.合并插入緩存(以當(dāng)前1秒內(nèi)IO次數(shù)是否小于5為界限,小于5在執(zhí)行);
3.刷最多100個臟頁到磁盤(臟頁比例是否超過設(shè)置的閥值);
4.如果當(dāng)前沒有用戶活動,則切換到background循環(huán)中。
*/
do thing per second;
Thread.sleep(1000*1);
}
/**
1.刷100個臟頁到磁盤(在10秒內(nèi)IO次數(shù)小于200次的情況下);
2.合并最多5個插入緩存;
3.將日志緩沖刷到磁盤;
4.刪除無用的undo頁;
5.刷100個或10個臟頁到磁盤(當(dāng)臟頁比例大于70%時刷100個臟頁,否則刷10個臟頁)
*/
do thing per 10 seconds;
}
}
background循環(huán):
1.刪除無用的undo頁;
2.合并20個插入緩沖;
3.調(diào)回到主循環(huán)
2.InnoDB 1.2.*之前
通過分析InnoDB 1.0.*版本,我們知道InnoDB采用硬編碼的方式實現(xiàn),InnoDB 1.2.*版本支持用戶來自定義IO吞吐量,通過innodb_io_capacity參數(shù)來設(shè)置,這樣就適應(yīng)了高性能和低性能的磁盤,另外還有innodb_max_dirty_pages_pct來設(shè)置臟頁在緩沖池的百分比。另外還可以配置innodb_adaptive_flushing和innodb_purge_batch_size可以設(shè)置。
3.InnoDB 1.2.*:
算法結(jié)構(gòu):
if(innodb is idle) {
do 10秒間隔的操作
} else {
do 1秒間隔的操作
}
另外,對于刷臟頁的操作,innoDB從Master Thread 分離出了單獨線程Page Cleaner Thread,減輕了Master Thread的工作。
2.1.2 IO Thread
InnoDB大量使用了Async IO 來處理IO請求,極大的提高了數(shù)據(jù)庫性能,IO Thread主要負(fù)責(zé)這些IO請求的回調(diào)(call back)。
2.1.3 Purge Thread
當(dāng)事務(wù)被提交之后,其所使用的undolog就不再需要了,Purge Thread主要負(fù)責(zé)回收這些undo數(shù)據(jù)所占用的空間。
2.1.4 Page Cleaner Thread
主要負(fù)責(zé)臟頁(即緩沖池中的頁和磁盤中的頁數(shù)據(jù)不一致)的刷新操作,減輕Master Thread的負(fù)擔(dān),提高引擎性能。
2.2.內(nèi)存
2.2.1 緩沖池
緩存為了解決CPU和磁盤之間速度的鴻溝,來提高基于磁盤的數(shù)據(jù)庫系統(tǒng)的整體性能。針對數(shù)據(jù)庫頁的修改,InnoDB則先修改緩沖池中的頁,然后再以一定的頻率刷新到磁盤上,而不是每次頁有修改就刷新到磁盤上。
2.2.2 重做日志緩沖
InnoDB首先將重做日志信息放入到緩沖區(qū),然后按照一定的頻率將其刷新到外部磁盤的重做日志文件。一般情況下1秒刷新就會刷新一次,因此重做日志緩沖緩沖的大小不需要很大,8MB基本都能夠滿足。在下列三種情況下會刷新重做日志緩沖到外部磁盤的重做日志文件:
a.Master Thread 每秒將重做日志緩沖刷新到重做日志文件;
b.每次事務(wù)提交時會將重做日志緩沖刷新到重做日志文件;
c.當(dāng)重做日志緩沖剩余空間小于1/2時,將重做日志緩沖刷新到重做日志文件。
2.2.3 額外內(nèi)存池
在InnoDB引擎中,對數(shù)據(jù)進(jìn)行內(nèi)存分配時,首先充額外的內(nèi)存池中進(jìn)行申請,當(dāng)該區(qū)域的內(nèi)存不夠時,才會從緩沖池中申請。
2.3 CheckPoint(檢查點)技術(shù)
為了協(xié)調(diào)CPU和磁盤速度的鴻溝,因此頁的操作都是在緩沖池中進(jìn)行的。若每一次的頁變化都將其刷新到磁盤中,那么開銷巨大。InnoDB在事務(wù)提交時,采用先寫重做日志,再修改頁,這樣系統(tǒng)宕機(jī)時,可以通過重做日志來恢復(fù),而不會導(dǎo)致數(shù)據(jù)丟失。CheckPoint實現(xiàn)了在數(shù)據(jù)庫宕機(jī)時,不需要重做所有日志,因為在CheckPoint之前的數(shù)據(jù)都已經(jīng)刷到了磁盤里,故數(shù)據(jù)庫只需要對CheckPoint之后的重做日志進(jìn)行恢復(fù)即可,這樣極大地縮短了恢復(fù)時間,同樣也減少了重做日志所占的磁盤空間(只需要保存CheckPoint之后的重做日志)。
CheckPoint刷數(shù)據(jù)的兩種方式:
a.Sharp CheckPoint 每次發(fā)生數(shù)據(jù)庫關(guān)閉時,將所有臟頁刷到磁盤,對數(shù)據(jù)庫可用性產(chǎn)生很大影響。
b.Fuzzy CheckPoint 每次發(fā)生數(shù)據(jù)庫關(guān)閉時,將部分臟頁刷到磁盤,而不是所有臟頁。
2.4 InnoDB特性
2.4.1 插入緩存(Insert Buffer)
針對非聚集索引的更新和插入操作(要求是非聚集索引,且索引不是unique的,因為數(shù)據(jù)庫不去查找索引頁來判斷插入記錄的唯一性),不是每次都是直接插入到索引頁中,而是先判斷插入的非聚集索引頁是否在緩沖池中,如果在,則直接插入;否則先放到一個Insert Buffer對象中,然后再以一定的頻率和情況將Insert Buffer對象和非聚集索引葉子節(jié)點的進(jìn)行合并(即多步合成一步),大大提高了非聚集索引的插入性能。缺點:遇到段時間內(nèi)大量寫的情況,Insert Buffer會占用使用過多的緩沖池空間,影響性能,如果此時宕機(jī),會導(dǎo)致大量的Insert Buffer對象中的數(shù)據(jù),沒有合并到非聚集索引中,影響系統(tǒng)恢復(fù)效率。
Insert Buffer也是由一個B+樹構(gòu)成,MySql 4.1版本之后,每個數(shù)據(jù)庫實例只有一個Insert Buffer對象。
2.4.2 兩次寫(Double Write)
在對系統(tǒng)重做日志前,用戶需要一個頁的副本,當(dāng)寫入失敗時,先通過副業(yè)來還原對應(yīng)的頁,再執(zhí)行重做日志。補(bǔ)充了重做日志只對頁進(jìn)行操作的粗粒度的弊端。
2.4.3 自適應(yīng)Hash索引(Adaptive Hash Index)
Hash算法在不沖突的情況下,時間復(fù)雜度為O(1),效率明顯高于B+樹。InnoDB通過監(jiān)控表上的索引頁的查詢,如果監(jiān)控到通過建立Hash索引可以帶來速度提升,則InnoDB會通過緩沖池的B+樹頁來構(gòu)造,創(chuàng)建Hash索引,不需要人為控制調(diào)整,故稱為自適應(yīng)Hash索引。
2.4.4 異步IO(Asynchronous IO)
InnoDB中,read ahead方式的讀取都是通過AIO實現(xiàn)的,另外臟頁的刷新(寫入到磁盤)也是由AIO完成。
3.數(shù)據(jù)存儲

說明:
namespace表空間:所有數(shù)據(jù)都保存在namespace中,如果innodb_file_per_table停用(默認(rèn)停用),所有的數(shù)據(jù)保存在共享表空間ibdata1中;innodb_file_per_table啟用,每張表的表空間存放的有數(shù)據(jù)、索引和插入緩存Bitmap頁數(shù)據(jù),其他如回滾undo信息,插入緩存索引頁,系統(tǒng)事務(wù)信息,二次寫緩沖等還是保存在共享表空間ibdata1中。
segment段:namespace由segment構(gòu)成,常見的有數(shù)據(jù)段(B+樹的葉子節(jié)點),索引段(B+樹的非葉子節(jié)點),回滾段等。segment由Innodb自動管理,DBA無法管理。
extent區(qū):segment由extent構(gòu)成,extent由連續(xù)的page組成的空間,大小都是1MB,不可設(shè)置。
page頁:page是InnoDB磁盤管理的最小單位,默認(rèn)大小為16KB,可設(shè)置。
row行: MySQL數(shù)據(jù)按行存放,即數(shù)據(jù)庫中的一條數(shù)據(jù)記錄。
4.事務(wù)(Transaction)
4.1 事務(wù)的特性:
原子性(Atomicity):由redo log和undo log實現(xiàn);
一致性(Consistency):由undo log實現(xiàn);
隔離性(Isolation):由鎖實現(xiàn);
持久性(Durability):由redo log實現(xiàn)。
4.2 事務(wù)隔離級別:
1.RU(Read UnCommitted) 讀未提交;
2.RC(Read Commited) 不可重復(fù)讀;
3.RR(Repeatable Read) 可重復(fù)讀;
4.Serializable 串行化。
4.3 分布式事務(wù):
分布式事務(wù)指允許多個獨立的事務(wù)資源(Transactional Resources,如一個事務(wù)涉及到一個是MySQL,一個是Oracle,還有一個SQLServer)參與到一個全局事務(wù)中。
MySQL通過XA事務(wù)來支持分布式事務(wù),XA事務(wù)允許不同數(shù)據(jù)庫之間的分布式事務(wù)。在分布式事務(wù)時,InnoDB的事務(wù)隔離級別必須是最高級別,即Serializable 串行化。

分布式事務(wù)采用兩段式提交(two-phase commit)方式:
第一階段:所有參與全局事務(wù)的節(jié)點都開始準(zhǔn)備,然后告訴事務(wù)管理器他們準(zhǔn)備好提交了。
第二階段:事務(wù)管理器告訴資源管理器執(zhí)行commit或者rollback,如果任何一個節(jié)點顯示不能commit,則所有節(jié)點都被告知需要rollback。
備注:應(yīng)避免循環(huán)commit,自動commit和自動rollback。
5.索引
InnoDB支持的索引有:
5.1 B+(Balance+)樹索引
B+樹是平衡二叉樹的擴(kuò)展,B+樹索引不能夠找到一個給定鍵值的具體行,B+樹索引找到的知識查找數(shù)據(jù)行所在的頁(即InnoDB進(jìn)行磁盤管理的最小單位,默認(rèn)為16K),讓后數(shù)據(jù)庫把頁讀入到內(nèi)存,再在內(nèi)存中進(jìn)行查找,最后得到要查找的數(shù)據(jù)。
在數(shù)據(jù)庫中,B+樹的一般高度都在2~4層,太高了會影響查詢性能,畢竟搜索到每一層都需要IO。一般千萬級別的數(shù)據(jù)量3層就足夠了,如果數(shù)據(jù)量超過千萬級別,那么最好的方式還是分庫分表。
5.1.1 聚集索引
聚集索引(clustered index)按照每張表的主鍵構(gòu)造一顆B+樹,同時葉子節(jié)點(又稱數(shù)據(jù)頁)存放的即為整張表的行記錄數(shù)據(jù)(注意:聚集索引的存儲是邏輯上連續(xù)的,而不是物理上連續(xù)的),即葉子節(jié)點上保存了完整的每行的記錄,而在非葉子節(jié)點中存放的只有鍵值和指向子節(jié)點的偏移量,每個聚集索引的葉子節(jié)點都通過一個雙向鏈表連接。 因為葉子節(jié)點只能按照一顆B+樹進(jìn)行排序,因此每張表只能夠創(chuàng)建一個聚集索引。
聚集索引和主鍵的關(guān)系與區(qū)別:
關(guān)系:
a.如果一個表定義了主鍵,那么這個主鍵就是聚集索引;
b.如果表沒有定義主鍵,那么該表的第一個唯一非空索引作為聚集索引;
c.如果沒有主鍵和唯一非空索引,那么innodb內(nèi)部會生成一個隱藏的主鍵作為聚集索引(隱藏主鍵是一個6字節(jié)的自增列)。
區(qū)別:
| 屬性 | 主鍵 | 聚集索引 |
|---|---|---|
| 個數(shù) | 一個表可以創(chuàng)建多個主鍵 | 一個表只能創(chuàng)建一個聚集索引 |
| 是否允許為NULL | 不可以 | 可以 |
| 是否要求唯一 | 要求 | 不要求,可以通過單獨設(shè)置為否限制唯一 |
自增主鍵的優(yōu)缺點:
優(yōu)點:速度快,數(shù)字型空間小,數(shù)據(jù)庫可以自己控制主鍵自動增長;
缺點:插入指定ID的數(shù)據(jù)時,很難保證主鍵沖突;分庫和分表情況下,自增主鍵將是一個很大的挑戰(zhàn)。
5.1.2 非聚集索引
非聚集索引的葉子節(jié)點并不包含行記錄的所有數(shù)據(jù),葉子節(jié)點包含了鍵值和書簽(書簽告訴InnoDB哪里可以找到與索引相應(yīng)的行數(shù)據(jù),即相應(yīng)行數(shù)據(jù)的聚集索引鍵),因此效率和聚集索引沒法比,幾乎耗時是聚集索引的兩倍,不過一張表上可以創(chuàng)建多個非聚集索引。
5.1.3 Cardinality值
Cardinality值表示索引中不重復(fù)記錄的預(yù)估值,不是一個準(zhǔn)確值,因為為了不影響數(shù)據(jù)庫性能,Cardinality值是通過采樣獲得的。當(dāng)Cardinality/Table_total_count值越大(最大值為1),B+樹索引創(chuàng)建的價值越大;當(dāng)值很小時,沒有必要創(chuàng)建B+索引。
5.2 全文檢索
為解決SQL的like '%XXX%' 不走索引的問題,MySQL使用了倒排索引(和Elastic Search一樣),從MySQL 5.7.6開始已經(jīng)支持中文了,但只能在CHAR、VARCHAR或者TEXT的字段上創(chuàng)建全文索引,而且要使用相同的字符集和排列規(guī)則,且每張表只能有一個全文索引。
正式由于這些問題,所以搜索很難達(dá)到Elastic Search的性能,故很少使用MySql的全文檢索。
5.1.4 索引下推(Mysql5.6以后版本):
索引下推是針對非主鍵的復(fù)合索引查詢的場景,減少回表查詢次數(shù),舉例:
user(id、name、age)表,id為主鍵,(name,age)為聯(lián)合索引。
執(zhí)行SQL:
select * from user where name like '張%' and age=30
1.不使用索引下推執(zhí)行過程(回表兩次):
a.先執(zhí)行name like '張%',獲得id;
b.根據(jù)id通過主鍵索引獲取查詢數(shù)據(jù)(回表);
c.根據(jù)b的結(jié)果過濾掉age <> 30的,獲得符合age=30的數(shù)據(jù)的id;
d.根據(jù)id通過主鍵索引獲取查詢數(shù)據(jù)(回表)。
2.使用索引下推執(zhí)行過程(回表一次)
a.先執(zhí)行l(wèi)ike '張%' and age=30,獲得id;
b.根據(jù)id通過主鍵索引獲取查詢數(shù)據(jù)(回表)。
在執(zhí)行計劃中,Using index condition表示使用索引下推。
https://baijiahao.baidu.com/s?id=1664831035473859908&wfr=spider&for=pc
6.鎖
鎖用來管理對共享資源的并發(fā)訪問,從而提供數(shù)據(jù)的完整性和一致性。
鎖的類型:
共享鎖:允許事務(wù)讀一行數(shù)據(jù);
排它鎖:允許事務(wù)刪除或更新一行數(shù)據(jù)。
行鎖的算法:
1.Record Lock 單個行記錄上的鎖,總是鎖住索引記錄,如果沒有索引,則鎖定隱式主鍵;
2.Gap Lock 間隙鎖 鎖定一個范圍,但不包含記錄本身;
舉例來說,假如student表中只有1001條記錄,其student_id的值分別是1,2,...,1000,1001,下面的SQL:
SELECT * FROM student WHERE student_id > 1000 FOR UPDATE
是一個范圍條件的檢索,InnoDB不僅會對符合條件的student_id值為1001的記錄加鎖,也會對student_id大于101的“間隙”加鎖,雖然這些記錄并不存在。
3.Next-Key Lock 即Record Lock + Gap Lock 鎖定一個范圍,并包含記錄本身。
6.1 臟讀
臟讀是指在不同的事務(wù)環(huán)境下,當(dāng)前事務(wù)可以讀到其他事務(wù)未提交的數(shù)據(jù)。

6.2 不可重復(fù)讀
不可重復(fù)讀是指在一個事務(wù)內(nèi),多次讀取同一個數(shù)據(jù)集合,得到的結(jié)果集不一樣(其他事務(wù)同時在做修改這個結(jié)果集包含的內(nèi)容,并且已經(jīng)commit)

6.3 幻讀
幻讀是指一個事務(wù)內(nèi),在前后兩次范圍查詢(不是等于,如where age > 20)的時候,后一次查詢看到了前一次查詢沒有看到的數(shù)據(jù)。
產(chǎn)生幻讀的原因是,行鎖只能夠鎖住行,但是針對插入數(shù)據(jù)這個動作,更新的是已有記錄的間隙中,為解決幻讀,MySql引入了間隙鎖。
6.4 間隙鎖(Next Key鎖)
當(dāng)我們的sql執(zhí)行范圍查詢并請求共享鎖或者排它鎖的時候,InnoDB會給符合條件的已有數(shù)據(jù)記錄的索引項加鎖,對于健值在條件范圍內(nèi)但不存在的記錄,稱為間隙。InnoDB對間隙加的鎖,稱為間隙鎖。間隙鎖一方面解決了幻讀,滿足了隔離級別的要求;另一方面滿足了恢復(fù)和復(fù)制的需要。
間隙鎖的使用會導(dǎo)致符合條件范圍的數(shù)據(jù)插入的阻塞,使用不當(dāng)為導(dǎo)致嚴(yán)重的鎖等待,因此在實際開發(fā)中,應(yīng)避免使用范圍條件,特別是并發(fā)較高的場景。
6.5 MVCC (Multi-Version Concurrency Control)
MySQL InnoDB通過版本號MVCC(Multi-Version Concurrency Control)實現(xiàn)事務(wù)隔離,實現(xiàn)可重復(fù)度,MVCC實現(xiàn)方式中,每行數(shù)據(jù)記錄含有隱藏的兩列數(shù)據(jù)
DATA_TRX_ID:事務(wù)的id,長度為6Byte
DATA_ROLL_PTR:表示回滾指針,指向該行回滾段 (rollback segment)的指針,長度為7 Byte,記錄改行數(shù)據(jù)的所有未提交的舊版本數(shù)據(jù),在undo中都通過鏈表的形式存儲。
具體規(guī)則如下:
a.select情況:
InnoDB只會查找版本小于或者等于當(dāng)前事務(wù)版本的數(shù)據(jù)行(即行的系統(tǒng)版本小于或等于事務(wù)的系統(tǒng)版本號),這樣確保了事務(wù)讀取的行是當(dāng)前事務(wù)開始之前已經(jīng)存在的行,或者是事務(wù)自己自身插入或者修改的行。
b.insert情況:
InnoDB為新插入的每一行記錄保存事務(wù)的id作為DATA_TRX_ID的值。
c.delete情況:
InnoDB為刪除的每一行記錄保存事務(wù)的id作為DATA_TRX_ID的值,回滾指針指向舊的版本數(shù)據(jù)。
d.update情況:
InnoDB為新插入的每一行記錄保存當(dāng)前系統(tǒng)的版本號作為行版本號,同時保存當(dāng)前系統(tǒng)版本號到原來的行作為行刪除標(biāo)示。
6.6 丟失更新

6.7 死鎖
死鎖是指兩個或兩個以上事務(wù)在執(zhí)行過程中,因為相互爭奪共享資源而造成的一種互相等待的現(xiàn)象。
解決死鎖的方式:
1.超時閥值設(shè)置;
2.通過等待圖來主動死鎖檢測,如果等待圖中存在回路,就代表存在死鎖。;
7 主從復(fù)制
MySQL主從復(fù)制的步驟:
+a.Master把數(shù)據(jù)修改記錄保存到二進(jìn)制日志binary log中;
+b.Slave把Master的binary log日志copy到自己的中繼日志replay log中;
+c.Slave重做中繼日志,將更改作用到自己的數(shù)據(jù)庫上,以達(dá)到主從數(shù)據(jù)的最終一致性。

7.1復(fù)制的方式
a.基于SQL語句的復(fù)制
Master記錄那些更改數(shù)據(jù)的SQL到日志文件,Slave獲取該SQL日志文件,然后再執(zhí)行一遍Master執(zhí)行過的SQL。
優(yōu)點:
實現(xiàn)簡單,主從數(shù)據(jù)傳輸量很小,占用帶寬很少。如果出現(xiàn)問題可以很好的根據(jù)SQL語句去定位。
缺點:
更新必須是串行的,另外,Master和Slave執(zhí)行SQL的時間和環(huán)境不同,會出現(xiàn)Master執(zhí)行成功,Slave執(zhí)行失敗的問題,而且錯誤具有累積性。如果在使用觸發(fā)器或者存儲過程,最好不要使用基于SQL的復(fù)制模式。
b.基于行的復(fù)制
Master將實際數(shù)據(jù)記錄保存到Binary log中,Slave獲取該Binary log文件,然后更改對應(yīng)的數(shù)據(jù)行。
優(yōu)點:
使用場景廣,可以正確的復(fù)制每一行,錯誤不具有累加性。
缺點:
針對一次修改數(shù)據(jù)量很大的情況,該方法會保存大量的Binary log數(shù)據(jù),給Master和復(fù)制造成很大的負(fù)載,影響數(shù)據(jù)庫性能。由于沒有記錄SQL語句,出現(xiàn)問題后,無法判斷是那些SQL導(dǎo)致的問題。
c.折中
MySQL能夠在這兩種復(fù)制模式間動態(tài)切換,默認(rèn)情況下使用基于SQL語句的復(fù)制,如果發(fā)現(xiàn)SQL語句無法正確的復(fù)制,就切換到基于行的復(fù)制模式。
7.2 復(fù)制的常見問題
Master過大的包,過大的復(fù)制延遲,受限的寬帶,磁盤空間,主從系統(tǒng)配置不一樣,加鎖引起的鎖爭用,數(shù)據(jù)損壞,以及不確定性更改(update ... limit 5)等問題。
8 MySql緩存

緩存的問題:
1.開啟緩存之后,每次select開始之前先檢查是否命中緩存,帶來性能問題,特別是緩存命中率不高的情況時;
2.select結(jié)果被緩存時,也帶來性能開銷;
3.某個表被寫入時,改表的所有緩存都會失效;
4.join操作會導(dǎo)致緩存失效;
5.事務(wù)也影響mysql緩存,在事務(wù)commit之后,數(shù)據(jù)才能夠緩存。
9 MySql實踐問題
9.1 varchar(n)保存數(shù)據(jù)長度問題
MySql 4.0 之前的版本
n指的是n個字節(jié),如果存放utf-8格式只能保存 (n / 3)個漢字,即如果varchar(20) 那么只能保存6個漢字;
MySql 5.0 之后的版本
n指的是n個字符,如果存放utf-8格式,那么無論是數(shù)字,字母還是漢字,都可存放n個,即如果varchar(20) 那么可以保存20個漢字(自己親測可以);
gbk類型:
varchar(n)中每個字符最多占2個字節(jié),最大長度不能超過(65535 / 2);
utf-8類型:
varchar(n)中每個字符最多占3個字節(jié),最大長度不能超過(65535 / 3);