MySQL 支持的数据类型(关系型数据库)

1、数值类型

  • MySQL 支持所有标准 SQL 中的数值类型,其中包括严格数值类型(integer、smallint、decimal、numeric),以及近似数值数据类型(float、real、double precision),并在此基础上做了扩展,扩展后增加了 tinyint、mediumint 和 bigint 这 3 种长度不同的整型,并增加了 bit 类型,用来存放位数据。

1.1 整数类型

1.1.1 分类

  • 按照取值范围和存储方式不同,分为 tinyint、smallint、mediumint、int(即 integer)和 bigint 这 5 个类型,分别为 1、2、3、4、8 字节,如果超出类型范围的操作会发生 “Out of range” 错误提示。
整数类型 字节 最小值(有符号 无符号) 最大值(有符号 无符号) 描述
tinyint 1 -128,0 127,255 tinyint[(m)] [unsigned] [zerofill]
smallint 2 -32768,0 32767,65535 smallint[(m)] [unsigned] [zerofill]
mediumint 3 -8388608,0 8388607,1677215 mediumint[(m)] [unsigned] [zerofill]
int、integer 4 -2147483648, 0 2147483647,4294967295 int[(m)] [unsigned] [zerofill]
bigint 8 -9223372036854775808,0 9223372036854775807,18446744073709551615 bigint[(m)] [unsigned] [zerofill]

1.1.2 指定显示宽度

  • 对于整型数据,MySQL 还支持在类型名称后加 “(m)” 的方式来指定显示宽度,”(m)” 表示该值一共显示 m 位数字,m 又称为精度,如果不显示指定宽度则默认为 int(11)。

  • 一般配合 zerofill 使用,即在数字位数不够的空间用字符 “0” 填满。

  • 在设置了宽度限制后,如果插入值大于限制宽度,这时,宽度格式已经没有意义,还是按照类型的实际精度(如:int 无符号的数值范围为0-255)进行保存,左边不会再填充任何的 “0” 字符。

1.1.3 属性

  • unsigned(无符号)

    • 可选属性需要在字段里面保存非负数或者需要较大的上限值时使用。
    • 如果一个列指定为 zerofill,则 MySQL 自动为该列添加 unsigned 属性。
  • auto_increment

    • 在需要产生唯一标识符或顺序值时使用,即 not null、主键 primary key 或者 unique 键的整数类型。
    • auto_increment 值初始值为 1,增加幅度为 1。
    • 一个表中最多只能有一个 auto_increment 列。

1.2 小数类型

1.2.1 分类

  • 分为浮点数和定点数。
浮点数类型 字节 最小值(有符号 无符号) 最大值(有符号 无符号) 描述
float 4 ± 1.175494351E-38 ± 3.402823466E+38 float[(m, d)] [unsigned] [zerofill]
double 8 ± 2.2250738585072014E-308 ± 1.7976931348623157E+308 double[(m, d)] [unsigned] [zerofill]
  • 浮点数一般用于表示含有小数部分的数值,包括 float(单精度)和 double(双精度)。
定点数类型 字节 最小值(有符号 无符号) 最大值(有符号 无符号) 描述
dec(m, d)、decimal(m, d)、numeric(m, d) m + 2 最大取值范围与 double 相同,给定 dec 的有效值范围由 m 和 d 决定 dec[(m, d)] [unsigned] [zerofill]
  • 在 MySQL 中,decimal(或 numberic)用来表示定点数,定点数实际上是以字符串形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。

1.2.2 指定显示宽度

  • 浮点数和定点数都可以用类型名称后加 “(m, d)” 的方式来进行表示,”(m, d)” 表示该值一共显示 m 位数字(整数位+小数位),其中 d 位位于小数点后面,m 和 d 又称为精度和标度。

  • 浮点数如果不写精度和标度,则会按照实际精度值显示。

  • 当一个字段被定义为浮点类型后,如果插入数据的精度超过该列定义的实际精度,则插入值会被四舍五入到实际定义的精度值,然后插入,四舍五入的过程不会报错。

  • 定点数如果不写精度和标度,则按照默认值 decimal(10, 0) 来进行操作。

  • 当一个字段被定义为定点数类型后,如果实际插入的数值精度大于实际定义的精度,则 MySQL 会进行警告(默认的 SQLMode 下),但是数据按照实际精度四舍五入后插入;如果 SQLMode 是在 traditional(传统模式)下,则系统会直接报错,导致数据无法插入。

