萬盛學電腦網

 萬盛學電腦網 >> 數據庫 >> mysql教程 >> mysql中char、varchar、nvarchar數據類型的用法區別

mysql中char、varchar、nvarchar數據類型的用法區別

mysql中char、varchar、nvarchar數據類型的用法區別 有需要的朋友可

說明:
1、char:
固定長度的非 Unicode 字符數據,最大長度為 8,000 個字符。
2、varchar:
可變長度的非 Unicode 數據,最長為 8,000 個字符。
3、nvarchar:
可變長度 Unicode 數據,其最大長度為 4,000 字符。
4、nchar
固定長度的 Unicode 數據,最大長度為 4,000 個字符。
5、char和varchar都是字符串類型的
用Unicode編碼的字符串,結果是字符的整數值


如有以下數據結構:

工號 姓名 部門
———————–
1 張三 財務
2 李四 人事
3 王五 銷售
……..

我們定義”姓名”為char(10)(靜態)的時簡單地用php代碼表示:
簡單地模擬底層數據存儲鏈表$data

 代碼如下 復制代碼 $col_num_len  =1;      //工號長度為1
$col_name_len=10;    //姓名長度為10
$col_unit_len   =4;     //部門長度為4
$col_len=$col_num_len+$col_name_len+$col_unit_len+3;       

  //表示每筆記錄的總長度,包括3個分隔符
實現如下:

 代碼如下 復制代碼

$data="1|張三      |財務|2|李四      |人事|3|王五      |銷售|...";         //簡單地模擬底層數據存儲鏈表

//假設查找第2條記錄的"姓名"字段數據
$record_start=$col_len*1+1;                                                       //獲取第2行的起始位置
$record  =substr($data,$record_start,$col_len);                        //獲取第2條記錄
$col_name_start=$col_num_len+2;                                                   //獲取"姓名"字段的起始位置
$col_name=substr($record,$col_name_start,$col_name_len);  //獲取"姓名"字段的數據
echo $col_name;

-----------

 代碼如下 復制代碼 //假設更新第2條記錄的"姓名"字段數據為"李小四"
$update_info="李小四";
$data=substr_replace($data,$update_info,$col_name_start,$col_name_len);        //更新字段,流程結束
而如果我們定義”姓名”字段為varchar(10)(動態)的時候情況則要復雜:
注意存儲”姓名”的字段沒有空格,這是char和varchar的存儲區別
$col_num_len  =1;      //工號長度為1
$col_name_len=10;    //姓名長度為10
$col_unit_len   =4;     //部門長度為4
$col_len=$col_num_len+$col_name_len+$col_unit_len+3;

實現如下:

 代碼如下 復制代碼

//動態存放數據行的起始位置,數據為更新時生成(重新)
$record_1_start=1;$record_1_name_dynamic_len=4;                //$col_1_name_dynamic_len記錄"姓名"動態字段的長度
$record_2_start=13;$record_2_name_dynamic_len=4;
$record_3_start=26;$record_3_name_dynamic_len=6;
...

$data="1|張三|財務|2|李四|人事|3|王小明|銷售|...";                       //簡單地模擬底層數據存儲鏈表,注意存儲"姓名"的字段沒有空格

//假設查找第2條記錄的"姓名"字段數據
$record_2_end=$record_3_start-1;                                               //獲取第2行的結束位置
$record  =substr($data,$record_2_start,$record_2_end);         //獲取第2條記錄
$col_name_start=$col_num_len+2;                                                   //獲取"姓名"字段的起始位置
$col_name=substr($record,$col_name_start,$record_2_name_dynamic_len);  //獲取"姓名"字段的數據
echo $col_name;

//假設更新第2條記錄的"姓名"字段數據為"李小四",這邊比靜態的復雜很多
$update_info="李小四";
$update_len=strlen($update_info);                //獲取更新內容的長度
if($diff_len=$update_len-$record_2_name_dynamic_len)
{
$data=substr_replace($data,"",$col_name_start,$record_2_name_dynamic_len);        //清除原先數據
$record_2_name_dynamic_len=$update_len;                                                                        //更新字段的長度(並存儲新值)

//在此假設總記錄數為n
for($i=2;$i<=n;$i++)
{
${'record_'.$i.'_start'}=${'record_'.$i.'_start'}+$diff_len;                                        //重新更新每個行的起始位置(並存儲新值),系統開銷大(實際上有不同的方法解決)
}
}

$data=substr_replace($data,$update_info,$col_name_start,0);


文中直接使用”substr_replace”,而在數據量很大的時候,底層實現上的開銷也是不小的,在mysql中表現為(Row Migration)現象,在此不作贅述

根據以上的粗略實現證明:
1、varchar類型在更新環節上的系統開銷是遠大於char類型的。
2、兩者間查找搜索性能上是不相上下的。
3、兩者間的存儲數據量($data)環節上,char要顯示大於varchar。
4、大數據量提取時varchar的磁盤IO消耗更低,意味著varchar綜合查詢性能會更好。
5、沒有了。

實際應用中的結論(如在mysql中):
1、char適合字段頻繁更新時的應用。
2、varchar更節省磁盤空間。
3、實際應用中大數據量(多行)查詢返回,varchar的查詢性能比起char來要好出不少。
4、選擇char和varchar會改變整體數據結構的算法以及存儲方式。在mysql應用中,如已存在varchar字段,那麼其它所有的char字段將以varchar方式存儲。
5、沒有了。

(以上算法僅以PHP簡單描述,歡迎更好的思路加以指教)

注:此文原作者的寫作時間比較久遠了,所以有些地方和現在的有些出入,體現在:

1.在innodb引擎中,char和varchar的實現已無異,效率上並沒多大區別。
2.選擇char和varchar並不會改變整體數據結構的算法以及存儲方式。(我記得這是在MYSQL4裡的特性,網上的老文章有講述,到了MYSQL5實測已無此特性)


總結分析:
文字字段若長度固定,如:身分證號碼,就不要用 varchar 或 nvarchar,應該用 char 或 nchar。
支持多語言的站點應考慮使用 Unicode nchar 或 nvarchar 數據類型以盡量減少字符轉換問題
文字字段若長度不固定,如:地址,則該用 varchar 或 nvarchar。除了可節省存儲空間外,存取硬盤時也會較有效率

copyright © 萬盛學電腦網 all rights reserved