本篇主要介绍MySQL常用的数据类型,并总结了在创建表时应该如何选择数据类型的一些原则。
所有的整数类型都有一个可选属性UNSIGNED(无符号),如果需要在字段里面保存非负数或者需要较大的上限值时,可以用此选项。它的取值方位是正常值是下限取0,上限是原来的上限的2倍
actor_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
整数类型
类型 | 字节 | 最小值 | 最大值 |
---|---|---|---|
TINYINT | 1 | 有符号 -128 无符号 0 |
有符号 127 无符号 255 |
SMALLINT | 2 | 有符号 -32768 无符号 0 |
有符号 32767 无符号 65535 |
MEDIUMINT | 3 | 有符号 -32768 无符号 0 |
有符号 32767 无符号 65535 |
INT | 4 | 有符号 -(2^31) 无符号 0 |
有符号 (2^31)-1 无符号 (2^32) |
BIGINT | 8 | 有符号 -(2^63) 无符号 0 |
有符号 (2^63)-1 无符号 (2^64) |
MySQL支持在证书类型后面的小括号内指定显示宽度。如int(5)表示当数值宽度小于5时在数字前面填满宽度,如果不指定宽度则默认为int(11)。一般配合zerofill使用,意思是使用0进行填充。
mysql> create table int_test(id1 int,id2 int(5));
Query OK, 0 rows affected (0.03 sec)
mysql> desc int_test;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id1 | int(11) | YES | | NULL | |
| id2 | int(5) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
-- 加入zerofill参数
mysql> alter table int_test modify id1 int zerofill;
Query OK, 1 row affected (0.05 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> alter table int_test modify id2 int(5) zerofill;
Query OK, 1 row affected (0.06 sec)
Records: 1 Duplicates: 0 Warnings: 0
-- int 有unsigned 位数变为10
mysql> desc int_test;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| id1 | int(10) unsigned zerofill | YES | | NULL | |
| id2 | int(5) unsigned zerofill | YES | | NULL | |
+-------+---------------------------+------+-----+---------+-------+
mysql> select * from int_test;
+------------+-------+
| id1 | id2 |
+------------+-------+
| 0000000001 | 00001 |
+------------+-------+
1 row in set (0.00 sec)
浮点数类型
类型 | 字节 | 最小值 | 最大值 |
---|---|---|---|
FLOAT | 4 | +/-1.175494351E-38 | +/-3.402823466E+38 |
DOUBLE | 8 | +/-2.2250738585072014E-308 | +/-1.7976931348623157E+308 |
定点数类型
类型 | 字节 | 描述 |
---|---|---|
DEC(M.D) DECIMAL(M,D) |
M+2 | 最大取值范围与DOUBLE相同,有效的取值范围由M和D决定 |
浮点数和定点数都可以用类型名称后加“(M,D)”的方式进行表示,“(M,D)”表示该值一共显示M位数字(整数为+小数位),其中D为位于小数点后面,M和D又称为精度和标度。
定点数在MySQL内部以字符串形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。
float和double在不指定精度时,默认会按照实际的精度(由实际的硬件和操作系统决定)。如果有了精度和标度,则会自动将四舍五入后的结果插入,系统不会报错。
decimal如果不写精度和标度,按照默认值decimal(10,0)来进行操作,如果数值超越了精度和标度值,在默认SQLModel下,数据按照四舍五入后插入,在TRADITIONAL模式下,会报错。
点数和浮点数的四舍五入
mysql> create table t(f float(8,1),d decimal(8,1));
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t values(1.23456,1.23456);
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> insert into t values(1.25456,1.25456);
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from t;
+------+------+
| f | d |
+------+------+
| 1.2 | 1.2 |
| 1.3 | 1.3 |
+------+------+
定点数和浮点数区别
mysql> create table test(f float(10,2),d decimal(10,2));
Query OK, 0 rows affected (0.03 sec)
mysql> desc test;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| f | float(10,2) | YES | | NULL | |
| d | decimal(10,2) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
mysql> insert into test values(131072.32,131072.32);
Query OK, 1 row affected (0.01 sec)
-- 精度丢失
mysql> select * from test;
+-----------+-----------+
| f | d |
+-----------+-----------+
| 131072.31 | 131072.32 |
+-----------+-----------+
1 row in set (0.00 sec)
小结
类型 | 字节 | 最小值 | 最大值 | 零值表示 |
---|---|---|---|---|
DATE | 4 | 1000-01-01 | 9999-12-31 | 0000-00-00 |
DATETIME | 8 | 1000-01-01 00:00:00 | 9999-12-31 23:59:59 | 0000-00-00 00:00:00 |
TIMESTAMP | 4 | 19700101080001 | 2038年某个时刻 | 00000000000000 |
TIME | 3 | -838:59:59 | 838:59:59 | 00:00:00 |
YEAR | 1 | 1901 | 2155 | 000 |
mysql> desc time_test;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| d | date | YES | | NULL | |
| t | time | YES | | NULL | |
| dt | datetime | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into time_test values(now(),now(),now());
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select * from time_test;
+------------+----------+---------------------+
| d | t | dt |
+------------+----------+---------------------+
| 2021-02-15 | 02:45:49 | 2021-02-15 02:45:49 |
+------------+----------+---------------------+
TIMESTAMP演示
mysql> create table t_stamp(id timestamp);
Query OK, 0 rows affected (0.04 sec)
mysql> desc t_stamp;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
mysql> select * from t_stamp;
Empty set (0.00 sec)
mysql> insert into t_stamp values(null);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t_stamp;
+---------------------+
| id |
+---------------------+
| 2021-02-15 06:03:46 |
+---------------------+
1 row in set (0.01 sec)
上面可以看到,系统自动创建了默认值,插入了系统日期。
mysql> alter table t_stamp add column id2 timestamp;
ERROR 1067 (42000): Invalid default value for 'id2'
MySQL规定TIMESTAMP类型字段只能有一列的默认值为CURRENT_TIMESTAMP 。
TIMESTAMP还有一个重要特点,就是和时区相关。当插入日期时,会先转换为本地时区后存储,而从数据库中取出时也同样需要将日期转换成本地时区后显示。
mysql> desc t8;
+-------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-------+
| id1 | timestamp | NO | | CURRENT_TIMESTAMP | |
| id2 | datetime | YES | | NULL | |
+-------+-----------+------+-----+-------------------+-------+
2 rows in set (0.01 sec)
-- 查看当前时区
mysql> show variables like 'time_zone';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| time_zone | SYSTEM |
+---------------+--------+
1 row in set (0.01 sec)
-- 修改时区
mysql> set time_zone='+8:00';
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t8;
+---------------------+---------------------+
| id1 | id2 |
+---------------------+---------------------+
| 2021-02-15 22:13:17 | 2021-02-15 06:13:17 |
+---------------------+---------------------+
mysql> set time_zone='+9:00';
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t8;
+---------------------+---------------------+
| id1 | id2 |
+---------------------+---------------------+
| 2021-02-15 23:13:17 | 2021-02-15 06:13:17 |
+---------------------+---------------------+
TIMESTAMP的取值范围是1970-01-01 08:00:01到2038年某一天(东八区)。超过该范围时插入异常。
mysql> insert into t8(id1) values('1970-01-01 08:00:01');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t8(id1) values('1970-01-01 08:00:00');
ERROR 1292 (22007): Incorrect datetime value: '1970-01-01 08:00:00' for column 'id1' at row 1
MySQL包含有多种字符串类型,如CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET等。下面介绍常用的CHAR、VARCHA、BLOB、TEXT。
类型 | 字节 | 描述 |
---|---|---|
CHAR(M) | M | M为0~255之间的整数 |
VARCHAR(M) | M为0~65535之间的整数,值的长度+1个字节 | |
BLOB | 允许长度0~65535字节,值的长度+2个字节 | |
TEXT | 允许长度0~65535字节,值的长度+2个字节 |
CHAR列的长度固定为创建表时声明的长度,而VARCHAR的长度为可变长度。在检索时,CHAR列删除了尾部空格,VARCHAR则保留了空格。
值 | CHAR(4) | 存储需求 | VRACHAR(4) | 存储需求 |
---|---|---|---|---|
‘’ | ‘’ | 4个字节 | ‘’ | 1个字节 |
‘ab’ | 'ab ’ | 4个字节 | ‘ab’ | 3个字节 |
‘abcd’ | ‘abcd’ | 4个字节 | ‘abcd’ | 5个字节 |
mysql> create table vc(v VARCHAR(4),c CHAR(4));
Query OK, 0 rows affected (0.03 sec)
-- 插入具有空格的字符串
mysql> INSERT INTO vc VALUES('ab ','ab ');
Query OK, 1 row affected (0.00 sec)
-- char将尾部空格删除
mysql> select length(v),length(c) from vc;
+-----------+-----------+
| length(v) | length(c) |
+-----------+-----------+
| 4 | 2 |
+-----------+-----------+
BLOB能用来保存二进制数据,比如照片,而TEXT只能保存字符串数据,比如一篇文章或数据。
BLOB和TEXT值会引起一些性能问题,特别是执行大量操作后。
可以使用合成的索引来提高大文本字段(BLOB和TEXT)的查询性能。简单来说就是根据大文本字段的内容建立一个散列值,并把这个值存在单独的数据列中,查找时通过散列值进行查找,不过这样处理后只能使用精确查找。
mysql> create table blob_test(id varchar(100),context blob,hash_value varchar(40));
Query OK, 0 rows affected (0.03 sec)
-- 通过repeat函数重复创建
mysql> insert into blob_test values(1,repeat('helloworld',2),md5(context));
Query OK, 1 row affected (0.00 sec)
mysql> insert into blob_test values(2,repeat('helloworld',2),md5(context));
Query OK, 1 row affected (0.01 sec)
mysql> insert into blob_test values(3,repeat('sayhelloworld',2),md5(context));
Query OK, 1 row affected (0.01 sec)
mysql> select * from blob_test;
+------+----------------------------+----------------------------------+
| id | context | hash_value |
+------+----------------------------+----------------------------------+
| 1 | helloworldhelloworld | 8be363cf63c20050aaad7dbe737acd73 |
| 2 | helloworldhelloworld | 8be363cf63c20050aaad7dbe737acd73 |
| 3 | sayhelloworldsayhelloworld | ae47ee207fdec31e2ba91c229f5963b7 |
+------+----------------------------+----------------------------------+
-- 下面通过hash_value列查找'sayhelloworld'列
mysql> select * from blob_test where hash_value=md5(repeat('sayhelloworld',2));
+------+----------------------------+----------------------------------+
| id | context | hash_value |
+------+----------------------------+----------------------------------+
| 3 | sayhelloworldsayhelloworld | ae47ee207fdec31e2ba91c229f5963b7 |
+------+----------------------------+----------------------------------+
可通过对BLOB或者TEXT字段建立前缀索引,对该字段进行模糊查询
mysql> create index idx_blob on blob_test(context(100));
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc select * from blob_test where context like 'hello%'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: blob_test
partitions: NULL
type: range
possible_keys: idx_blob
key: idx_blob -- 使用了索引
key_len: 103
ref: NULL
rows: 2
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.01 sec)
本文主要介绍了MySQL的常用数据类型,并总结了在创建表时选择数据类型的一些注意事项