1.2.3 使用原则

  • 浮点数存在误差问题;
  • 对货币等对精度敏感的数据,应该用定点数表示或存储;
  • 在编程中,如果用到浮点数,要特别注意误差问题,并尽量避免做浮点数比较;
  • 要注意浮点数中一些特殊值的处理。

1.2.4 示例

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    > create table t (f float(8, 1));

    Query OK, 0 rows affected (0.03 sec)

    > desc t;

    +-------+------------+------+-----+---------+-------+
    | Field | Type | Null | Key | Default | Extra |
    +-------+------------+------+-----+---------+-------+
    | f | float(8,1) | YES | | NULL | |
    +-------+------------+------+-----+---------+-------+
    1 row in set (0.00 sec)

    > insert into t values (1.23456), (1.25456);

    Query OK, 1 row affected (0.05 sec)

    > select * from t;

    +------+
    | f |
    +------+
    | 1.2 |
    | 1.3 |
    +------+
    2 rows in set (0.00 sec)
  • 从上面的例子中,可以发现对于第一次插入值 1.23456 到 float(8, 1)时,该值被截断,并保存为 1.2,而插入值 1.25456 到 float(8, 1) 时,该值进行了四舍五入然后被截断,并保存为 1.3,所以在选择浮点型数据保存小数时,要注意四舍五入的问题,并尽量保留足够的小数位,避免存储的数据不准确。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    > create table test (c1 float(10, 2), c2 decimal(10, 2));

    Query OK, 0 rows affected (0.03 sec)

    > insert into test values (131072.32, 131072.32);

    Query OK, 1 row affected (0.02 sec)

    > select * from test;

    +-----------+-----------+
    | c1 | c2 |
    +-----------+-----------+
    | 131072.31 | 131072.32 |
    +-----------+-----------+
    1 row in set (0.00 sec)
  • 从上面的例子中可以看到,c1 列的值由 131072.32 变成了 131072.31,这是上面的数值在使用单精度浮点数表示时,产生了误差。这是浮点数特有的问题。因此在精度要求比较高的应用中(比如货币)要使用定点数而不是浮点数来保存数据。

  • 另外,浮点数的比较也是一个普遍存在的问题,在编程中应尽量避免浮点数的比较,如果非要使用浮点数的比较则最好使用范围比较而不要使用 “==” 比较。

1.3 位类型

1.3.1 用途

  • bit(m)位类型用于存放位字段值,

  • bit(m) 可以用来存放多位二进制数,M范围从 1~64,如果不写则默认为 1 位。

1.3.2 查看位类型字段

  • 对于位字段,直接使用 select 命令将不会看到结果,可以使用 bin(列名)(显示为二进制格式)或者 hex(列名)(显示为十六进制格式)函数进行读取。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 查看位类型字段值
    > select bin(id), hex(id) from t2;

    +---------+---------+
    | bin(id) | hex(id) |
    +---------+---------+
    | 1 | 1 |
    +---------+---------+
    1 rows in set (0.00 sec)

1.3.3 位类型字段插入操作

  • 数据插入 bit 类型字段时,首先转换为二进制,如果位数允许,将成功插入;如果位数小于实际定义的位数,则插入失败。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 插入位类型字段值
    > insert into t2 values(2);

    Query OK, 1 row affected (0.00 sec)

    > select bin(id), hex(id) from t2;

    +---------+---------+
    | bin(id) | hex(id) |
    +---------+---------+
    | 1 | 1 |
    | 10 | 2 |
    +---------+---------+
    2 rows in set (0.00 sec)

2、日期时间类型

  • MySQL 中有多种数据类型可以用于日期和时间的表示,不同的版本可能有所差异。

2.1 日期时间类型

