mysql的char,varchar,text,blob的幾點我的理解

mysql的char,varchar,text,blob是幾個有聯繫可是有有很大區別的字段類型,這算是mysql的基礎吧,但是基礎沒有學好,惡補一下。 php

先簡單的總結一下: mysql

char:定長,最大255個字符 算法

varchar:變長,最大65535個字符(既是單列的限制,又是整行的限制) sql

text:變長,有字符集的大對象,並根據字符集進行排序和校驗,大小寫不敏感 數據庫

blob:變長,無字符集的二進制大對象,大小寫敏感 spa

如下只是我我的的理解,才疏學淺,望各路高人指點。 code

我使用的引擎是myisam,因此如下的探討是集中在myisam上的。 對象

首先解釋char,char是項目中經常使用的字段類型之一,它表明的含義是採用固定長度存儲數據,換句話說,數據初始化的是就爲該類型的字段分配固定長度的存儲空間,即便沒有達到存儲空間的長度,實際佔用的存儲空間也是定義時的長度。舉個例子來講,好比某字段 a     char(50),指定的長度是50個字符的存儲空間,那麼當你存入一個字符:「abc」的時候,實際上字符長度是3個字符,可是佔用的硬盤空間仍是50個字符。很顯然,char的缺點就出來了:浪費存儲空間!可是同時char的優勢也顯示出來了:固定長度,(索引)效率極高,不存在碎片blog

這裏咱們再探討一下char的存儲方式,雖然char會浪費極大的存儲空間,可是你想過對於字符串的先後空格char是如何處理的嗎?當存儲的字符串沒有達到char的最大長度時,字符串後面是不會以空格來填充的,並且char會過濾字符串末端的空格而後存儲,而在比較字符串的時候又會自動空格填充到字符串的末端。 排序

好了,對char有了瞭解之後,對varchar的理解也就容易了。

varchar是存儲可變長度的字符串,簡單的說咱們定義表機構的時候指定的字段長度是最大長度,當字符串沒有達到最大長度的時候以字符串的實際長度來存儲的,不佔用多餘的存儲空間。所以,通常狀況下,varchar比char節省存儲空間,可是也常常有例外,後面接着探討這個問題。

一個特殊的狀況是建立表的時候採用ROW_FORMAT=FIXED選項(默認的是ROW_FORMAT=DYNAMIC),那麼mysql就會爲每行數據分配固定長度的存儲空間,固然這是特例。不知道你有沒有想過:爲何有管理員願意這樣作呢?對varchar分配固定長度的存儲空間是有道理的。舉一個常見的例子,假設採用DYNAMIC默認選項,那麼咱們建立一個字段b  varchar(100),如今咱們插入一個只有10個字符的數據:abcdefghij,很好,只佔用了10個字符的空間,相比char節省了很多存儲空間。可是你想到問題了嗎?好比某天之後你發現這個字段須要更新一下,更新爲20個字符的數據:abcdefghijklmnopqrst,你知道數據庫該如何存儲嗎?原先的存儲位置分配的只有10個字符的空間,如今要存儲20個字符,小於長度限制(最大長度是100個字符),問題就來了,mysql會如何處理呢?這裏接下來可能要探討mysql存儲層面的分頁機制或者拆分機制,就再也不繼續深刻了。總之不管mysql採起什麼方式,確定會在磁盤上造成碎片,長此以往造成的磁盤碎片對系統效率是一個致命的打擊,因此咱們常常看到有管理員要把mysql導出而後導入,就是爲了解決這個問題,提升效率。

上面咱們提出來了一個問題:varchar比char節省存儲空間,可是也常常有例外!對於這個疑問咱們如何理解呢?要深刻分析這個問題,咱們須要再次深刻了解varchar的存儲機制。經常使用的中文存儲通常採用gbk或者utf-8兩種字符集,gbk每一個字符佔2個字節,utf-8每一個字符佔3個字節,因此:gbk字符集的最大存儲長度是

(65535-1-1)/2= 32766或者(65535-1-2)/2= 32766,這個算法的含義是:65535是varchar的最大長度,第一個-1表示實際存儲位置是從第二位開始的,第二個-1或者-2表明的含義是:varchar 字段是將實際內容單獨存儲在聚簇索引以外,內容開頭用1到2個字節表示實際長度(長度小於255時用1個字節,長度超過255時須要2個字節),除以2的緣由是一個gbk字符集的字符佔2個字節長度,因此根據狀況能夠得出gbk字符集的最大存儲長度是32766。

