char和varchar是2种字符串类型,char(N)保存固定长度的字符串,
N范围:0~255(2^8-1);varchar(N)保存变长字符串,N范围:0~65535(2^16-1)。其中
N表示字符长度。
对char类型字符串,MySQL数据库会自动对存储列的右边进行填充
操作,直接字符串达到指定的长度N。而在读取列时,MySQL会自动
将填充的字符删除。而在进行数据比较时,系统又会将空格填充到
字符串的末尾,如果显示将SQL_MODE设置为:PAD_CHAR_TO_FULL_LENGTH
除外.
注意些函数:
length函数:字节长度,
char_length函数:字符长度
在多字节字符集下,char(N)长度列最多可占用的字节数为:该字符集单字符最大
占用字节数*N。如utf8,char(10)最多可能占用30(3*10)个字节。
char用固定长度的存储方式,系统为其分配最大的存储空间,当数据保存时,即使
没有达到最大长度,系统也会为其分配这么多的存储空间,这种存储方式造成磁盘
空间浪费。
varchar,存储时需要在前缀长度列表加上实际存储的字符,该字符占1~2个字节空间。
字符串长度<255字节时,需要1字节的空间,当大于255字节时,需要2字节空间。
对单字节latin1,char(10)占用10个字节和varchar(10)最大占用空间是11字节,其
中1字节来存放字符长度.
varchar和char,2种字符类型数据类型相比,差异前者是可变长度,后者是固定长度。
在存储时,前者根据实际存储的数据来分配最终的存储空间,后者不管实际存储数据
的长度,根据char规定的长度来分配存储空间。
varchar数据类型能够节约磁盘空间,可以提升数据库性能,不过,也会产生一些副作用
如因其长度是可变的,为此在数据进行更新时可能会导致一些额外的工作。如在更改前,
其字符长度是10位(varchar规定的最长字符数假设50位),此时系统就只给其分配10个存
储的位置,更改后,其数量达到20位。由于没有超过最大50位的限制,数据库还是可以
存储的。但是,其原先的存储位置已经无法满足其存储的需求。此时系统需要进行额外
的操作,根据引擎不同,有的会用拆分机制,而有的会用分页机制。
char(1)和varchar(1)这2个定义,虽然这2个只能够用来保存单个字符,但varchar比
char多占用一个存储位置,因varchar数据类型时,会多用1个字节来存储长度信息。
管理上的开销char字符类型是没有的。
在项目中建议:
1.字符长度判断,如某个字段,人名,一般长度有限的,如给其分配18个字符长度即可
此时,虽然每个人的名字长度有可能不同,但在为其分配了固定长度的字符类型,即18
个字符长度,最后浪费空间也不是很大。而如果采用varchar数据类型时,若后面需要改
名,而原先的存储空间不足用来容纳新的值,反而会造成一些额外的工作。在这种情况
下,进行均衡时,会认为用char固定长度的数据类型更好。在实际项目中,如某个字段
的字符长度较短,我们使用固定字符长度。
2.长度是否相近,如某个字段长度比较长,但是长度总是近似的,如90个到100个字符
之间,或相同长度。较适宜用char字符类型。较典型的应用是MD5哈希值,当利用MD5哈
希值来存储用户密码时,就适宜用char字符类型。此外,用户身份证号码等,建议用char
类型的数据
3.碎片角度进行考虑,使用char字符时,存储空间是一次性分配的,为此某个字段的内容
,其都是存储在一起的。这些是不存在的碎片的。而在可变长度的字符数据类型,其存储
长度是可变的,当其更改前后数据长度不一致时,就不可避免的会出现碎片的问题
4.varchar数据类型,分配不能过于太多,如,用户需要存储一个地址信息,只需要100个字符
但dba会认为,varchar数据类型是根据实际的需要分配长度的,可以给其大一点。为此分配
200个字符的存储空间,那varchar(100)和varchar(200)区别?其结果是不同的,对于存储90个
字符的数据,其存储空间相同。但是对于内存的消耗是不同的,对与varchar数据类型来说,磁
盘上的存储空间是根据实际字符长度来分配存储空间的,但对于内存来说,其使用固定大小的内存
块来保存值,就是使用字符类型中定义的长度,即200个字符空间。这对于排序或临时表(这些内容
都需要通过内存来实现)作业会产生比较大的不利影响。对于某些字段涉及到文件排序或磁盘临时表
时,分配varchar数据类型需要均衡,考虑冗余,保留10%的字符长度,不能随意分配长度,评估需要
实际长度.
补充:
MySQL中varchar最大长度是多少?
这不是一个固定的数字。本文简要说明一下限制规则。
strlen 计算字符串长度,一个中文当2字符
mb_strlen根据它的字符编码模式,统计字符quot
count计算数组中的元素数目或对象中的属性个数
<?php
header('Content-Type:text/html;charset=UTF-8');
$string1="谢春业";//定义中文字符变量
$string2="xcy";//定义英文字符变量
//直接输出看看他们的长度
echo strlen($string1);
echo "</br>";
echo strlen($string2);
echo "</br>";
//用 php 多字节扩展函数 mb_strlen试试看
echo mb_strlen($string1,'utf8');
echo "</br>";
echo mb_strlen($string2,'utf8');
echo "</br>";
?>
输出结果是:
9
3
3
3
1、限制规则
字段的限制在字段定义的时候有以下规则:
a) 存储限制
varchar 字段是将实际内容单独存储在聚簇索引之外,内容开头用1到2个字节表示实际长度(长度超过255时需要2个字节),
因此最大长度不能超过65535。
b) 编码长度限制
字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766;
字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845。
对于英文比较多的论坛 ,使用GBK则每个字符占用2个字节,而使用UTF-8英文却只占一个字节。
若定义的时候超过上述限制,则varchar字段会被强行转为text类型,并产生warning。
c) 行长度限制
导致实际应用中varchar长度限制的是一个行定义的长度。 MySQL要求一个行的定义长度不能超过65535。若定义的表长度超过这个值,则提示
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs。
2、计算例子
举两个例说明一下实际长度的计算。
a) 若一个表只有一个varchar类型,如定义为
create table t4(c varchar(N)) charset=gbk;
则此处N的最大值为(65535-1-2)/2= 32766。
减1的原因是实际行存储从第二个字节开始’;
减2的原因是varchar头部的2个字节表示长度;
除2的原因是字符编码是gbk。
b) 若一个表定义为
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个字节;
减30*3的原因是char(30)占用90个字节,编码是utf8。
如果被varchar超过上述的b规则,被强转成text类型,则每个字段占用定义长度为11字节,当然这已经不是“varchar”了。
补充:
mysql中char和varchar
在myisam引擎中,区别,
1.char固定长度,一次性分配存储空间;varchar变长,根据存储字符长度分配存储空间
2.更新很频繁,varchar易产生碎片,因每次更新会对新的字符长度重新计算分配空间,而char不会
3.char比varchar更容易占用更多磁盘空间
在myisam中,尽量使用char数据类型,非常快(数据文件中行在磁盘上容易被找到:当按照索引中的行号查找一个行时,用行长乘以行号)。容易缓存(存储空间固定不变),奔溃后容易重建,因为记录位于固定位置。因char准确计算出下一条记录的偏移量,同时可以避免碎片存在(因频繁更新字段的数据);
而varchar,每行有一个表明行有多长的头,因更新结果导致每行的头长度变动,同时若一个记录变大,它需要被分开成多片,准确定位某个记录计算需要进过较复杂的过程;
InnoDB引擎,表的数据行内部存储格式对固定长度的数据行和可变长度的数据行不加区分(所有数据行共用一个表头部分,这个表头部分存放着指向各有关数据列的指针),因char类型通常比varchar类型占用更多存储空间,故从减少占用磁盘空间和磁盘IO考虑,使用varchar类型更有利;
注意,varchar还有一个问题,可以自动适应存储空间,对节约磁盘空间有利,但是,在内存中是按照定义长度申请,长度大小对内存消耗有一定影响,所以,在varchar类型选择上不能过分慷慨,最好根据需求均衡。
http://tech.it168.com/a2011/0426/1183/000001183173.shtml
MySQL技术内幕.SQL编程