今天遇到了一个关于char类型的问题,感觉非常值得注意,所以写下这篇文章,用于总结。
先来看问题:
在数据库中创建两张表,两张表中插入完全相同的数据,不同点在于Sname
字段的数据类型不同,一个是char(20)
另一个是varchar(20)
但是当我用相同的语句进行模糊查询时select Sname from StudentA where Sname like '欧阳_';
,
却得到了截然不同的结果,这是什么原因呢??
create table StudentA
(
Sno char(10) primary key
,Sname `char(20)` not null
);
insert into StudentA values('2018110601','欧阳');
insert into StudentA values('2018110602','欧阳洋');
insert into StudentA values('2018110603','欧阳洋洋');
select Sname from StudentA where Sname like '欧阳_';//结果如下
// | Sname
// 1 | 欧阳
// 2 | 欧阳洋
create table StudentB
(
Sno char(10) primary key
,Sname `varchar(20)` not null
);
insert into StudentB values('2018110601','欧阳');
insert into StudentB values('2018110602','欧阳洋');
insert into StudentB values('2018110603','欧阳洋洋');
select Sname from StudentA where Sname like '欧阳_';//结果如下
// | Sname
// 1 | 欧阳洋
这是因为:char
类型的长度是固定
的,当长度不够是会自动补齐空格,varchar
的长度是可变
的,多余的长度会自动收缩。
关于空格的一些细节,后面会进行详细介绍,这里不再赘述。
这就表示,使用char(10)存储字符串'abc'
时,实际上是这样的:‘abc _______’
,字符串将占10个字节(包括7个空字符);
而使用varchar(10),则表示只占3个字节‘abc’
,10是最大值,当存储的字符小于10时,按照实际的长度存储。
所以,在第一个表StudentA
中,每一条记录的Sname
字段实际上是这样存储的:(因为每个汉字占用2个字节)
‘欧阳________________’
字符串占20个字节(所以还包括16个空字符);
‘欧阳洋______________’
字符串占20个字节(所以还包括14个空字符);
‘欧阳洋洋____________’
字符串占20个字节(所以还包括12个空字符);
而,在第二个表StudentB
中,每一条记录的Sname
字段实际上是这样存储的:(因为每个汉字占用2个字节)
‘欧阳’
字符串占4个字节;
‘欧阳洋’
字符串占6个字节;
‘欧阳洋洋’
字符串占8个字节;
这样一来,在进行select Sname from StudentA where Sname like '欧阳_';
查询时,后面的空格也会被计入其中,所以
第一个表(char)的查询结果为:
select Sname from StudentA where Sname like '欧阳_';//结果如下
// | Sname
// 1 | 欧阳
// 2 | 欧阳洋
第二个表(varchar)的查询结果为:
select Sname from StudentA where Sname like '欧阳_';//结果如下
// | Sname
// 1 | 欧阳洋
总结一下:
1. 在长度固定或者长度较短时可以使用char。(列如身份证号码、邮政编码、手机号码)
2. 经常被修改的字段,为了效率应当考虑用char代替varchar(列如一个用户的名字经常被修改)
3. 密码字段不能使用char,空格会影响查询。