2.1.1 分类

  • 每种日期时间类型都有一个有效值范围,如果超出这个范围,在默认的 SQLMode 下,系统会进行错误提示,并将以零值来进行存储。
日期时间类型 字节 最小值 最大值 格式 描述
date 4 1000-01-01 9999-12-31 YYYY-MM-DD date
time 3 -838:59:59.000000 838:59:59.000000 HH:MM:SS[.fraction] time[(fsp)]
datetime 8 1000-01-01 00:00:00.000000 9999-12-31 23:59:59.999999 YYYY-MM-DD HH:MM:SS[.fraction] datetime[(fsp)]
timestamp 4 1970-01-01 00:00:01.000000 UTC 2038-01-19 03:14:07.999999 UTC YYYY-MM-DD HH:MM:SS[.fraction] timestamp[(fsp)]
year 1 1000 9999 YYYY year(date)
  • timestamp:YYYY-MM-DD HH:MM:SS 格式的字符串

    • 应用场合:需要经常插入或者更新日期为当前系统时间的时候用。
    • 显示宽度固定为 19 个字符。如果想要获得数字值,应在 timestamp 列添加 “+0”。
    • MySQL 规定,timestamp 类型字段一列的默认值为 current_timestamp,如果强制修改,系统会报错。
    • MySQL 只给表中的第一个 timestamp 字段设置默认值为系统日期,如果有第二个 timestamp 类型,则默认值设置为 0 值。
    • 特点:与时区相关。当插入日期时,会先转换为本地时区后存放;而从数据库里面取出时,也同样需要将日期转换为本地时区后显示。这样,两个不同时区的用户看到的同一个日期可能是不一样的。
  • year:YYYY

    • 它比 date 占用更少的空间。
    • year 有 2 位或 4 位格式的年,默认是 4 位格式。
    • 在 4 位格式中,允许的值是 1901~2155 和 0000。
    • 在 2 位格式中,允许的值是 70~69,表示从 1970~2069 年。
    • MySQL 以 YYYY 格式显示 year 值(从 5.5.27 开始,2 位格式的 year 已经不被支持)。

2.1.2 零值

  • 每种日期时间类型都有一个有效值范围,如果超出这个范围,在默认的 SQLMode 下,系统会进行错误提示,并将以零值来进行存储。
类型 零值
date 0000-00-00
time 00:00:00
datetime 0000-00-00 00:00:00
timestamp 0000-00-00 00:00:00
year 0000

2.1.3 timestamp 和 datetime 的区别

  • 时间取值范围不同

    • timestamp:1970-01-01 08:00:01 到 2038 年的某个时间,时间取值范围较小。
    • datetime :1000-01-01 00:00:00 到 9999-12-31 23:59:59,范围较大。
  • 时间属性的不同

    • timestamp

      • 表中的第一个 timestamp 列自动设置为系统时间 current_timestamp。如果在一个 timestamp 列中插入 null 或者不明确给该列赋值时,则该列值将自动设置为当前的日期和时间。
      • 当插入的值超出取值范围时,MySQL 认为该值溢出,使用零值 “0000-00-00 00:00:00” 进行填补。
      • timestamp 插入和查询都受当地时区的影响,更能反映出实际的日期。
      • 其属性受 MySQL 版本和服务器 SQLMODE 的影响很大,本章是以 MySQL5.0 为例,具体要参照想对应的 MySQL 帮助文档。
    • datetime

      • 只能反映出插入时当地的时区,其他时区的人查看数据必然会有误差的。

2.1.4 使用原则

  • 根据实际需要选择能够满足应用的最小存储的日期类型。如果应用只需要记录“年份”,那么用 1 个字节来存储的 year 类型完全可以满足,而不需要用 4 个字节来存储的 date 类型。这样不仅仅能节约存储,更能够提高表的操作效率。

  • 如果要记录年月日时分秒,并且记录的年份比较久远,那么最好使用 datetime,而不要使用 timestamp。因为 timestamp 表示的日期范围比 datetime 要短得多。
    如果记录的日期需要让不同时区的用户使用,那么最好使用 timestamp,因为日期类型中只有它能够和实际时区相对应。

