Mysql varchar(max)

设计数据库时,不禁有这样的疑问,varchar()最大可以设置多大呢?与什么有关呢?

字符集

为什么要有字符集?

简单讲,数据在网络上传输与硬盘中储存,都是以二进制的形式存在的。我们熟知的文字、图片以及视频想要存储与传输,必然需要一套规则,使其成为可以被储存和传输的二进制数据,而字符集则是文字编解码的规则。
详情可参考字符编码的历史演变

在数据的储存上,mysql提供了不同的字符集支持。

查看mysql支持的字符集:

mysql> show character set;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| armscii8 | ARMSCII-8 Armenian              | armscii8_general_ci |      1 |
| ascii    | US ASCII                        | ascii_general_ci    |      1 |
...
| gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
| utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
| utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_0900_ai_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.01 sec)

Mysql 提供了server、database、table、column级字符集设置。
字符集规则是可以继承的,也就是说:

  • column 没有设置则继承 table 的字符集设置。
  • table 没有设置则继承 database 的字符集设置。
  • database 没有设置则继承 server 的字符集设置。

查看全局字符集设置:

mysql> show global variables like'%character_set%';
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8                           |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.01 sec)

note:字符集设置不当会出现汉字乱码。

char与varchar

char:固定长度类型,char(n)则表示只能储存n字节数据,不足n则在末尾填充空格,最大存储255字符。占用储存空间n × 字符集最大占用字节。
varchar:可变长度类型,varchar(n)则表示可存储char_length(n)长度的字符,储存空间占用(字符集最大占用 × n + 1 or 2长度字节),字节数 > 255 时用2字节表示长度。

length() 与 char_length()

char_length():返回字符长度,与空间占用大小无关

mysql> select char_length('a'),char_length('1'),char_length('hello world'),char_length('你好');
+------------------+------------------+----------------------------+-----------------------+
| char_length('a') | char_length('1') | char_length('hello world') | char_length('你好')   |
+------------------+------------------+----------------------------+-----------------------+
|                1 |                1 |                         11 |                     2 |
+------------------+------------------+----------------------------+-----------------------+
1 row in set (0.00 sec)

length(): 返回占用字节数

mysql> select length('a'),length('1'),length('hello world'),length('我'),length("你好"),length('🤤');
+-------------+-------------+-----------------------+---------------+------------------+-------------+
| length('a') | length('1') | length('hello world') | length('我')  | length("你好")   | length('?') |
+-------------+-------------+-----------------------+---------------+------------------+-------------+
|           1 |           1 |                    11 |             3 |                6 |           4 |
+-------------+-------------+-----------------------+---------------+------------------+-------------+
1 row in set (0.00 sec)

utf8mb4是mysql在5.5之后新增的字符集编码mb4就是most bytes 4的意思,可编码4字节字符。所以utf8不支持emoji在utf8mb4解决了

不同的字符集的空间占用。

  • 创建一个字符集为utf8mb4的表
mysql> create table test_utf8mb4 (cu varchar(10), dcu varchar(10),cn varchar(10),dcn varchar(10),smy varchar(10)) charset=utf8mb4;
Query OK, 0 rows affected (0.02 sec)
// 插入一条数据
mysql> insert into test_utf8mb4 (`cu`,`dcu`,`cn`,`dcn`,`smy`) values ('a','hello','你',"你好",'🤤');
Query OK, 1 row affected (0.00 sec)

mysql> select length(cu),length(dcu),length(cn),length(dcn),length(smy) from test_utf8mb4;
+------------+-------------+------------+-------------+-------------+
| length(cu) | length(dcu) | length(cn) | length(dcn) | length(smy) |
+------------+-------------+------------+-------------+-------------+
|          1 |           5 |          3 |           6 |           4 |
+------------+-------------+------------+-------------+-------------+
1 row in set (0.00 sec)

在utf8mb4字符集中,英文数字占1个字节,中文占用3个字节,emoji占用4字节。

  • 创建一个字符集为gbk的表
