面试数据库常问之char与varchar的区别

Posted 黑黑白白君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试数据库常问之char与varchar的区别相关的知识,希望对你有一定的参考价值。



字符串类型是在数据库中存储字符串的数据类型,字符串类型包括char,varchar,text,enum和set。

  • 在数据库中,字符型的数据是最多的,可以占到整个数据库的80%以上。为此正确处理字符型的数据,对于提高数据库的性能有很大的作用
  • 在字符型数据中,用的最多的就是Char与Varchar两种类型。前面的是固定长度,而后面的是可变长度。

1)CHAR和VARCHAR字符型数据

CHAR 和VARCHAR 很类似,都用来保存MySQL中较短的字符串

  • 都是在创建表时指定了最大长度,其基本形式:字符串类型(M)。其中:

    • 字符串类型参数指定了数据类型是char类型还是varchar类型
    • M参数指定了该字符串的最大长度为M
    CREATE TABLE IF NOT EXISTS stuinfo(
    	stuId INT,
    	stuName VARCHAR(20),
    	gender CHAR,
    	bornDate DATETIME
    );
    
    mysql> CREATE TABLE cdefault(c char);
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> desc cdefault;  # 对于mysql 5.7,char默认长度为1
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | c     | char(1) | YES  |     | NULL    |       |
    +-------+---------+------+-----+---------+-------+
    1 row in set (0.01 sec)
    
    mysql> select version();
    +-----------+
    | version() |
    +-----------+
    | 5.7.26    |
    +-----------+
    1 row in set (0.01 sec)
    
  • CHAR 列的长度固定为创建表时声明的长度,长度可以为从0~255 的任何值。

  • VARCHAR 列中的值为可变长字符串,长度可以指定为0~255(MYSQL 5.0.3 以前)或者65535(5.0.3以后)之间的值。


2)存储方式的区别

VARCHAR与CHAR两种字符型数据类型相比,最大的差异就是前者是可变长度,而后者则是固定长度

  • 在存储时,前者会根据实际存储的数据来分配最终的存储空间。
  • 而后者则不管实际存储数据的长度,都是根据CHAR规定的长度来分配存储空间。

二者的主要区别在于存储方式的不同

  • Char采用的是固定长度的存储方式。
    • 保存CHAR值时,在它们的右边填充空格以达到指定的长度。
    • 检索到CHAR值时,尾部的空格被删除掉
    • 在存储或检索过程中不进行大小写转换。
    • 保存数据时,即使没有达到最大的长度,系统也会为其分配这么多的存储空间。显然,这种存储方式会造成磁盘空间的浪费
    • char存储定长数据很方便,char字段上的索引效率很高。

  • Varchar用来保存可变长度的字符串。
    • VARCHAR的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是65,532字节。
    • 当值保存和检索时尾部的空格仍保留,符合标准SQL。
    • varchar值保存时只保存需要的字符数,另加一个字节来记录长度(长度超过255时需要2个字节)。
    • 通常情况下,由于系统会根据实际存储的数据量来分配合适的存储空间,VARCHAR数据类型能够节约磁盘空间,为此往往认为其能够提升数据库的性能。
    • 但在提升性能的同时,往往也会因为其长度是可变的,从而在数据进行更新时可能会导致一些额外的工作
      • 如在更改前,其字符长度是10位(Varchar规定的最长字符数假设是50位),此时系统就只给其分配10个存储的位置(假设不考虑系统自身的开销)。
      • 更改后,其数据量达到了20位。由于没有超过最大50位的限制,为此数据库还是允许其存储的。只是其原先的存储位置已经无法满足其存储的需求,此时系统就需要进行额外的操作。如根据存储引擎不同,有的会采用拆分机制,而有的则会采用分页机制。

检索的时候,CHAR 列删除了尾部的空格,而VARCHAR 则保留这些空格。通过给表vc 中的VARCHAR(4)和char(4)字段插入相同的字符串来描述这个区别:

	mysql> use learn1;
	Database changed
	mysql> CREATE TABLE vc(v VARCHAR(4), c CHAR(4));  # 创建测试表vc,并定义两个字段v VARCHAR(4)和c CHAR(4)
	Query OK, 0 rows affected (0.04 sec)
	
	mysql> INSERT INTO vc VALUES('ab ','ab ');  # v 和c 列中同时插入字符串“ab ”,注意最后是有一个空格的
	Query OK, 1 row affected (0.01 sec)
	
	mysql> SELECT length(v),length(c) FROM vc;  # 显示查询结果,可以发现,c 字段的length 只有2
	+-----------+-----------+
	| length(v) | length(c) |
	+-----------+-----------+
	|         3 |         2 |
	+-----------+-----------+
	1 row in set (0.01 sec)
	
	mysql> SELECT CONCAT(v,'+'),CONCAT(c,'+') FROM vc;  # 给两个字段分别追加一个“+”字符看得更清楚
	+---------------+---------------+
	| CONCAT(v,'+') | CONCAT(c,'+') |
	+---------------+---------------+
	| ab +          | ab+           |
	+---------------+---------------+
	1 row in set (0.00 sec)
  • *如果插入的字符串的长度已经大于可以插入的最大值?

    比如说,现在我们定义2个char类型和varchar类型的字段,长度都为5,但是我们插入的值是‘123456’,那么系统就会阻止这个值的插入然后报错。

    mysql> CREATE TABLE maxtest(v varchar(5),c char(5));
    Query OK, 0 rows affected (0.04 sec)
    
    mysql> INSERT INTO maxtest VALUES('1','123456');
    ERROR 1406 (22001): Data too long for column 'c' at row 1
    mysql> INSERT INTO maxtest VALUES('123456','1');
    ERROR 1406 (22001): Data too long for column 'v' at row 1
    
  • Varchar数据类型的最大长度能不能设置很大?

    不能。对于Varchar数据类型来说,硬盘上的存储空间虽然都是根据实际字符长度来分配存储空间的,但是对于内存来说,则是使用固定大小的内存块来保存值。

    比如现在用户需要存储一个地址信息。根据评估,只要使用100个字符就可以了。VARCHAR(100)与VARCHAR(200)用来存储90个字符的数据,其存储空间相同,但是对于内存的消耗是不同的在内存中,是使用字符类型中定义的长度,即200个字符空间。这对于排序或者临时表(这些内容都需要通过内存来实现)作业会产生比较大的不利影响

    • 所以如果某些字段会涉及到文件排序或者基于磁盘的临时表时,分配VARCHAR数据类型时仍然不能够太过于慷慨。还是要评估实际需要的长度,然后选择一个最长的字段来设置字符长度。如果为了考虑冗余,可以留10%左右的字符长度。千万不能认为其为根据实际长度来分配存储空间,而随意地分配长度。