2.1.5 示例

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    > create table t6(dt datetime);

    Query OK, 0 rows affected (0.03 sec)

    > insert into t6 values('2007-9-3 12:10:10');

    Query OK, 1 row affected (0.00 sec)

    > insert into t6 values('2007/9/3 12+10+10');

    Query OK, 1 row affected (0.00 sec)

    > insert into t6 values('20070903121010');

    Query OK, 1 row affected (0.01 sec)

    > insert into t6 values(20070903121010);

    Query OK, 1 row affected (0.00 sec)

    > select * from t6;

    +---------------------+
    | dt |
    +---------------------+
    | 2007-09-03 12:10:10 |
    | 2007-09-03 12:10:10 |
    | 2007-09-03 12:10:10 |
    | 2007-09-03 12:10:10 |
    +---------------------+
    4 rows in set (0.00 sec)

3、字符串类型

  • MySQL 包括了 char、varchar、binary、varbinary、blob、text、enum 和 set 等多种字符串类型。
字符串类型 字节 描述及存储要求
char(m) m 允许长度 0~255 个字节的定长字节字符串
varchar(m) 允许长度 0~65535 个字节的变长字节字符串,值的长度为 +1 字节
tinytext 允许长度 0~255 字节,值的长度为 +2 字节
text 允许长度 0~65535 字节,值的长度为 +2 字节
mediumtext 允许长度 0~167772150 字节,值的长度为 +3 字节
longtext 允许长度 0~4294967295 字节,值的长度为 +4 字节
binary(m) m 允许长度 0~m 个字节的定长字节字符串
varbinary(m) 允许长度 0~m 个字节的变长字节字符串,值的长度为 +1 字节
tinyblob 允许长度 0~255 字节,值的长度为 +1 字节
blob 允许长度 0~65535 字节,值的长度为 +2 字节
mediumblob 允许长度 0~167772150 字节,值的长度为 +3 字节
longblob 允许长度 0~4294967295 字节,值的长度为 +4 字节
enum 取值范围需要在创建表时指定,可以包含 0~65535 个成员
set 取值范围需要在创建表时指定,可以包含 0~64 个成员

3.1 char 和 varchar 类型

3.1.1 相同点

  • char 和 varchar 都用来保存 MySQL 中较短的字符串。

3.1.2 区别

chart(4) 存储需求 varchar(4) 存储需求
“” ‘ ‘ 4 个字节 ‘’ 1 个字节
‘ab’ ‘ab ‘ 4 个字节 ‘ab’ 3 个字节
‘abcd’ ‘abcd’ 4 个字节 ‘abcd’ 5 个字节
‘abcdefgh’ ‘abcd’ 4 个字节 ‘abcd’ 5 个字节
  • 存储方式的不同

    • char 列中的值为固定长度字符串,长度可以为从 0~255 的任何值;
    • varchar 列中的值为可变长度字符串,长度可以指定为 0~255(MySQL 5.0.3 版本以前)或者 65535(MySQL 5.0.3 版本以后)之间的值。
  • 在检索时的处理方式

    • char 删除了尾部的空格,
    • varchar 保留尾部的空格。
  • 最后一行的值只适用 MySQL 运行在非“严格模式”时,如果 MySQL 运行在严格模式,超过列长度的值将不会保存,并且会出现错误提示。

  • 由于 chart 是固定长度的,所以它的处理速度比 varchar 快得多,但是其缺点是浪费存储空间,程序需要对行尾空格进行处理,所以对于那些长度变化不大并且对查询速度有较高要求的数据可以考虑使用 chart 类型来存储。

  • 另外,随着 MySQL 版本的不断升级,varchar 数据类型的性能也在不断改进并提高,所以在许多的应用中,VARCHAR 类型被更多地使用。