那麼UTF-8字符集呢?算法以下:

(65535-1-1)/3=  21844或者(65535-1-2)/3= 21844減1減2的含義同上,除以3的含義是一個utf-8的字符集字符佔用實際長度是3個字節。

看完了這段你就能理解char(1)和varchar(1)佔用的存儲空間了吧?在這個極端狀況下,很顯然char更節省存儲空間,由於char沒有管理數據的額外開銷。

 

接下來,咱們重點探討一下varchar的65535存儲長度表明的真正含義是什麼?由於前面說過一句話:既是單列的限制,又是整行的限制!咱們詳細來解釋一下。對於單列的限制,咱們舉一個例子:create table tablename(c varchar(N)) charset=gbk;那麼N的最大值是(65535-1-2)=32766。同時,若是同一個有其餘字段的話,那麼全部字段的長度和不能超過65535,舉個例子:create table tablename(c1 int(4), c2 char(30), c3 varchar(N) ) charset=utf8,那麼N的最大值是(65535-1-2-4-30*3)/3=21812,也許你很理解int(4)須要4個字符的位置,這裏可能須要更深刻的瞭解int的存儲機制,我不太瞭解,書尚未看呢。總之int類型佔用4個字符的長度,換句話說create table tablename(c1 int(32), c2 char(30), c3 varchar(N) ) charset=utf8,N的最大值也是(65535-1-2-4-30*3)/3=21812。我作了一個簡單的實驗,看截圖。

第一張varchar的長度大於21812,因而失敗了

大小: 89.39 K
尺寸: 550 x 264
瀏覽: 4 次
點擊打開新窗口瀏覽全圖

第二張varchar長度等於21812,保存成功

大小: 58.9 K
尺寸: 550 x 334
瀏覽: 6 次
點擊打開新窗口瀏覽全圖

 轉載請註明來源:www.blogguy.cn

 廢話了這麼多,總之一句話:char在浪費存儲空間的劣勢下,得到了較高的效率,varchar相反。接下來咱們也要總結一下什麼狀況下使用char,什麼狀況下使用varchar。

原則一:根據字符串長度肯定,凡是固定長度的字符串或者相似固定長度的字符串一概用char。好比身份證號碼,手機號碼,銀行卡號,MD5,哈希值等這是字符串是固定長度的,毫無疑問用char,還有一類是基本固定長度可是略有出入的,好比中國人的姓名等,通常長度多是2~5個漢字,這類信息也很是適合用char來存儲,只要分配一些略大於一般長度便可。

原則二:數據是否常常更改致使碎片,可能常常變更而產生存儲碎片的小字符串一概用char。咱們知道char類型的數據是一次性分配存儲空間的,不管之後你怎麼修改,數據始終在該存儲空間內的,不會產生碎片。而varchar則不一樣,varchar的數據長度是可變的,當修改後的數據大於當前存儲長度時,就會產生碎片,若是該應用是反覆修改數據的應用,那麼長此以往就是產生無數碎片,效率可想而知。

原則三:理解varchar的存儲空間和內存空間的區別,合理指定varchar的長度。咱們知道varchar的存儲長度是根據字符串的長度而定的,可是運行時佔用的內存空間倒是按照定義的長度分配內存空間的(個人理解,不知道是否正確)。這個現象致使存儲一個字符串,好比通訊地址,通暢在100個字符內就能存儲完成,因而varchar(100)是一個合理的選擇,可是因爲以前講的,可能有人圖方便使用varchar(500),反正用的存儲空間是同樣的,可是效果確實不同的。在內存模型中varchar(100)與varchar(500)是兩碼事,後者比前者佔用多5倍的內存空間,在臨時表和排序的時候這個差異幾乎可能差一個數量級,因而效率可想而知。

轉載註明來源:www.blogguy.cn

 基本上解釋完char和varchar,這裏順帶看看Nchar和Nvarchar是什麼?

nvarchar表示可變長度 Unicode 數據,其最大長度爲 4,000 字符;nchar表示固定長度的 Unicode 數據,最大長度爲 4,000 個字符。

