1)分类算法
按照取值范围和存储方式不一样,分为 tinyint、smallint、mediumint、int(即 integer)和 bigint 这 5 个类型,分别为 一、二、三、四、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] |
2)指定显示宽度编程
对于整型数据,MySQL 还支持在类型名称后加 "(m)" 的方式来指定显示宽度,"(m)" 表示该值一共显示 m 位数字,m 又称为精度,若是不显示指定宽度则默认为 int(11)。服务器
通常配合 zerofill 使用,即在数字位数不够的空间用字符 "0" 填满。网络
在设置了宽度限制后,若是插入值大于限制宽度,这时,宽度格式已经没有意义,仍是按照类型的实际精度(如:int 无符号的数值范围为0-255)进行保存,左边不会再填充任何的 "0" 字符。函数
3)属性性能
unsigned(无符号)优化
auto_increment操作系统
1)分类3d
分为浮点数和定点数。
浮点数通常用于表示含有小数部分的数值,包括 float(单精度)和 double(双精度)。
浮点数类型 | 字节 | 最小值(有符号 无符号) | 最大值(有符号 无符号) | 描述 |
---|---|---|---|---|
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] |
在 MySQL 中,decimal(或 numberic)用来表示定点数,定点数其实是以字符串形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。
定点数类型 | 字节 | 最小值(有符号 无符号) 最大值(有符号 无符号) | 描述 |
---|---|---|---|
dec(m, d)、decimal(m, d)、numeric(m, d) | m + 2 | 最大取值范围与 double 相同,给定 dec 的有效值范围由 m 和 d 决定 | dec[(m, d)] [unsigned] [zerofill] |
2)指定显示宽度
浮点数和定点数均可以用类型名称后加 "(m, d)" 的方式来进行表示,"(m, d)" 表示该值一共显示 m 位数字(整数位+小数位),其中 d 位位于小数点后面,m 和 d 又称为精度和标度。
当一个字段被定义为浮点类型后,若是插入数据的精度超过该列定义的实际精度,则插入值会被四舍五入到实际定义的精度值,而后插入,四舍五入的过程不会报错。
当一个字段被定义为定点数类型后,若是实际插入的数值精度大于实际定义的精度,则 MySQL 会进行警告(默认的 SQLMode 下),可是数据按照实际精度四舍五入后插入;若是 SQLMode 是在 traditional(传统模式)下,则系统会直接报错,致使数据没法插入。
3)使用原则
4)示例
> 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)
> 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)用途
bit(m)位类型用于存放位字段值,
bit(m) 能够用来存放多位二进制数,M范围从 1~64,若是不写则默认为 1 位。
2)查看位类型字段
对于位字段,直接使用 select 命令将不会看到结果,可使用 bin(列名)(显示为二进制格式)或者 hex(列名)(显示为十六进制格式)函数进行读取。
# 查看位类型字段值 > select bin(id), hex(id) from t2; +---------+---------+ | bin(id) | hex(id) | +---------+---------+ | 1 | 1 | +---------+---------+ 1 rows in set (0.00 sec)
3)位类型字段插入操做
数据插入 bit 类型字段时,首先转换为二进制,若是位数容许,将成功插入;若是位数小于实际定义的位数,则插入失败。
# 插入位类型字段值 > 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)
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 格式的字符串
year:YYYY
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 |
3)timestamp 和 datetime 的区别
时间取值范围不一样
时间属性的不一样
4)使用原则
根据实际须要选择可以知足应用的最小存储的日期类型。若是应用只须要记录“年份”,那么用 1 个字节来存储的 year 类型彻底能够知足,而不须要用 4 个字节来存储的 date 类型。这样不只仅能节约存储,更可以提升表的操做效率。
若是要记录年月日时分秒,而且记录的年份比较久远,那么最好使用 datetime,而不要使用 timestamp。由于 timestamp 表示的日期范围比 datetime 要短得多。
若是记录的日期须要让不一样时区的用户使用,那么最好使用 timestamp,由于日期类型中只有它可以和实际时区相对应。
5)示例
> 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)
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 个成员 |
1)相同点
2)区别
存储方式的不一样
在检索时的处理方式
最后一行的值只适用 MySQL 运行在非“严格模式”时,若是 MySQL 运行在严格模式,超过列长度的值将不会保存,而且会出现错误提示。
值 | chart(4) | 存储需求 | varchar(4) | 存储需求 |
---|---|---|---|---|
"" | ' ' | 4 个字节 | '' | 1 个字节 |
'ab' | 'ab ' | 4 个字节 | 'ab' | 3 个字节 |
'abcd' | 'abcd' | 4 个字节 | 'abcd' | 5 个字节 |
'abcdefgh' | 'abcd' | 4 个字节 | 'abcd' | 5 个字节 |
因为 chart 是固定长度的,因此它的处理速度比 varchar 快得多,可是其缺点是浪费存储空间,程序须要对行尾空格进行处理,因此对于那些长度变化不大而且对查询速度有较高要求的数据能够考虑使用 chart 类型来存储。
另外,随着 MySQL 版本的不断升级,varchar 数据类型的性能也在不断改进并提升,因此在许多的应用中,VARCHAR 类型被更多地使用。
3)不一样的存储引擎对 chart 和 varchar 的使用原则
MyISAM 存储引擎:建议使用固定长度的数据列代替可变长度的数据列。
MEMORY 存储引擎:目前都使用固定长度的数据行存储,所以不管使用 chart 或 varchar 列都没有关系。二者都是做为 chart 类型处理。
InnoDB 存储引擎:建议使用 varchar 类型。对于 InnoDB 数据表,内部的行存储格式没有区分固定长度和可变长度列(全部数据行都使用指向数据列值的头指针),所以在本质上,使用固定长度的 chart 列不必定比使用可变长度 varchar 列性能要好。于是,主要的性能因素是数据行使用的存储总量。因为 chart 平均占用的空间多于 varchar,所以使用 varchar 来最小化须要处理的数据行的存储总量和磁盘 I/O 是比较好的。
4)示例
> 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)
1)binary 和 varbinary 相似于 char 和 varchar,不一样的是它们包含二进制字符串而不包含非二进制字符串。
2)示例
> 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)
1)通常在保存少许字符串的时候,咱们会选择 char 或者 varchar;而在保存较大文本时,一般会选择使用 text 或者 blob。两者之间的主要差异是 blob 能用来保存二进制数据,好比照片;而 text 只能保存字符数据,好比一篇文章或者日记。
2)MySQL 中,text 是一个字符串大型对象,是一个能够存储大量数据的容器,它能容纳不一样大小的数据。text 类型实际是个类型系列(tinytext、text、mediumtext、longtext),除了在存储的最大信息量上不一样外,他们是等同的。
类型 | 字节 |
---|---|
tinytext | 255B |
text | 65K |
mediumtext | 16M |
longtext | 4G |
3)MySQL 中,blob 是一个二进制字符串大型对象,是一个能够存储大量数据的容器,它能容纳不一样大小的数据。blob 类型实际是个类型系列(tinyblob、blob、mediumblob、longblob),除了在存储的最大信息量上不一样外,他们是等同的。
类型 | 字节 |
---|---|
tinyblob | 255B |
blob | 65K |
mediumblob | 16M |
longblob | 4G |
4)blob 和 text 值会引发一些性能问题,特别是在执行了大量的删除操做时
删除操做会在数据表中留下很大的“空洞”,之后填入这些“空洞”的记录在插入的性能上会有影响。为了提升性能,建议按期使用 optimize table 功能对这类表进行碎片整理,避免由于“空洞”致使性能问题。
> 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。
$ du -sh t.* 16K t.frm 155Mt.MYD 8.0Kt.MYI
从表 t 中删除 id 为 “1” 的数据,这些数据占总数据量的 1/3。
> delete from t where id = 1; Query OK, 131072 rows affected (3.44 sec)
再退出到操做系统下,查看表 t 的物理文件大小,能够发现,表t的数据文件仍然为155MB,并无由于数据删除而减小。
$ du -sh t.* 16K t.frm 155Mt.MYD 8.0Kt.MYI
接下来对表进行 optimize(优化)操做。
# optimize table 表名; > optimize table t; +--------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------+----------+----------+----------+ | test.t | optimize | status | OK | +--------+----------+----------+----------+ 1 row in set (2.88 sec)
再次查看表 t 的物理文件大小,能够发现,表的数据文件大大缩小,“空洞”空间已经被回收。
$ du -sh t.* 16K t.frm 104Mt.MYD 8.0Kt.MYI
5)可使用合成的(Synthetic)索引来提升大文本字段(blob 或 text)的查询性能
简单来讲,合成索引就是根据大文本字段的内容创建一个散列值,并把这个值存储在单独的数据列中,接下来就能够经过检索散列值找到数据行了。可是,要注意这种技术只能用于精确匹配的查询(散列值对于相似“<”或“>=”等范围搜索操做符是没有用处的)。可使用 MD5() 函数生成散列值,也可使用 SHA1() 或 CRC32(),或者使用本身的应用程序逻辑来计算散列值。请记住数值型散列值能够很高效率地存储。一样,若是散列算法生成的字符串带有尾部空格,就不要把它们存储在 char 或 varchar 列中,它们会受到尾部空格去除的影响。合成的散列索引对于那些 blob 或 text 数据列特别有用。用散列标识符值查找的速度比搜索 blob 列自己的速度快不少。
> 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” 的记录,则能够经过相应的散列值来查询。
> 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 列建立索引。
> 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 个字符进行模糊查询,就能够用到前缀索引。注意,这里的查询条件中,“%” 不能放在最前面,不然索引将不会被使用。
6)在没必要要的时候避免检索大型的 blob 或 text 值
7)把 blob 或 text 列分离到单独的表中
1)取值范围
2)存储空间
enum 里面能够包含 0~65535 个成员。根据成员的不一样,存储上也有所不一样。
成员个数 | 字节 |
---|---|
1~255 | 1 |
255~65535 | 2 |
3)示例
> 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)
1)取值范围
2)存储空间
set 里面能够包含 0~64 个成员。根据成员的不一样,存储上也有所不一样。
成员个数 | 字节 |
---|---|
1~8 | 1 |
9~16 | 2 |
17~24 | 3 |
25~32 | 4 |
33~64 | 8 |
3)与 enum 的区别
存储空间
选取成员个数
插入值选取
插入值超出范围处理方式
4)示例
> 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)