MySql
数据类型
UNSIGNED
UNSIGNED属性就是将数字类型无符号化,无符号化的话就只有正数。例如INT,如果没有加UNSIGNED那么它的范围就是 − 2 31 -2^{31} −231~ 2 31 2^{31} 231(INT有4个字节,也就是32位,减去符号位,只有31位),而INT UNSIGNED的范围为0~ 2 32 2^{32} 232,因为去掉符号位就有32位了。
这看起来是一个不错的选项,特别是对住像主键这种自增的东西,开发者都希望为整数,但UNSIGNED可能会带来一些负面的影响。
比如下面这个栗子
CREATE TABLE t(
a INT UNSIGNED,
b INT UNSIGNED
)ENGINE=INNODB;
INSERT INTO t SELECT 1,2;
SELECT * FROM t;
SELECT a-b FROM t;
执行最后一条select语句的结果是
其实结果在不同的系统可能还会不一样
可以是 − 1 -1 −1,可以是一个很大的正值,也可能会报错,报错就是如上,out of range超出了范围。
原因其实是,这里 1 − 2 1-2 1−2变成十六进制的结果是 0 x F F F F F F F F 0xFFFFFFFF 0xFFFFFFFF,再转变成二进制其实是一串1, 11111111.... 11111111.... 11111111....,然后再将其变为十进制,如果是有符号位,那么前面的1代表是负数,然后取反加1,结果就是-1,如果前面没有符号位,那就表示一个很大的正数。
ZEROFILL
ZEROFILL像是一个长度属性,关系到的是数字类型后面的长度值,比如int(10),通常像这种类型后面添加的参数不是代表字符个数就是字节个数,那么整形应该已经是限定死是4个字节的,那这里的10代表什么?其实如果没有ZEROFILL这个属性,这里的10没有任何意义。
现在我们对上面创建的表进行修改,修改成int(4)和加上zerofill属性
ALTER TABLE t CHANGE COLUMN a a INT(4) UNSIGNED ZEROFILL;
//再进行查询
SELECT * FROM t;
ZEROFILL的效果其实就是如果宽度小于设定的宽度,则会进行自动填充0,要注意的是,这里只是最后显示的结果,在Mysql中实际存储的还是1,可以使用hex函数来证明
可以看到HEX(a)为1而不是0001,所以里面储存的还是1,而不是0001,其实也可以设想一下,如果数据库内部存储的是0001这样的字符串,又怎么进行整形的加减乘除呢?
SQL_MODE模式的设置
SQL_MODE是比较容易让人忽略的一个常量,默认为空,SQL_MODE的设置其实是一种比较冒险的设置,因为在这种设置下,可以允许一些非法操作,比如可以将NULL插入到非NULL的字段中,甚至可以插入一些非法日期,比如 “2012-12-32”,因此最好将这个值设为严格模式。
对于SQL_MODE的设置,可以在Mysql的配置文件如my.cnf和my.ini中进行,也可以在客户端的工具中进行,并且可以分别进行全局的设置或者当前会话的设置。下面的语句可以用来查看当前SQL_MODE的设置情况。
//查看全局
SELECT @@global.sql_mode;
//查看当前会话
SELECT @@session.sql_mode;
日期和时间类型
Mysql数据中总共有5种于日期和时间有关的数据类型
类型 | 所占空间 |
---|---|
DATETIME | 8个字节 |
TIMESTAMP | 4个字节 |
DATE | 3个字节 |
TIME | 3个字节 |
YEAR | 1个字节 |
DATITIME和DATE
DATETIME是占用空间最多的一种类型,占用了8个字节,可以显示日期同时也可以显示时间,其可以表达的范围为1000-01-01 00:00:00到9999-12-31 23:59:59。而DATE只可以表示日期,不可以显示时间,其可以表达的范围为1000-01-01到9999-12-31。
在mysql数据库中,对日期和输入格式的要求是十分宽松的,以下的输入都可以视为日期类型
2011-01-01 00:01:00
2011/01/01 00+01+10
20110101000110
11/01/01 00@01@10
其中,最后一种类型的年上面的11是表示离当前时间最近的年份。
SELECT CAST('11/01/01 00@01/10' AS DATETIME) AS datetime;
数据库的日期类型不能精确到微秒级别,任何的微妙数值都会被数据库截断。
CREATE TABLE t2(
a DATETIME
)
//插入微妙级别的数据
INSERT INTO t2 SELECT '2011-01-01 00:01:10.123456';
//查询插入的数据
SELECT a FROM t2;
不过mysql数据库提供了函数MICROSECOND函数来提取日期中的微秒值。
SELECT MICROSECOND('2011-01-01 00:01:10.123456');
mysql的CAST函数在强制转换到DATETIME时也会截断毫秒数,在插入之后同样会截断。
mysql从5.6.4版本开始,mysql增加了对秒的小数部分(fractional second)的支持,其具体语法是type_name(fsp)。
其中,type_name可以是TIME、DATETIME、和TIMESTAMP。fsp表示支持秒的小数部分的精度,最大为6,精确到微秒;默认是为0,表示没有小数部分,同时这也是为了兼容之前的DATETIEM和TIMESTAMP的用法,而对于一些时间函数,也增加了对fsp的支持,比如CURTIME()、SYSDATE()和UTC_TIMESTAMP()。
SELECT CURTIME(4) AS 'time';
#### TIMESTAMP
TIMESTAMP和DATETIME显示的效果是一样的,都是固定的YYYY-MM-DD HH:MM:SS类型,但TIMESTAMP只有4个字节,那是因为显示范围的不同,TIMESTAMP的显示范围是从UNIX的时间纪元开始(1970-01-01 00:00:00 UTC)到2038-01-19 03:14:07 UTC(Integer类型是4个字节,也就是32位,能表示的最长时间是68年,UTC是世界统一时间),而其实际存储的内容是1970-01-01 00:00:00到当前时间的毫秒数。
TIMESTAMP和DATETIME的不同
-
在建表时,列为TIMESTAMP类型的可以设置默认值而DATETIME不行
//虽然执行这条语句不会报错,但表中的a列信息还是没有默认值 CREATE TABLE t3( a DATETIME DEFAULT '2011-01-01 00:01:10' ) //不会报错,且有默认值信息 CREATE TABLE t4( b TIMESTAMP DEFAULT '2011-01-01 00:01:10' )
-
在更新表时,可以设置TIMESTAMP类型的列自动更新为当前时间
CREATE TABLE t5( a INT , b TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) INSERT INTO t5(a) VALUES(1); SELECT * FROM t5; //执行UPDATE时更新为当前时间的例子 CREATE TABLE t6( a INT, //设置b字段为update操作时,修改为当前时间 b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) INSERT INTO t6 SELECT 1,CURRENT_TIMESTAMP; //过一段时间 UPDATE t6 SET a = 2 WHERE a = 1; SELECT * FROM t6;
但要注意的是,要发生数据变化才会修改,即如果执行update操作,但数据还是不变,那么也不会进行更新的。原本是可以在建表时将TIMESTAMP的列设为一个默认值为更新时的时间,已经取消了。
YEAR和TIME
YEAR类型只会占用一个字节(也就是8位,可以储存范围为0~255),并且在定义时可以指定显示的宽度为YEAR(4)或者YEAR(2)(现在YEAR(2)已经被删除了,所以下面只讨论YEAR(4))。
YEAR(4)其显示年份为1901~2155
TIME类型占用3个字节,显示的范围为-839:59:59~838:59:59,TIME在时位上可以超过23,因为它不但可以表示一天的时间,也可以表示时间间隔(几天或者一个月),同时这也表示了为什么会有负数,TIME和DATETIME类型一样,也可以显示微秒时间MISCOPESECOND(),也一样会被掐断。
与日期相关的函数
NOW、CURRENT_TIMESTAMP和SYSDATE
这三个函数都是返回当前时间,并且有一点区别
SELECT NOW(),CURRENT_TIMESTAMP(),SYSDATE();
SLEEP前
SLEEP后
SYSDATE明显睡了两秒,也就是说,返回的是执行到函数的时间
时间加减函数
无论是时间类型还是时间函数类型,都不可以简单使用加减号来进行运算,如果使用加减号来进行运算,会发现只是简单地按位对应来加减而已,没有返回正确的时间类型。
CREATE TABLE t7(
a TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
b TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
INSERT INTO t7 VALUES();
SELECT a+b,a,b FROM t7;
SELECT NOW(),NOW()+0;
具体使用过的方法是DATE_ADD(date,INTERVAL expr unit)和DATE_SUB(date,INTERVAL,expr,unit),分别是假发和减法(INTERVAL是间隔的意思)
SELECT NOW() AS cur,DATE_ADD(NOW(),INTERVAL 1 DAY) AS tomorrow,DATE_SUB(NOW(),INTERVAL 1 DAY) AS yesterday;
其中expr值可以是hi一个负数,因此单纯使用DATE_ADD也可以完成DATE_SUB的操作。
SELECT NOW() AS cur,DATE_ADD(NOW(),INTERVAL -1 DAY) AS yesterday;
如果是闰月的话(比如不是闰年的2月28日加上4年,就会变成闰年的2月29日),DATE_ADD函数返回的日期是2月29日,如果不是闰月,那么返回的日期是2月28日。
SELECT DATE_ADD('2000-02-29',INTERVAL 4 YEAR);
SELECT DATE_ADD('2000-02-29',INTERVAL 5 YEAR);
除了DAY和YEAR之外,还有其他类型的,比如MICROSECOND(微秒会被截断)、SECOND(秒)、MINUTE(分钟)、HOUR、WEEK、MONTH等类型
DATE_FORMAT函数
按照用户的需求格式化打印出日期
SELECT DATE_FORMAT(NOW(),"%Y%m%d");
数字类型
整形
整形类型有INT、SMALLINT、TINYINT、MEDIUMINT和BIGINT。
类型 | 占用空间(字节) | 最小值 | 最大值 |
---|---|---|---|
TINYINT | 1 | -128(有符号位) | 255 |
SMALLINT | 2 | -32768(-2^15) | 2^16 |
MEDIUNINT | 3 | -2^23 | 2^24 |
INT | 4 | -2^31 | 2^32 |
BIGINT | 8 | -2^63 | 2^64 |
对于整形,前面有两个相关的属性就是ZEROFILL和UNSIGNED,一旦开启了ZEROFILL那么UNSIGNED也会自动开启。
浮点型(非精确类型)
Mysql支持两种浮点类型,单精度的FLOAT类型以及双精度的DOUBLE PRECISION类型。这两种类型都是非精确的类型,即经过一些操作之后并不能保证运算的准确性,例如M*G/G不一定会等于M。
FLOAT类型用于表示近似数值数据类型,SQL标准允许在关键字FLOAT后面的括号内用位来指定精度(但不能为指数范围)。Mysql还支持可选的只用于确定存储大小的精度规定,0到23的精度对应FLOAT列的4字节单精度,24到53的精度对应DOUBLE列的8字节双精度。
Mysql还允许使用非标准语法,FLOAT(M,D)或REAL(M.D)或DOUBLE PRECISION(M,D)。这里的(M,D)表示该值一共显示M位整数,其中D位是小数点后面的位数。例如FLOAT(7,4)的一个列可以显示为-999.9999。如果超出了范围,Mysql保存值时会进行四舍五入,比如在FLOAT(7,4)中插入999.00009,会变成999.0001。
Mysql将DOUBLE视为DOUBLE PRECISION(非标准扩展)的同义词,将REAL视为DOUBLE PRECISION(非标准扩展)的同义词,即REAL和DOUBLE都是DOUBLE PRECISION,若将Mysql服务器的模式设置,REAL_AS_FLOAT,那这时REAL会被视为FLOAT类型。
为了保证最大的可以可移植性(保证精确性,因为如果不满长FLOAT参数里面的长度会进行补充),需要使用近似数值数据值存储的代码,使用FLOAT或DOUBLE PRECISION,并不规定精度或者位数。
高精度类型
DECIMAL和NUMERIC类型在Mysql中被视为相同的类型,用于保存必须为确切精度的值,比如工资,当声明该类型的列时,通常必须指定精度和标度(精度指数字位数即保存值的主要位数,标度指小树点后面可以保存的位数),例如 salary DECIMAL(5,2) ,精度为5,标度为2。在标准SQL中,语法DECIMAL(M)等价于DECIMAL(M,0),M默认是10的。
CREATE TABLE t10(
a DECIMAL
)
SHOW CREATE TABLE t10;
DECIMAL或NUMERIC的最大位数是65位,但具体的DECIMAL或NUMERIC列的实际范围受具体列的精度或标度约束。如果分配给此类列的值的小数点后位数超过指定的标度允许的范围,值将按该标度进行转换,即列的标度大于指定标度,可以按指定标度来进行转化(一般列允许的标度跟操作系统有关,和mysql版本)。
位类型
位类型,即BIT数据类型可用来保存位字段的值,BIT(M)类型表示允许存储M位数值,M范围为1到64,占用的空间为(M+7)/8字节。如果为BIT(M)列分配的值的长度小于M位,会在值得左边用0来填充,例如BIT(6)列分配一个值b’101’,其效果与分配b’000101’相同(这里b代表是BIT类型,位类型),要指定类型,可以使用b’value’符
CREATE TABLE t11(
a BIT(4)
)
INSERT INTO t11 SELECT b'1000';
SELECT HEX(a),a FROM t11;
#### 字符类型
字符集
我们首先来认识一下字符集,字符集其实由字符组成的,通俗讲是字符集合嘛,比如什么什么支持gbk字符集,那么他就可以识别出gbk字符集里面包含的字符,然后来认识一下字符编码,字符编码其实是由字符集来支持的,字符编码其实是由字符和它对应的唯一二进制编码组成的,即形成一个映射关系,比如gbk字符集支持Unicode编码,那么gbk里面的字符就可以对应Unicode里面的映射关系,变成二进制,然后储存在计算机中,我们所说的乱码情况,就是字符集使用了不支持的编码方式,导致解码错误,也就是映射关系出现问题。
对于简体中文,我们习惯使用gbk或gb2312,这两者的关系是gbk是gb2312的超集,因此可以支持更多的汉字,不过当前mysql不支持中文字符集gb18030,因此在有些应用中已经出现gbk不能显示特定中文字体的情况了,如果使用繁体中文的话,big5是首选的字符集。
Unicode和utf8的区别
Unicode是一种在计算机上使用的字符编码,为每种语言的每个字符设定了统一且唯一的二进制编码,utf8是字符集。对于Unicode编码的字符集,尽量将所有CHAR字段设置为VARCHAR字段,因为对于CHAR字段,数据库会保存最大可能的字节数,比如CHAR(30),字段中可以储存的字符长度为30,但表中使用的字符集允许一个字符占的最大字节为3,那么CHAR(30),数据库可能存储90字节的数据。
对字符集的设置可以在Mysql的配置文件中完成(my.ini)
mysql可以细化每个对象字符集的设置
CREATE TABLE t12(
a VARCHAR(10) CHARSET gbk,
b VARCHAR(10) CHARSET latin1,
c VARCHAR(10)
)CHARSET=utf8;
c列这里没有设置字符集,所以会使用表的字符集utf8,如果表也没有字符集,那就会使用架构(数据库)时指定的字符集,如果在创建数据库中也没有规定字符集,那就会使用数据库配置文件中指定的字符集。
排序规则
排序规则是指对指定字符集下不同字符的比较规则,其特征有以下几点。
- 两个不同的字符集可能有相同的排序规则
- 每个字符集有一个默认的排序规则
- 常用的命令规则
- _ci(case insensitive)表示大小写不敏感
- _cs(case sensitive)表示大小写敏感
- _bin(binary)表示二进制的比较
SHOW CHARSET; //可以查看Mysql支持的所有字符集,里面的Default_collation就是默认支持的排序规则
SHOW COLLATION; //查看支持的各种排序规则
SHOW COLLATION LIKE "gbk%"; //查找关于gbk字符集的排序规则
如果需要查看gbk字符集默认的排序规则
SHOW CHARSET LIKE "gbk%";
可以看到,gbk默认的比较方式是gbk_chinese_ci,跟上一章表Default字段为yes的对应。
排序规则有什么影响
CREATE TABLE t13(
a VARCHAR(10)
)CHARSET=utf8;
INSERT INTO t13 SELECT "a";
INSERT INTO t13 SELECT "A";
SELECT * FROM t13 WHERE a = "a";
最后一条查询语句的结果是下图所示
再看看utf8的默认排序规则
SHOW CHARSET LIKE utf8
可以看到utf8默认的排序规则是_ci,也就是大小写不敏感,所以对于语句where a = “a”,并不会区分大小写,将A也搜索了出来。
再查查
SELECT "a" = "A"; //查看当前会话的排序规则
可以看到返回值为1,所以认为这两个字符的比较结果是相等的,如果要进行区分大小写,可以设置当前会话的排序规则,语句为SET NAMES … COLLATE …
SET NAMES utf8 COLLATE utf8_bin //修改为二进制排序规则
此时,返回值就为0了,数据库认为a和A是不同的字符,但如果需要对表中字段进行区分,需要将指定列的排序规则进行修改
ALTER TABLE t13 MODIFY COLUMN a VARCHAR(10) COLLATE utf8_bin;
//再次执行
SELECT * FROM t13 WHERE a = 'A';
排序规则不仅会影响大小写的比较问题,也会影响着索引。
//将a列修改回原来定义的排序规则
ALTER TABLE t13 MODIFY COLUMN a VARCHAR(10) COLLATE utf8_general_ci;
//给a加一个唯一索引
ALTER TABLE t13 ADD UNIQUE KEY(a);
结果
因为大小写不敏感,所以存在着列a中是存在2个相同的值的,所以无法进行添加唯一索引。。索引是B+树,加索引时会进行比对。
CHAR和VARCHAR
这是两种最常用的字符串类型,一般来说CHAR(N)是用来保存固定长度的字符串,VARCHAR(N)用来保存可变长字符类型,对于CHAR类型,N的范围为0 ~ 255( 2 8 2^8 28),对于VARCHAR类型,N的取值范围为0 ~ 65535( 2 16 2^{16} 216),两种类型的N都代表字符长度,而不是字节长度。
注:不过在mysql4.1之前的版本,N是代表字节长度。
对于CHAR类型的字符串,Mysql数据库会自动对存储列的右边进行填充(Right Padded)操作,直到字符串达到指定的长度N,而在读取该列时,mysql数据库会自动将填充的字符删除(所以建议如果是固定长度的字符串才使用CHAR,不固定的使用VARCHAR),有一种情况例外,可以将SQL_MODE设置为PAD_CHAR_TO_FULL_LENGTH。
ALTER TABLE t13 MODIFY COLUMN a CHAR(10);
SELECT a,HEX(a),LENGTH(a) FROM t13;
//修改Sql_mode模式
SET sql_mode='pad_char_to_full_length';
SELECT a,HEX(a),LENGTH(a) FROM t13;
LENGTH()函数返回的是字节长度而不是字符长度(一个汉字是两个字节),CHAR_LENGTH()函数返回的是字节长度,因此可以得出CHAR类型会进行填满的(如果没有改变SQL_MODE,会将填充的进行删除,所以返回的不会是10,而是3),对于多字节字符集,CHAR(N)长度的列最多可占用的字节数为该字符集单字符最大的字节数 * 字符长度,例如在utf8下,CHAR(10)最多可能占用30个字节,因为utf8单个字符可以占最大3个字节。
SELECT @a:='MySql技术内幕';
SELECT @a,HEX(@a),LENGTH(@a),CHAR_LENGTH(@a);
在utf8字符集下,一个汉字占3个字节,gbk下,一个汉字占2个字符。
CREATE TABLE t14(
a VARCHAR(10) CHARSET utf8,
b VARCHAR(10) CHARSET gbk
)
INSERT INTO t14 SELECT "MySql计数内幕","MySql计数内幕";
SELECT a,LENGTH(a),CHAR_LENGTH(a),b,LENGTH(b),CHAR_LENGTH(b) FROM t14;
VARCHAR类型储存变长字段的字符类型,与CHAR类型不同的是,其存储时需要在浅醉长度列表上加上实际存储的字符,该字符会占用1~2字节的空间,具体的规则如下,当储存的字符串长度小于255(
2
8
2^8
28)时,其需要1个字节空间,当大于255(
2
8
2^8
28)字节时,需要2字节的空间。所以对于lantin1字符集(单个字符占最大的字节为1)来说,CHAR(10)和VARCHAR(10)占用最大字节是不同的,CHAR(10)肯定是10个字节,但VARCHAR(10)至少为11个字节,如果为VARCHAR(255)甚至会12个字节,因为需要额外的字节来存放字符长度。
虽然CHAR和VARCHAR的存储方式不太相同,但是对于两个字符串的比较,都只比较其值,忽略CHAR值存在的右填充,即使将SQL_MODE设置为PAD_CHAR_TO_FULL_LENGTH也一样。
BINARY与VARBINARY
这两个与CHAR和VARCHAR比较类似,唯一不同的是BINARY与VARBINARY存储的是二进制的字符串(存储的是二进制,图片,视频那些),而且BINARY与VARBINARY没有字符集的概念,对其排序和比较都是按照二进制值进行对比的,
BINARY(N)和VARBINARY(N)中的N是指字节长度(CHAR,VARCHAR的N是字符长度),对于BINARY(10),其可存储的字节固定为10,而对于CHAR(10),其存储的字符长度为10,但字节长度不一样(需要知道字符集单个字符所占用的最大字节)。
CREATE TABLE t15(
a BINARY(1)
)ENGINE=INNODB CHARSET=GBK;
//修改为gbk字符集
SET NAMES GBK;
//插入数据
INSERT INTO t15 SELECT '我';
SELECT a,HEX(a) FROM t15;
结果
在表中,字段a是一个BINARY(1)占一个字节,而在GBK字符集中,一个汉字占两个字节,所以根本不够内存,所以在插入时会给出警告,提示字符被截断,如果SQL_MODE为严格模式,则会直接报错。
//修改a列为2字节
ALTER TABLE t15 MODIFY COLUMN a BINARY(2);
SELECT a,HEX(a) FROM t15;
CHAR VARCHAR和BINARY VARBINARY的不同之处
SELECT a,LENGTH(a) FROM t15;
首先第一个不同之处就是参数N,CHAR和VARCHAR的N是字符长度,而BINARY和VARBINARY的N是字节长度。第二个不同的是CHAR和VARCHAR进行比较时,比较的是存储的字符,忽略字符后的填充字符,而对于BINARY和VARBINARY来说,由于是按照二进制值来进行比较的(BINARY也会进行填充,而且比较时并不会忽略填充字符,由上图可知),因此结果会不同。
SELECT HEX('a'),HEX('a '),'a'='a ';
SELECT HEX(BINARY('a')),HEX(BINARY('a ')),BINARY('a')=BINARY('a ');
BLOB和TEXT
BLOB是用来存储二进制大数据类型的(比如图片和视频),根据储存长度的不同,BLOB可细分为以下4中类型,括号中的数代表存储的字节数。
-
TINYBLOB( 2 8 2^8 28)
-
BLOB( 2 16 2^{16} 216)
-
MEDIUMBLOB( 2 24 2^{24} 224)
-
LONGBLOB( 2 32 2^{32} 232)
TEXT类型同BLOB一样,也可以细分为4种类型
- TINYTEXT( 2 8 2^8 28)
- TEXT( 2 16 2^{16} 216)
- MEDIUMTEXT( 2 24 2^{24} 224)
- LONGTEXT( 2 32 2^{32} 232)
在大多数情况下,可以将BLOB类型的列视为足够大的VARBINARY类型的列。同样,也可以将TEXT类型的列视为足够大的VARCHAR类型的列,然而,在BLOB和TEXT在以下几方面又不同于VARBINARY和VARCHAR
- 在BLOB和TEXT类型的列上创建索引时,必须指定索引前缀的长度,而VARCHAR和VARBINARY的前缀长度是可选的(索引前缀其实是适用于很长的数据,因为数据很长,会让索引变得也很长(索引要进行比对的),所以要规定前缀索引来索引开始的一部分字符,如果前面一部分字符相同,那就是匹配成功,这样可以大大节约索引空间,从而提高索引效率,但这样会降低索引的选择性即可能存在匹配错误情况,前面一部分匹配成功,但后面不正确)
- BLOB和TEXT类型的列不能有默认值
- 在排序时,只是用列的前max_sort_length个字节(默认值为1024,该参数是一个动态参数,可以在客户端进行更改)
在数据库中,最小的存储单位是页(也可以称为块)。为了有效存储列类型为BLOB或者TEXT的大数据类型,一般将这种属性的列的值存放在行溢出页中,而数据页存储的行数据只包含BLOB或TEXT类型数据列的前一部分数据。
数据页是由许多的行数据组成,每行数组由各个列组成,对于列类型为BLOB的数据,InnoDB存储引擎只存储前20字节,而该列的完整数据则存放在BLOB的行溢出页中,在这种方式下,数据页中能存放大量的行数据,从而提高了数据的查询效率
此外,InnoDB引擎会将大VARCHAR类型字符串,比如VARCHAR(65530),也就是VARCHAR最大字符长度( 2 16 2^{16} 216),会自动转化为TEXT或者BLOB类型。
ENUM和SET类型
ENUM和SET都是集合类型,不同的是ENUM类型最多可以枚举65536( 2 16 2^{16} 216)个元素,而SET类型中最多枚举64个元素( 2 6 2^6 26)。
由于MySQL不支持传统的CHECK约束,因此通过ENUM和SET类型并结合SQL_MODE可以解决一部分问题,例如,表中有一个"性别"列,规定域的范围只能是"male"或者"female",在这种情况下可以通过ENUM类型结合严格的SQL_MODE模式来进行约束
CREATE TABLE t16(
user_name VARCHAR(33),
sex ENUM("male","female")
)ENGINE=INNODB
//设置为严格模式
SET sql_mode = 'strict_trans_tables';
INSERT INTO t16 SELECT 'David','male';
INSERT INTO t16 SELECT 'Mike','female';
//下面这条会插入失败
INSERT INTO t16 SELECT 'John','bimale';