一  前言
  varchar(N) N代表什么意思,能存放多少个中文字符?属于老生常谈的问题了,今天又被一个开发同事问我关于这个问题,索性写一篇文章来具体介绍一下。

二 理论知识

 先说明一下 MySQL 历来版本对 varchar 的定义: 
   4.0版本以下,varchar(50),指的是50字节,如果存放UTF8汉字时,只能存16个(每个中文3字节)
   5.0版本以上,varchar(50),指的是50字符,无论存放的是数字、字母还是UTF8中文(每个中文3字节),都可以存放50个 
 存储限制
   需要额外占用字节存放字符的长度:小于255为1个字节,大于255则要2个字节
 编码限制
   gbk :每个字符最多占用2个字节
   utf8:每个字符最多占用3个字节
   utf8mb4 每个字符最多占用4个字节,中文占3个字节,emoji表情符号 占用4个字节 
 长度限制
   MySQL定义行的长度不能超过65535,该数值限制了列的数目,比如char(128) utf8字符集,最多有65535/(128*3)=170个汉字。

三 测试
环境 Server version: 5.6.26-74.0-log Percona Server  
mysql> create table  t1
    -> (id int  NOT NULL AUTO_INCREMENT    primary key,
    ->  name  varchar(10)
    -> ) engine=innodb default charset=utf8mb4;
Query OK, 0 rows affected (0.01 sec)
mysql> create table  t2
    -> (id int  NOT NULL AUTO_INCREMENT    primary key,
    ->  name  varchar(10)
    -> ) engine=innodb default charset=utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> create table t3
    -> (id int  NOT NULL AUTO_INCREMENT    primary key,
    ->  name  varchar(10)
    -> ) engine=innodb default charset=gbk;
Query OK, 0 rows affected (0.01 sec)
utf8mb4 字符集
mysql> insert into t1(name) values('abcdfeghi');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t1(name) values('abcdfeghij');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t1(name) values('abcdfeghijk');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into t1(name) values('一二三四五六七八九十');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t1(name) values('一二三四五六七八九十一');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-------------------------------------------+
| Level   | Code | Message                                   |
+---------+------+-------------------------------------------+
| Warning | 1265 | Data truncated for column 'name' at row 1 |
+---------+------+-------------------------------------------+
1 row in set (0.00 sec)
mysql> insert into t1(name) values('0123456789');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t1(name) values('01234567890');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select id,name,length(name),char_length(name) from t1;
+----+--------------------------------+--------------+-------------------+
| id | name                           | length(name) | char_length(name) |
+----+--------------------------------+--------------+-------------------+
|  1 | abcdfeghi                      |            9 |                 9 |
|  2 | abcdfeghij                     |           10 |                10 |
|  3 | abcdfeghij                     |           10 |                10 |
|  4 | 一二三四五六七八九十              |           30 |                10 |
|  5 | 一二三四五六七八九十              |           30 |                10 |
|  6 | 0123456789                     |           10 |                10 |
|  7 | 0123456789                     |           10 |                10 |
+----+--------------------------------+--------------+-------------------+
7 rows in set (0.00 sec)
utf8 字符集
mysql> insert into t2(name) values('abcdfeghi');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2(name) values('abcdfeghij');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2(name) values('abcdfeghijk');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into t2(name) values('一二三四五六七八九十');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2(name) values('一二三四五六七八九十一');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into t2(name) values('0123456789');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2(name) values('01234567890');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select id,name,length(name),char_length(name) from t2;
+----+--------------------------------+--------------+-------------------+
| id | name                           | length(name) | char_length(name) |
+----+--------------------------------+--------------+-------------------+
|  1 | abcdfeghi                      |            9 |                 9 |
|  2 | abcdfeghij                     |           10 |                10 |
|  3 | abcdfeghij                     |           10 |                10 |
|  4 | 一二三四五六七八九十              |           30 |                10 |
|  5 | 一二三四五六七八九十              |           30 |                10 |
|  6 | 0123456789                     |           10 |                10 |
|  7 | 0123456789                     |           10 |                10 |
+----+--------------------------------+--------------+-------------------+
7 rows in set (0.00 sec)
gbk 字符集
mysql> insert into t3(name) values('abcdfeghi');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3(name) values('abcdfeghij');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3(name) values('abcdfeghijk');
Query OK, 1 row affected, 1 warning (0.00 sec) 
mysql> insert into t3(name) values('一二三四五六七八九十');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t3(name) values('一二三四五六七八九十一');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into t3(name) values('0123456789');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3(name) values('01234567890');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select id,name,length(name),char_length(name) from t3;
+----+--------------------------------+--------------+-------------------+
| id | name                           | length(name) | char_length(name) |
+----+--------------------------------+--------------+-------------------+
|  1 | abcdfeghi                      |            9 |                 9 |
|  2 | abcdfeghij                     |           10 |                10 |
|  3 | abcdfeghij                     |           10 |                10 |
|  4 | 一二三四五六七八九十              |           20 |                10 |
|  5 | 一二三四五六七八九十              |           20 |                10 |
|  6 | 一二三四五六七八九十              |           20 |                10 |
|  7 | 0123456789                     |           10 |                10 |
|  8 | 0123456789                     |           10 |                10 |
+----+--------------------------------+--------------+-------------------+
8 rows in set (0.00 sec)
   从上面的测试可以看出,目前版本中 varchar(N) 定义的长度的单位是字符,length(str)表示str占用的字节数,char_length(str)表示str占用的字符数。
