【MySQL】浅谈 varchar(N)
一 前言
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)的更多相关文章
- Python 基于python+mysql浅谈redis缓存设计与数据库关联数据处理
基于python+mysql浅谈redis缓存设计与数据库关联数据处理 by:授客 QQ:1033553122 测试环境 redis-3.0.7 CentOS 6.5-x86_64 python 3 ...
- MySQL浅谈 LEFT JOIN
On条件(在“A left join b on conditional_expr”)决定如何从table B 中检索数据行(Matching-State); 如果B中没有行匹配On 条件,额外的B的所 ...
- mysql浅谈--事务ACID特性
mysql MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管 ...
- MYSQL优化浅谈,工具及优化点介绍,mysqldumpslow,pt-query-digest,explain等
MYSQL优化浅谈 msyql是开发常用的关系型数据库,快速.稳定.开源等优点就不说了. 个人认为,项目上线,标志着一个项目真正的开始.从运维,到反馈,到再分析,再版本迭代,再优化… 这是一个漫长且考 ...
- 重新学习MySQL数据库6:浅谈MySQL的中事务与锁
『浅入深出』MySQL 中事务的实现 在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇 ...
- sql语句浅谈以及mysql遇到的问题解决见解
mysql数据库基本操作: .显示数据库和查看mysql版本 show databases; select version(); select user();查看用户 .选择数据库 use 数据库名; ...
- 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载
浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...
- MySql主从配置实践及其优势浅谈
MySql主从配置实践及其优势浅谈 1.增加两个MySQL,我将C:\xampp\mysql下的MYSQL复制了一份,放到D:\Mysql2\Mysql5.1 修改my.ini(linux下应该是my ...
- 浅谈mysql主从复制的高可用解决方案
1.熟悉几个组件(部分摘自网络)1.1.drbd —— DRBD(Distributed Replicated Block Device),DRBD号称是 "网络 RAID" ...
随机推荐
- php __autoload函数 加载类文件
面向对象的开发时,大家肯定都会遇到这样的问题,就是加载文件,一般都是加文件的头部inclue_once,require一大堆,看着很让人烦.当然你可以自己写程序来加载.php5以后引入了__autol ...
- JSP serverlet区别与联系
jsp是html包含java servlet是java包含html jsp请求到tomcat---tomcat封装了jsp到servlet实现. 所以jsp请求时候,会自动创建session 而不用在 ...
- Scala 的list
9.1 使用列表 列表类型:跟数组一样,列表也是同质化的(homogeneous).即所有元素都要是同种类型. 列表结构:所有列表由两部分组成:Nil 和 ::(cons). 基本操作:主要有三个:h ...
- 操作系统项目:向Linux内核添加一个系统调用
内容: 向Linux增加一个系统调用 撰写一个应用测试程序调用该系统调用 使用ptrace或类似的工具对该测试程序进行跟踪调 环境: 1.vmware workstation 15.0.0 2.ubu ...
- JavaWeb项目实现图片验证码
一.什么是图片验证码? 可以参考下面这张图: 我们在一些网站注册的时候,经常需要填写以上图片的信息. 这种图片验证方式是我们最常见的形式,它可以有效的防范恶意攻击者采用恶意工具,调用“动态验证码短信获 ...
- c#写出乘法口诀
显然是显得无聊五分钟写的乘法口诀 static void Main(string[] args) { int dq; int[] array ...
- python基础一 day13 迭代器
# 双下方法# print([1].__add__([2]))# print([1]+[2]) # 迭代器# l = [1,2,3]# 索引# 循环 for# for i in l:# i## for ...
- mysql安装(docker)
mkdir /opt/mysql vim /opt/mysql/Dockerfile 5.7 FROM alpine FROM mysql:5.7.26 EXPOSE 3306 8.0 FROM al ...
- [BZOJ2938]病毒 (AC自动机+dfs)
题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...
- shell脚本,awk替换{}里面的内容
如何将oxo{axbxc}oxo{dxexf}oxo里面的{}里面的x 替换为; 用awk实现 [root@localhost 09-30]# echo 'oxo{axbxc}oxo{dxexf}ox ...