一  前言
  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. jQuery height() innerHeight() outerHight() width() innerWidth() outerWidth()源码解读

    在第二层each,传入的对象以height举例是这样的,{padding:innerHeight,content:height,"":outerHeight} 对它遍历调用func ...

  2. C#的特性学习

    转自:https://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html   特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类 ...

  3. top 进程管理

    top 动态查看进程 前五行解释: 第一行参数说明: top - 07:06:19    当前时间 up 10 min,  系统运行时间,格式为时:分 1 user,  当前登录用户数 load av ...

  4. Promise/A+规范

    1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...

  5. vue样式操作与事件绑定

    Vue笔记 1 Vue实例 (VM) var vm = new Vue({    el:'#app', //挂载元素        //数据    data: {        title:'值', ...

  6. codeforces727C(交互)

    题意 $n$个数,初始时不知道他们的值. 每次可以询问两个数的和,在$n$次询问内确定他们的值 $n \leqslant 5000$ Sol 首先询问出$1, 2$,$1, 3$,$2, 3$ 解个方 ...

  7. jQuery Deferred对象详细源码分析(-)

    本系列文章讲介绍这个Deferred东西到底拿来干什么,从1.5版本加进来,jQuery的很多代码都重写了.直接先上源码分析了,清楚了源码分析,下节将讲具体的应用 以及应用场景. 创建对象 var d ...

  8. 盒子模型--IE与标准

    从上图可以看到标准 W3C 盒子模型的范围包括 margin.border.padding.content,并且 content 部分不包含其他部分. 从上图可以看到 IE 盒子模型的范围也包括 ma ...

  9. codevs 2919 选择题

    时间限制: 1 s  空间限制: 16000 KB  题目等级 : 黄金 Gold 题目描述 Description 某同学考试,在N*M的答题卡上写了A,B,C,D四种答案. 他做完了,又不能交,一 ...

  10. 10个优秀的移动Web应用开发框架

    在最近几年里,移动互联网高速发展.市场潜力巨大.继计算机.互联网之后,移动互联网正掀起第三次信息技术革命的浪潮,新技术.新应用不断涌现.今天这篇文章向大家推荐10大优秀的移动Web开发框架,帮助开发者 ...