那Nchar和Nvarchar在什麼狀況下使用呢?咱們知道字符 中,英文字符只須要一個字節存儲就足夠了,但漢字衆多,須要兩個字節存儲,英文與漢字同時存在時容易形成混亂,Unicode字符集就是爲了解決字符集這 種不兼容的問題而產生的,它全部的字符都用兩個字節表示,即英文字符也是用兩個字節表示。因而支持多語言的站點應考慮使用 Unicode nchar 或 nvarchar 數據類型以儘可能減小字符轉換問題。一樣的解釋還有下面咱們要研討的NText。

 

下面咱們看看text和blob

 text分爲4種類型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT,分別對應不一樣的長度。text是非二進制字符串,而且須要指定字符集,並按照該字符集進行校驗和排序。只能存儲純文本,能夠看做是VARCHAR在長度不足時的擴展。

blob也分爲4種類型:TINYBLOB,BLOB,mediumblob和LongBlob,分別對應不一樣的長度,blob存儲的是二進制數據,所以無需字符集校驗,blob除了存儲文本信息外,因爲二進制存儲格式,因此還能夠保存圖片等信息,blob能夠看做是VARBINARY在長度不足時的擴展。

 text和blob的各類類型存儲長度,咱們用以下的表格表示:

TinyBlob                             最大長度255個字元(2^8-1)  
TinyText                             最大長度255個字元(2^8-1)
Blob                                    最大長度65535個字元(2^16-1)
Text                                    最大長度65535個字元(2^16-1)
MediumBlob                         最大長度 16777215 個字元(2^24-1)
MediumText                         最大長度 16777215 個字元(2^24-1
LongBlob                              最大長度4294967295個字元 (2^32-1)
LongText                              最大長度4294967295個字元 (2^32-1)

 

 好了,到此char,varchar,text,blob內容探討基本完成了,下面是我再次複習一下有關int型數據的內容,列在這裏方便對比。

 

XML/HTML代碼
  1. • TINYINT——一個微小的整數,支持 -128到127(SIGNED),0到255(UNSIGNED),須要1個字節存儲   
  2. • BIT——同TINYINT(1)   
  3. • BOOL——同TINYINT(1)   
  4. • SMALLINT——一個小整數,支持 -32768到32767(SIGNED),0到65535(UNSIGNED),須要2個字節存儲 MEDIUMINT——一箇中等整數,支持 -8388608到8388607(SIGNED),0到16777215(UNSIGNED),須要3個字節存儲   
  5. • INT——一個整數,支持 -2147493648到2147493647(SIGNED),0到4294967295(UNSIGNED),須要4個字節存儲   
  6. • INTEGER——同INT   
  7. • BIGINT——一個大整數,支持 -9223372036854775808到9223372036854775807(SIGNED),0到18446744073709551615(UNSIGNED),須要8個字節存儲   
  8. • FLOAT(precision)——一個浮點數。precision<=24用於單精度浮點數;precision在25和53之間,用於又精度浮點數。FLOAT(X)與相誚的FLOAT和DOUBLE類型有差相同的範圍,可是沒有定義顯示尺寸和小數位數。在MySQL3.23以前,這不是一個真的浮點值,且老是有兩位小數。MySQL中的全部計算都用雙精度,因此這會帶來一些意想不到的問題。   
  9. • FLOAT——一個小的菜單精度浮點數。支持 -3.402823466E+38到-1.175494351E-38,0和1.175494351E-38 to 3.402823466E+38,須要4個字節存儲。若是是UNSIGNED,正數的範圍保持不變,但負數是不容許的。   
  10. • DOUBLE——一個雙精度浮點數。支持 -1.7976931348623157E+308到-2.2250738585072014E-308,0和2.2250738585072014E-308到1.7976931348623157E+308。若是是FLOAT,UNSIGNED不會改變正數範圍,但負數是不容許的。   
  11. • DOUBLE PRECISION——同DOUBLE   
  12. • REAL——同DOUBLE   
  13. • DECIMAL——將一個數像字符串那樣存儲,每一個字符佔一個字節   
  14. • DEC——同DECIMAL   
  15. • NUMERIC——同DECIMAL   

 

轉載請註明來源:www.blogguy.cn

相關文章
相關標籤/搜索