不论什么字符集,对于数字和英文字母都是只占用1个字符,也占用一个字节。而中文汉字因字符集不同而不同。

四 总结
   回过头来回答文章开头的问题varchar(N)可以存放多少个中文汉字。答案是在 5.0 以后的版本中 varchar(N) 可以存放N个汉字 。
   抛开字符集 ,如果一行数据全部为 varchar 类型,其最大长度为 65535 个字节。
行长度计算公式如下:
row length = 1
           + (sum of column lengths)
           + (number of NULL columns + delete_flag + 7)/8
           + (number of variable-length columns)
 对于MyISAM,需要额外1个位来记录值是否为NULL;对于InnoDB,没有区别
 对于row_format为fixed,delete_flag为1;对于row_format=dynamic,delete_flag为0

根据这个公式,我们便能够解答开头N的最大值:(65535-1-2)/3
减1是因为实际存储从第2个字节开始
减2则因为要在列表长度存储实际字符长度
除3是因为utf8编码限制
再来一道:
create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;
N的最大值:(65535-1-2-4-30*3)/3
则此处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”了

五 参考 
http://blog.csdn.net/u012048106/article/details/23173911
字符,字节和编码 
MySQL乱码问题以及utf8mb4字符集

原文blog:

http://blog.itpub.net/22664653/viewspace-1979335/

【MySQL】浅谈 varchar(N)的更多相关文章

  1. Python 基于python+mysql浅谈redis缓存设计与数据库关联数据处理

    基于python+mysql浅谈redis缓存设计与数据库关联数据处理 by:授客  QQ:1033553122 测试环境 redis-3.0.7 CentOS 6.5-x86_64 python 3 ...

  2. MySQL浅谈 LEFT JOIN

    On条件(在“A left join b on conditional_expr”)决定如何从table B 中检索数据行(Matching-State); 如果B中没有行匹配On 条件,额外的B的所 ...

  3. mysql浅谈--事务ACID特性

    mysql MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管 ...

  4. MYSQL优化浅谈,工具及优化点介绍,mysqldumpslow,pt-query-digest,explain等

    MYSQL优化浅谈 msyql是开发常用的关系型数据库,快速.稳定.开源等优点就不说了. 个人认为,项目上线,标志着一个项目真正的开始.从运维,到反馈,到再分析,再版本迭代,再优化… 这是一个漫长且考 ...

  5. 重新学习MySQL数据库6:浅谈MySQL的中事务与锁

    『浅入深出』MySQL 中事务的实现 在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇 ...

  6. sql语句浅谈以及mysql遇到的问题解决见解

    mysql数据库基本操作: .显示数据库和查看mysql版本 show databases; select version(); select user();查看用户 .选择数据库 use 数据库名; ...

  7. 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载

    浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...

  8. MySql主从配置实践及其优势浅谈

    MySql主从配置实践及其优势浅谈 1.增加两个MySQL,我将C:\xampp\mysql下的MYSQL复制了一份,放到D:\Mysql2\Mysql5.1 修改my.ini(linux下应该是my ...

  9. 浅谈mysql主从复制的高可用解决方案

    1.熟悉几个组件(部分摘自网络)1.1.drbd     —— DRBD(Distributed Replicated Block Device),DRBD号称是 "网络 RAID" ...

随机推荐

  1. [aspnetcore]asp.net core程序部署到Ubuntu中的路径问题

    先标记下正确写法 new FileInfo(Environment.CurrentDirectory + "/Config/Log4net.config") 很多同行喜欢这样写: ...

  2. [已读]JavaScript高级程序设计(第3版)

    从去年开始看,因为太长,总是没有办法一口气把它看完,再加上它与第二版大部分一致,读起来兴致会更缺一点. 与第二版相比,它最大的改变就是增加了很多html5的内容,譬如:Object对象的一些新东西,数 ...

  3. C. Functions again DP + 分类讨论

    http://codeforces.com/contest/789/problem/C 首先按题目要求处理出dis数组. 那么对于任意一个区间,[L, R],是dis[L] - dis[L + 1] ...

  4. Access denied for user ''@'localhost' to database 的一个问题

    $conn = new mysqli("127.0.0.1", 'abc', '', DB_DATABASE); 在提供了用户名的情况下,竟然返回错误 说用户提供的用户为空,非常奇 ...

  5. Linux 增加虚拟内存

    1. 用 df -h 命令找一个比较大的磁盘空间 2.建立swap文件 大小为2G count= 3.启用虚拟内存 1. 将swap文件设置为swap分区文件 mkswap swapfile #(由于 ...

  6. Spring-打印机案例

    1.导包 <!--beans--><dependency> <groupId>org.springframework</groupId> <art ...

  7. 爬虫requests库的基本用法

    需要注意的几个点: 1.后面的s是一个虚拟目录 2.url后面不用加问号,发起请求的时候会自动帮你加上问号 get_url = 'http://www.baidu.com/s' 3. url的特性:u ...

  8. while嵌套应用二:九九乘法表

    __author__ = 'zht' #!/usr/bin/env python # -*- coding: utf-8 -*- ''' #努力学习每一天 ''' #while嵌套应用二:九九乘法表 ...

  9. moment算本月开始日期和结束日期

    moment算本月开始日期和结束日期 1.引入moment.js var vStartDate=new moment().add('month',addMonth).format("YYYY ...

  10. (一)maven之创建一个maven项目

    为什么要使用Maven? 1.  maven使用的是本地仓库存储jar,所有项目都会共用仓库中的同一份jar. 2.  Spring core.jar必须同时引用版本兼容的common-logging ...