MySQL选择合适的数据类型

文章目录

  • 前言
  • 一、数值类型
    • 1.简述
    • 2.选择原则
  • 二、日期时间类型
    • 1.简述
    • 2.选择原则
  • 三、字符串类型
    • 1.简述
    • 2.选择原则
  • 总结


前言

本篇主要介绍MySQL常用的数据类型,并总结了在创建表时应该如何选择数据类型的一些原则。


一、数值类型

1.简述

所有的整数类型都有一个可选属性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模式下,会报错。

2.选择原则

点数和浮点数的四舍五入

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)

小结

  • 浮点数和定点数存在四舍五入;
  • 浮点数存在误差问题
  • 对货币等对精度敏感的数据,应采用定点数表示。

二、日期时间类型

1.简述

类型 字节 最小值 最大值 零值表示
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

2.选择原则

  • 根据需要选择满足应用的最小存储日期类型。如只需要记录年,则可以选择YEAR类型,不需要选择DATE类型。字节越少,节约存储,表的操作效率高
  • 日期存储如果跟时区有关,最好选择TIMESTAMP
  • 需要记录的年份比较久远,最好选择DATETIME。

三、字符串类型

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)

2.选择原则

  • InnoDB存储引擎下,建议使用VARCHAR类型
  • MyISAM存储引擎建议使用固定长度的数据列
  • BLOB和TEXT注意删除后的性能问题,可通过OPTIMIZE TABLE 命令进行整理
  • BLOB和TEXT,可通过建立前缀索引,为前n为建立索引,增加模糊查询。
  • 在不必要的时候避免检索BLOB和TEXT字段

总结

本文主要介绍了MySQL的常用数据类型,并总结了在创建表时选择数据类型的一些注意事项

你可能感兴趣的:(MySQL,mysql,数据库)