3.1.3 不同的存储引擎对 chart 和 varchar 的使用原则

  • MyISAM 存储引擎:建议使用固定长度的数据列代替可变长度的数据列。

  • MEMORY 存储引擎:目前都使用固定长度的数据行存储,因此无论使用 chart 或 varchar 列都没有关系。两者都是作为 chart 类型处理。

  • InnoDB 存储引擎:建议使用 varchar 类型。对于 InnoDB 数据表,内部的行存储格式没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),因此在本质上,使用固定长度的 chart 列不一定比使用可变长度 varchar 列性能要好。因而,主要的性能因素是数据行使用的存储总量。由于 chart 平均占用的空间多于 varchar,因此使用 varchar 来最小化需要处理的数据行的存储总量和磁盘 I/O 是比较好的。

3.1.4 示例

  • 显然 char 列最后的空格在做操作时都已经被删除,而 varchar 依然保留空格。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    > create table vc ( v varchar(4), c char(4) );

    Query OK, 0 rows affected (0.06 sec)

    > insert into vc values ('ab ', 'ab ');

    Query OK, 1 row affected (0.06 sec)

    > select length(v),length(c) from vc;

    +-----------+-----------+
    | length(v) | length(c) |
    +-----------+-----------+
    | 4 | 2 |
    +-----------+-----------+
    1 row in set (0.00 sec)

    > SELECT concat(v, '+'), concat(c, '+') from vc;

    +----------------+----------------+
    | concat(v, '+') | concat(c, '+') |
    +----------------+----------------+
    | ab + | ab+ |
    +----------------+----------------+
    1 rows in set (0.00 sec)

3.2 binary 和 varbinary 类型

3.2.1 binary 和 varbinary

  • 类似于 char 和 varchar,不同的是它们包含二进制字符串而不包含非二进制字符串。

3.2.2 示例

  • 可以发现,当保存 binary 值时,在值的最后通过填充 “0x00”(零字节)以达到指定的字段定义长度。从上例中看出,对于一个 binary(3) 列,当插入时 “a” 变为 “a\0\0”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    > create table t ( c binary(3) );

    Query OK, 0 rows affected (0.03 sec)

    > insert into t set c = 'a';

    Query OK, 1 row affected (0.04 sec)

    > select *, hex(c), c = 'a', c = 'a\0', c = 'a\0\0' from t;

    +------+--------+---------+-----------+-------------+
    | c | hex(c) | c = 'a' | c = 'a\0' | c = 'a\0\0' |
    +------+--------+---------+-----------+-------------+
    | a | 610000 | 0 | 0 | 1 |
    +------+--------+---------+-----------+-------------+
    1 row in set (0.00 sec)

3.3 text 和 blob 类型

3.3.1 类型的选择

  • 一般在保存少量字符串的时候,我们会选择 char 或者 varchar;而在保存较大文本时,通常会选择使用 text 或者 blob。二者之间的主要差别是 blob 能用来保存二进制数据,比如照片;而 text 只能保存字符数据,比如一篇文章或者日记。

3.3.2 text 类型

  • MySQL 中,text 是一个字符串大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。text 类型实际是个类型系列(tinytext、text、mediumtext、longtext),除了在存储的最大信息量上不同外,他们是等同的。
类型 字节
tinytext 255B
text 65K
mediumtext 16M
longtext 4G

3.3.3 blob 类型

  • MySQL 中,blob 是一个二进制字符串大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。blob 类型实际是个类型系列(tinyblob、blob、mediumblob、longblob),除了在存储的最大信息量上不同外,他们是等同的。
类型 字节
tinyblob 255B
blob 65K
mediumblob 16M
longblob 4G