mysql> create table test_gbk (cu varchar(10), dcu varchar(10),cn varchar(10),dcn varchar(10),smy varchar(10)) charset=gbk;
Query OK, 0 rows affected (0.02 sec)
// 插入一条数据
mysql> insert into test_gbk (`cu`,`dcu`,`cn`,`dcn`,`smy`) values ('a','hello','你',"你好",'🤤');
ERROR 1366 (HY000): Incorrect string value: '\xF0\x9F\xA4\xA4' for column 'smy' at row 1
// emoji是一个不正确的值,可以看到smy是一个4字节字符。
mysql> insert into test_gbk (`cu`,`dcu`,`cn`,`dcn`) values ('a','hello','你',"你好");
Query OK, 1 row affected (0.00 sec)

mysql> select length(cu),length(dcu),length(cn),length(dcn),length(smy) from test_gbk;
+------------+-------------+------------+-------------+-------------+
| length(cu) | length(dcu) | length(cn) | length(dcn) | length(smy) |
+------------+-------------+------------+-------------+-------------+
|          1 |           5 |          2 |           4 |        NULL |
+------------+-------------+------------+-------------+-------------+
1 row in set (0.00 sec)

gbk的字符集中,英文数字占1字节,中文占2字节,且只能保存2字节及以下字符。

在mysql中,char(n) or varchar(n)中的n代表的是可插入的字符长度,非字节空间
既然n指的是字符长度,char(n)最大255,那么varchar(n)最大可以设置为多少呢?

行大小限制

在mysql中,mysql有65535字节的最大行大小限制。也就是说,所有字段占用的空间都被包含在65535字节中。

  • 新建一个varchar(65535)的表
mysql> create table long_var (v varchar(65535) not null);
ERROR 1074 (42000): Column length too big for column 'v' (max = 16383); use BLOB or TEXT instead
// 报错,提示最大值为16383

16383 * 4 = 65532,还有3字节空间呢?
这样看起来并不直观,utf8mb4占用4字节空间,不如用latin1代替,latin1只占用一字节。

mysql> create table long_var (v varchar(65535)) charset=latin1;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
// 失败,提示最大行大小为65535。
// 对了,varchar()还有2个字节的长度标识位。
mysql> create table long_var (v varchar(65533)) charset=latin1;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
// 65533 还报错?
mysql> create table long_var (v varchar(65533) not null) charset=latin1;
Query OK, 0 rows affected (0.02 sec)
// 同样65533成功了,接下来就是找不同的时间了。

第二条语句多了一条not null 的语句,在mysql中行大小除了数据列长度,还包括可空标识,即NULL标识。
如果有一个列允许为空,则需要1 bit来标识,每8 bits的标识会组成一个字段,该字段会存放在每行最开始的位置。可空表示是行内共享的。
那么,新建一个可空列的表,字段长读应设置为65535 - 2字节长度 - 1字节null标识 = 65532;

mysql> create table long_var_32 (v varchar(65532)) charset=latin1;
Query OK, 0 rows affected (0.02 sec)

varchar()的最大长度,受字符集限制,且行内共65535字节的大小,也就是说varchar(65532)只能有一个。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • MySQL数据库对象与应用 2.1-MySQL数据类型 库建立好之后基本不动,和我们接触最频繁的是表. 建表就是声...
    极客圈阅读 2,129评论 0 8
  • 一、数据库简介 1.数据库系统 1.1数据库 DataBase【DB】,指的是长期保存到计算机上的数据,按照一定顺...
    郑元吉阅读 592评论 0 6
  • 什么是数据库? 数据库是存储数据的集合的单独的应用程序。每个数据库具有一个或多个不同的API,用于创建,访问,管理...
    chen_000阅读 4,030评论 0 19
  • MySQL技术内幕:SQL编程 姜承尧 第1章 SQL编程 >> B是由MySQL创始人之一Monty分支的一个版...
    沉默剑士阅读 2,408评论 0 3
  • 对于我们这些缺乏难忘经历,没有做出“丰功伟绩”的,不如意事常八九,能与人言无二三的平凡的大多数来说,一辈子所做出的...
    冷悲秋阅读 1,200评论 2 51