3)选择Varchar还是Char数据类型?

3.1 根据字符的长度来判断

1、在实际项目中, 如果某个字段的字符长度比较短,则一般是采用固定字符长度。因为varchar还要占个byte用于存储信息长度。

比如人的名字,其最长的长度也是有限的。通常分配18个字符长度即可。
此时虽然每个人的名字长度有可能不同,但是即使为其分配了固定长度的字符类型,即18个字符长度,最后浪费的空间也不是很大
而如果采用NVARCHAR数据类型时,万一以后需要改名,而原先的存储空间不足用来容纳新的值,反而会造成一些额外的工作。在这种情况下,进行均衡时,会认为采用CHAR固定长度的数据类型更好。

2、如果字符串的最大长度比平均长度大很多,即列长度经常变动较大的情况,通常选择Varchar。

3、如果某个字段的长度虽然比较长,但是其长度总是近似的,如一般在90个到100个字符之间,甚至是相同的长度。此时比较适合采用CHAR字符类型。

  • 比较典型的应用就是MD5哈希值。当利用MD5哈希值来存储用户密码时,就非常使用采用CHAR字符类型。因为其长度是相同的。
  • 另外,像用来存储用户的身份证号码等等,一般也建议使用CHAR类型的数据。

3.2 从存储碎片角度考虑

  • 使用CHAR字符型时,由于存储空间都是一次性分配的,所以某个字段的内容都是存储在一起的。单从这个角度来讲,其不存在碎片的困扰
  • 而可变长度的字符数据类型,其存储的长度是可变的。当更改前后数据长度不一致时,就不可避免地会出现碎片的问题
    • 故使用可变长度的字符型数据时,数据库管理员要时不时地对碎片进行整理,如执行数据库导出导入作业,来消除碎片。

3.3 从表存储引擎的类型考虑

常见的mysql表引擎有INNODB和MyISAM,主要的区别是INNODB适合频繁写数据库操作,MyISAM适合读取数据库的情况多一点。

  • MyISAM管理非事务表,提供高速存储和检索以及全文搜索能力,如果再应用中执行大量select操作,应该选择MyISAM。如果数据表涉及的存储数据多、查询多,用myisam,如文章表。
  • InnoDB用于事务处理,具有ACID事务支持等特性,如果在应用中执行大量insert和update操作,应该选择InnoDB。如果数据表涉及业务逻辑多,增删改操作多,就用innodb,如订单表。
  • 对于MyISAM表,尽量使用Char,对于那些经常需要修改而容易形成碎片的myisam和isam数据表就更是如此,它的缺点就是占用磁盘空间。
  • 对于InnoDB表,因为它的数据行内部存储格式对固定长度的数据行和可变长度的数据行不加区分(所有数据行共用一个表头部分,这个表头部分存放着指向各有关数据列的指针),所以使用char类型不见得会比使用varchar类型好。
    • 事实上,因为char类型通常要比varchar类型占用更多的空间,所以从减少空间占用量和减少磁盘i/o的角度,使用varchar类型反而更有利


【部分内容参考自】

  • Mysql 数据库字符类型详解:https://www.cnblogs.com/xuchunlin/p/6235369.html
  • MySQL数据库char与varchar的区别分析及使用建议:https://www.jb51.net/article/55366.htm
  • char与varchar类型区别的深度剖析:https://blog.csdn.net/qq_34858648/article/details/77881176

以上是关于面试数据库常问之char与varchar的区别的主要内容,如果未能解决你的问题,请参考以下文章

面试面试常问之堆栈的区别

计算机基础面试常问之进程和线程的区别

计算机网络面试常问之GET和POST的区别

面试常问之——Nginx和Apache有什么区别?

面试常问之——Mysql引擎中MyISAM和InnoDB的区别有哪些?

最常问的MySQL面试题集合