3.3.4 存在的问题

  • blob 和 text 值会引起一些性能问题,特别是在执行了大量的删除操作时

  • 删除操作会在数据表中留下很大的“空洞”,以后填入这些“空洞”的记录在插入的性能上会有影响。为了提高性能,建议定期使用 optimize table 功能对这类表进行碎片整理,避免因为“空洞”导致性能问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    > create table t (id varchar(100), context text);

    Query OK, 0 rows affected (0.04 sec)

    > insert into t values (1, repeat('haha', 100));

    Query OK, 1 row affected (0.01 sec)

    > insert into t values (2, repeat('haha', 100));

    Query OK, 1 row affected (0.01 sec)

    > insert into t values (3, repeat('haha', 100));

    Query OK, 1 row affected (0.01 sec)

    > insert into t select * from t;

    Query OK, 3 rows affected (0.07 sec)
    Records: 3 Duplicates: 0 Warnings: 0

    ...

    > insert into t select * from t;

    Query OK, 196608 rows affected (6.19 sec)
    Records: 196608 Duplicates: 0 Warnings: 0
  • 退出到操作系统下,查看表 t 的物理文件大小,这里数据文件显示为 155MB。

    1
    2
    3
    4
    $ du -sh t.*
    16K t.frm
    155Mt.MYD
    8.0Kt.MYI
  • 从表 t 中删除 id 为 “1” 的数据,这些数据占总数据量的 1/3。

    1
    2
    3
    > delete from t where id = 1;

    Query OK, 131072 rows affected (3.44 sec)
  • 再退出到操作系统下,查看表 t 的物理文件大小,可以发现,表t的数据文件仍然为155MB,并没有因为数据删除而减少。

    1
    2
    3
    4
    $ du -sh t.*
    16K t.frm
    155Mt.MYD
    8.0Kt.MYI
  • 接下来对表进行 optimize(优化)操作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # optimize table 表名;
    > optimize table t;

    +--------+----------+----------+----------+
    | Table | Op | Msg_type | Msg_text |
    +--------+----------+----------+----------+
    | test.t | optimize | status | OK |
    +--------+----------+----------+----------+
    1 row in set (2.88 sec)
  • 再次查看表 t 的物理文件大小,可以发现,表的数据文件大大缩小,“空洞”空间已经被回收。

    1
    2
    3
    4
    $ du -sh t.*
    16K t.frm
    104Mt.MYD
    8.0Kt.MYI

3.3.5 解决方法

  • 可以使用合成的(Synthetic)索引来提高大文本字段(blob 或 text)的查询性能

  • 简单来说,合成索引就是根据大文本字段的内容建立一个散列值,并把这个值存储在单独的数据列中,接下来就可以通过检索散列值找到数据行了。但是,要注意这种技术只能用于精确匹配的查询(散列值对于类似“<”或“>=”等范围搜索操作符是没有用处的)。可以使用 MD5() 函数生成散列值,也可以使用 SHA1() 或 CRC32(),或者使用自己的应用程序逻辑来计算散列值。请记住数值型散列值可以很高效率地存储。同样,如果散列算法生成的字符串带有尾部空格,就不要把它们存储在 char 或 varchar 列中,它们会受到尾部空格去除的影响。合成的散列索引对于那些 blob 或 text 数据列特别有用。用散列标识符值查找的速度比搜索 blob 列本身的速度快很多。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    > create table t (id varchar(100), context blob, hash_value varchar(40));

    Query OK, 0 rows affected (0.06 sec)

    > insert into t values (1, repeat('beijing', 2), md5(context));

    Query OK, 1 row affected (0.09 sec)

    > insert into t values (2, repeat('beijing', 2), md5(context));

    Query OK, 1 row affected (0.04 sec)

    > insert into t values (3, repeat('beijing 2008', 2), md5(context));

    Query OK, 1 row affected (0.08 sec)

    > select * from t;

    +------+--------------------------+----------------------------------+
    | id | context | hash_value |
    +------+--------------------------+----------------------------------+
    | 1 | beijingbeijing | 09746eef633dbbccb7997dfd795cff17 |
    | 2 | beijingbeijing | 09746eef633dbbccb7997dfd795cff17 |
    | 3 | beijing 2008beijing 2008 | 1c0ddb82cca9ed63e1cacbddd3f74082 |
    +------+--------------------------+----------------------------------+
    3 rows in set (0.00 sec)
  • 如果要查询 context 值为 “beijing 2008beijing 2008” 的记录,则可以通过相应的散列值来查询。

    1
    2
    3
    4
    5
    6
    7
    8
    > select * from t where hash_value = md5(repeat('beijing 2008', 2));

    +------+--------------------------+----------------------------------+
    | id | context | hash_value |
    +------+--------------------------+----------------------------------+
    | 3 | beijing 2008beijing 2008 | 1c0ddb82cca9ed63e1cacbddd3f74082 |
    +------+--------------------------+----------------------------------+
    1 row in set (0.01 sec)
  • 上面的例子展示了合成索引的用法,由于这种技术只能用于精确匹配,在一定程度上减少了 I/O,从而提高了查询效率。

  • 如果需要对 blob 或者 clob 字段进行模糊查询,MySQL 提供了前缀索引,也就是只为字段的前 n 列创建索引。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    > create index idx_blob on t(context(100));

    Query OK, 0 rows affected (0.02 sec)
    Records: 0 Duplicates: 0 Warnings: 0

    > desc select * from t where context like 'beijing%' \G;

    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: t
    partitions: NULL
    type: range
    possible_keys: idx_blob
    key: idx_blob
    key_len: 103
    ref: NULL
    rows: 3
    filtered: 100.00
    Extra: Using where
    1 row in set, 1 warning (0.00 sec)
  • 可以发现,对 context 前 100 个字符进行模糊查询,就可以用到前缀索引。注意,这里的查询条件中,“%” 不能放在最前面,否则索引将不会被使用。

3.3.6 在不必要的时候避免检索大型的 blob 或 text 值

  • 例如,SELECT * 查询就不是很好的想法,除非能够确定作为约束条件的 WHERE 子句只会找到所需要的数据行。否则,很可能毫无目的地在网络上传输大量的值。这也是 blob 或 text 标识符信息存储在合成的索引列中对用户有所帮助的例子。用户可以搜索索引列,决定需要的哪些数据行,然后从符合条件的数据行中检索 blob 或 text 值。

3.3.7 把 blob 或 text 列分离到单独的表中

  • 在某些环境中,如果把这些数据列移动到第二张数据表中,可以把原数据表中的数据列转换为固定长度的数据行格式,那么它就是有意义的。这会减少主表中的碎片,可以得到固定长度数据行的性能优势。它还可以使主数据表在运行 SELECT * 查询的时候不会通过网络传输大量的 blob 或 text 值。

3.4 enum 类型

3.4.1 取值范围

  • 是一个字符串对象,它的值范围需要在创建表时指定。

3.4.2 存储空间

  • enum 里面可以包含 0~65535 个成员。根据成员的不同,存储上也有所不同。
成员个数 字节
1~255 1
255~65535 2

3.4.3 示例

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    > create table t ( gender enum('M', 'F'));

    Query OK, 0 rows affected (0.06 sec)

    > insert into t values ('M'), ('1'), ('f'), (null);

    Query OK, 4 rows affected (0.06 sec)
    Records: 4 Duplicates: 0 Warnings: 0

    > select * from t;

    +--------+
    | gender |
    +--------+
    | M |
    | M |
    | F |
    | NULL |
    +--------+
    4 rows in set (0.00 sec)
  • 从上面的例子中,可以看出 enum 类型是忽略大小写的,在存储 “M”、“f” 时将它们都转成了大写.

  • 还可以看出对于插入不在 enum 指定范围内的值时,并没有返回警告,而是插入了 enum(‘M’,’F’) 的第一个值 “M”,这点用户在使用时要特别注意。
  • 另外,enum 类型只允许从值集合中选取单个值,而不能一次取多个值。

3.5 set 类型

3.5.1 取值范围

  • 是一个字符串对象,它的值范围需要在创建表时指定。

3.5.2 存储空间

  • set 里面可以包含 0~64 个成员。根据成员的不同,存储上也有所不同。
成员个数 字节
1~8 1
9~16 2
17~24 3
25~32 4
33~64 8

3.5.3 与 enum 的区别

  • 存储空间

    • set 和 enum 存储空间不同。
  • 选取成员个数

    • 最主要的区别在于 set 类型一次可以选取多个成员,而 enum 则只能选一个。
  • 插入值选取

    • set 类型可以从允许值集合中选择任意 1 个或多个元素进行组合。
    • enum 只允许从集合值中选取单个值,而不能一次取多个值。
  • 插入值超出范围处理方式

    • 对于超出定义的 set 允许值范围的值将不允许注入到设置的 set 类型列中,发出警告。
    • 对于(’a,d,a’)这样包含重复成员的集合将只取一次,写入后的结果为 “a,d”。
    • 对于超出定义的 enum 允许范围的值,并不返回警告,而是插入一个在 enum 指定值范围的第一个值。
    • enum 类型只允许从值集合中选取。

3.5.4 示例

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    > create table t (col set('a', 'b', 'c', 'd'));

    Query OK, 0 rows affected (0.11 sec)

    > insert into t values ('a,b'), ('a,d,a'), ('a,b'), ('a,c'), ('a');

    Query OK, 5 rows affected (0.02 sec)
    Records: 5 Duplicates: 0 Warnings: 0

    > select * from t;

    +------+
    | col |
    +------+
    | a,b |
    | a,d |
    | a,b |
    | a,c |
    | a |
    +------+
    5 rows in set (0.00 sec)
  • set 类型可以从允许值集合中选择任意 1 个或多个元素进行组合。

  • 对于输入的值只要是在允许值的组合范围内,都可以正确地注入到 set 类型的列中。
  • 对于超出允许值范围的值例如(’a,d,f ‘)将不允许注入到上面例子中设置的 set 类型列中。
  • 而对于(’a,d,a’)这样包含重复成员的集合将只取一次,写入后的结果为 “a,d”。
文章目录
  1. 1. 1、数值类型
    1. 1.1. 1.1 整数类型
      1. 1.1.1. 1.1.1 分类
      2. 1.1.2. 1.1.2 指定显示宽度
      3. 1.1.3. 1.1.3 属性
    2. 1.2. 1.2 小数类型
      1. 1.2.1. 1.2.1 分类
      2. 1.2.2. 1.2.2 指定显示宽度
      3. 1.2.3. 1.2.3 使用原则
      4. 1.2.4. 1.2.4 示例
    3. 1.3. 1.3 位类型
      1. 1.3.1. 1.3.1 用途
      2. 1.3.2. 1.3.2 查看位类型字段
      3. 1.3.3. 1.3.3 位类型字段插入操作
  2. 2. 2、日期时间类型
    1. 2.1. 2.1 日期时间类型
      1. 2.1.1. 2.1.1 分类
      2. 2.1.2. 2.1.2 零值
      3. 2.1.3. 2.1.3 timestamp 和 datetime 的区别
      4. 2.1.4. 2.1.4 使用原则
      5. 2.1.5. 2.1.5 示例
  3. 3. 3、字符串类型
    1. 3.1. 3.1 char 和 varchar 类型
      1. 3.1.1. 3.1.1 相同点
      2. 3.1.2. 3.1.2 区别
      3. 3.1.3. 3.1.3 不同的存储引擎对 chart 和 varchar 的使用原则
      4. 3.1.4. 3.1.4 示例
    2. 3.2. 3.2 binary 和 varbinary 类型
      1. 3.2.1. 3.2.1 binary 和 varbinary
      2. 3.2.2. 3.2.2 示例
    3. 3.3. 3.3 text 和 blob 类型
      1. 3.3.1. 3.3.1 类型的选择
      2. 3.3.2. 3.3.2 text 类型
      3. 3.3.3. 3.3.3 blob 类型
      4. 3.3.4. 3.3.4 存在的问题
      5. 3.3.5. 3.3.5 解决方法
      6. 3.3.6. 3.3.6 在不必要的时候避免检索大型的 blob 或 text 值
      7. 3.3.7. 3.3.7 把 blob 或 text 列分离到单独的表中
    4. 3.4. 3.4 enum 类型
      1. 3.4.1. 3.4.1 取值范围
      2. 3.4.2. 3.4.2 存储空间
      3. 3.4.3. 3.4.3 示例
    5. 3.5. 3.5 set 类型
      1. 3.5.1. 3.5.1 取值范围
      2. 3.5.2. 3.5.2 存储空间
      3. 3.5.3. 3.5.3 与 enum 的区别
      4. 3.5.4. 3.5.4 示例
隐藏目录