本章将对MySQL的存储引擎和数据类型的使用进行详细的讲解。
存储引擎其实就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。因为在关系数据库中数据是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。在Oracle和SQL Server等数据库中只有一种存储引擎,所有数据存储管理机制都是一样的;而MySQL数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据需要编写自己的存储引擎。
引擎名称 | 事务 | 说明 |
---|---|---|
MYISAM | N | MySQL5.6之前的默认引擎,最常用的非事务型存储引擎 |
CSV | N | 以CSV格式存储的非事务性存储引擎,常用于数据交换 |
Archive | N | 只允许查询和新增数据而不允许修改的非事务性存储引擎,用于归档和日志存储 |
Memory | N | 是一种易失性非事务性存储引擎 |
InnoDB | Y | 最常用的事务性存储引擎 |
MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的、不同的功能和能力。通过选择不同的技术,能够获得额外的速度或者功能,从而改善应用的整体功能。
这些不同的技术以及配套的相关功能在MySQL中被称作存储引擎(也称作表类型)。MySQL默认配置了许多不同的存储引擎,可以预先设置或者在MySQL服务器中启用。可以选择适用于服务器、数据库和表格的存储引擎,以便在选择如何存储信息、如何检索这些信息以及需要的数据结合什么性能和功能的时候为其提供最大的灵活性。
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
mysql>
SHOW ENGINES语句可以用“;”结束,也可以用“\g”或者“\G”结束。“\g”与“;”的作用是相同的,“\G”可以让结果显示得更加美观。
mysql> show variables like '%storage_engine%';
+----------------------------------+--------+
| Variable_name | Value |
+----------------------------------+--------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | InnoDB |
| disabled_storage_engines | |
| internal_tmp_disk_storage_engine | InnoDB |
+----------------------------------+--------+
4 rows in set (0.00 sec)
在创建表的时候,可以通过增加ENGIN关键字设置新表的存储引擎:
CREATE TABLE `tb_admin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user` varchar(30) NOT NULL,
`password` varchar(30) NOT NULL,
`age` int(3) DEFAULT NULL,
`createtime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
也可以使用alter语句进行修改:
alter table tb_admin engine = MyISAM;
每种存储引擎都有各自的优势,不能笼统地说谁比谁更好,只有适合不适合。下面将重点介绍几种常用的存储引擎。
特点 | MyISAM | InnoDB | MEMORY | MERGE | NDB |
---|---|---|---|---|---|
存储限制 | 有 | 64TB | 有 | 没有 | 有 |
事务安全 | 不支持 | 支持 | 不支持 | 不支持 | 不支持 |
锁机制 | 表锁 | 行锁 | 表锁 | 表锁 | 行锁 |
B树索引 | 支持 | 支持 | 支持 | 支持 | 支持 |
哈希索引 | 不支持 | 不支持 | 支持 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
集群索引 | 不支持 | 支持 | 不支持 | 不支持 | 不支持 |
数据索引 | 不支持 | 支持 | 支持 | 不支持 | 支持 |
索引缓存 | 支持 | 支持 | 支持 | 支持 | 支持 |
数据可压缩 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
空间使用 | 低 | 高 | N/A | 低 | 低 |
内存使用 | 低 | 高 | 中等 | 低 | 高 |
批量插入的速度 | 高 | 低 | 高 | 高 | 高 |
支持外键 | 不支持 | 支持 | 不支持 | 不支持 | 不支持 |
下面根据其不同的特性,给出选择存储引擎的建议。
在MySQL数据库中,每一条数据都有其数据类型。MySQL支持的数据类型主要分成3类:数字类型、字符串(字符)类型、日期和时间类型。
MySQL支持所有的ANSI/ISO SQL 92数字类型。这些类型包括准确数字的数据类型(NUMERIC、DECIMAL、INTEGER和SMALLINT),还包括近似数字的数据类型(FLOAT、REAL和DOUBLE PRECISION)。其中的关键词INT是INTEGER的同义词,关键词DEC是DECIMAL的同义词。
在创建表时,使用哪种数字类型,应遵循以下原则。
数字类型总体可以分成整型和浮点型两类:
数据类型 | 取值范围 | 说明 | 单位 |
---|---|---|---|
TINYNT | 符号值:-127~127 无符号值: 0~255 | 最小的整数 | 1字节 |
BOOL | 符号值:-127~127 无符号值: 0~255 | 最小的整数 | 1字节 |
SMALLINT | 符号值:-32768~32767 无符号值: 0~65535 | 小型整数 | 2字节 |
MEDIUMINT | 符号值:-8388608~8388607 无符号值: 0~16777215 | 中型整数 | 3字节 |
INT,INTEGER | 符号值:-2147683648~2147683647 无符号值: 0~4294967295 | 标准整数 | 4字节 |
BIGINT | 符号值:-9223372036854775808~9223372036854775807 无符号值: 0~18446744073709551615 | 大整数 | 8字节 |
对于整数类型,MySQL还支持在类型名称后面的小括号内指定显示宽度,例如:int(5)表示当数据宽度小于5位的时候在数字前面填满宽度,如果不显示指定宽度则默认为int(11)。一般配合zerofill使用,即用“0”填充的意思。
zerofill
用法mysql> create table t1(id1 int,id2 int(5));
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t1 values(1,1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
+------+------+
| id1 | id2 |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
mysql> alter table t1 modify id1 int zerofill;
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> alter table t1 modify id2 int(5) zerofill;
Query OK, 1 row affected (0.06 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+------------+-------+
| id1 | id2 |
+------------+-------+
| 0000000001 | 00001 |
+------------+-------+
1 row in set (0.00 sec)
mysql>
mysql> insert into t1 values(2,2222222);
Query OK, 1 row affected (0.02 sec)
mysql> select * from t1;
+------------+---------+
| id1 | id2 |
+------------+---------+
| 0000000001 | 00001 |
| 0000000002 | 2222222 |
+------------+---------+
2 rows in set (0.00 sec)
mysql>
所有的整数类型都有一个可选属性UNSIGNED(无符号),如果需要在字段里面报错非负数或者需要较大的上限值时,可以使用此选项,它的取值范围是正常值的下限取0,上限取原值的2倍。
例如,tinyint有符号范围是-128+127,而无符号范围是0255。如果一个列指定为zerofill,则MySQL自动为该列添加UNSIGNED属性。
mysql> desc t1;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| id1 | int(10) unsigned zerofill | YES | | NULL | |
| id2 | int(5) unsigned zerofill | YES | | NULL | |
+-------+---------------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> alter table t1 add id3 int(7) unsigned;
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc t1;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| id1 | int(10) unsigned zerofill | YES | | NULL | |
| id2 | int(5) unsigned zerofill | YES | | NULL | |
| id3 | int(7) unsigned | YES | | NULL | |
+-------+---------------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql>
整数类型还有一个属性AUTO_INCREMENT。在需要产生唯一标识符或顺序值时,可以利用此属性。此属性只能用于整型类型。
create table a1(id int auto_increment not null,primary key);
create table a1(id int auto_increment not null,primary key(id));
create table a1(id int auto_increment not null,unique(id);
数据类型 | 取值范围 | 说明 | 单位 |
---|---|---|---|
FLOAT | +(-)3.402823466E+38 | 单精度浮点数 | 8或4字节 |
DOUBLE | +(-)1.7976931348623157E+308 +(-)2.2250738585072014E+308 |
双精度浮点数 | 8字节 |
DEC(M,D) DECIMAL(M,D) |
最大取值范围与DOUBLE相同,给定DECIMAL的有效取值范围由M和D决定 | 一般整数 | M+2 |
对于小数的表示,MySQL分为两种方式:浮点数和定点数。浮点数包括float(单精度)和double(双精度),而定点数则只有decimal一种表示。定点数在MySQL内部以字符串形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。
浮点数和定点数都可以用类型名称后加(M,D)
的方式来表示,表示该值一共显示M位数字(整数位+小数位),其中D位位于小数点后面,M和D又称为精度和标度。
例如:定义为float(7,4)的一个列表可以显示为-999.9999
。MySQL保存值时进行四舍五入,因此如果在float(7,4)列内插入999.00009,近似结果是999.0001。
值得注意的是,浮点数后面跟(M,D)
的用法是非标准用法,如果要用于数据库的迁移,则最好不要这么使用。float和double在不指定精时,默认会按照实际的精度(由实际的硬件和操作系统决定)来显示,而decimal在不指定精度时,默认的整数位为10,默认的小数位为0。
用法建议:
数据类型 | 取值范围 | 说明 | 单位 |
---|---|---|---|
BIT(M) | 符号值:-127~127 无符号值: 0~255 BIT(1)~BIT(64) | 最小的整数 | 1字节~8字节 |
对于BIT(位)类型,用于存放位字段值,BIT(M)可以用来存放多位二进制数,M范围从1~64,如果不写则默认为1位。对于位字段,直接使用SELECT命令将不会看到结果,可以使用bin()
(显示为二进制格式)或者hex()
(显示为十六进制格式)函数进行读取。
mysql> create table t2 (id bit(8));
Query OK, 0 rows affected (0.03 sec)
mysql> desc t2;
+-------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| id | bit(8) | YES | | NULL | |
+-------+--------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> insert into t2 values(128);
Query OK, 1 row affected (0.02 sec)
mysql> select * from t2;
+------+
| id |
+------+
| � |
+------+
1 row in set (0.00 sec)
mysql> select bin(id) from t2;
+----------+
| bin(id) |
+----------+
| 10000000 |
+----------+
1 row in set (0.01 sec)
mysql>
如果存储的数据超过限制,则插入数据会提示报错。如,id为bit(8),8位的int最大为255,写入256会提示错误。
mysql> insert into t2 value(256);
ERROR 1406 (22001): Data too long for column 'id' at row 1
mysql>
mysql> insert into t2 value(255);
Query OK, 1 row affected (0.02 sec)
mysql> alter table t2 modify id bit(16);
Query OK, 2 rows affected (0.06 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into t2 value(256);
Query OK, 1 row affected (0.02 sec)
mysql>
字符串类型可以分为3类:普通的文本字符串类型(CHAR和VARCHAR)、可变类型(TEXT和BLOB)和特殊类型(SET和ENUM)。
创建表时,使用字符串类型时应遵循以下原则。
即CHAR和VARCHAR类型,CHAR列的长度被固定为创建表所声明的长度,取值在1~255之间;VARCHAR列的值是变长的字符串,取值和CHAR一样
类型 | 取值范围 | 说明 |
---|---|---|
[national]char(M)[binary|ASCII|unicode] | 0~255个字符 | 固定长度为M的字符串,其中M的取值范围为0~255。national关键字指定了应该使用的默认字符集。binary关键字指定了数据是否区分大消息(默认是区分大小写的)ASCII关键字指定了在该列中使用latin1字符集。unicode关键字指定了使用UCS字符集 |
char | 0~255个字符 | char(M)类似 |
[national]varchar(M)[binary] | 0~255 个字符(5.0.3之前)0~65535 个字符(5.0.3以后) |
M为0~65535之间的整数,值的长度+1个字节。其他和char(M)类似 |
create table vc (
v varchar(4),
c char(4)
);
mysql> insert into vc values('ab ','ab ');
Query OK, 1 row affected (0.01 sec)
mysql> select length(v),length(c) from vc;
+-----------+-----------+
| length(v) | length(c) |
+-----------+-----------+
| 4 | 2 |
+-----------+-----------+
1 row in set (0.01 sec)
# 给两个字段分别追加一个“+”字符看得更清楚
mysql>
mysql> select concat(v,'+'),concat(c,'+') from vc;
+---------------+---------------+
| concat(v,'+') | concat(c,'+') |
+---------------+---------------+
| ab + | ab+ |
+---------------+---------------+
1 row in set (0.01 sec)
mysql>
存储引擎 | 使用建议 |
---|---|
MyISAM存储引擎 | 建议使用固定长度的数据列替代可变长度的数据列 |
MEMORY存储引擎 | 目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系,两者都作为CHAR类型处理 |
InnoDB存储引擎 | 建议使用VARCHAR类型。对于InnoDB数据表,内部的行存储格式没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),因此本质上,使用固定长度的CHAR列不一定笔记使用可变长度VARCHAR列性能要好。因此,主要的性能呢因素是数据行使用的存储总量。由于CHAR平均占用的空间多于VARCHAR,因此使用VARCHAR俩最小化需要处理的数据行的存储总量和磁盘I/O是比较好的 |
TEXT和BLOB,它们的大小可以改变,TEXT类型适合存储长文本,而BLOB类型适合存储二进制数据,支持任何数据,如文本、声音和图像等。
类型 | 最大长度(字节数) | 说明 |
---|---|---|
TINYBLOB | 2^8-1(255) | 小BLOB字段,允许长度0~255字节,值的长度+1个字节 |
BLOB | 2^16-1(65535) | 常规BLOB字段,允许长度0~65535字节,值的长度+2个字节 |
MEDIUMBLOB | 2^24-1(16777215) | 中型BLOB字段,允许长度0~167772150字节,值的长度+3个字节 |
LONGBLOB | 2^32-1(4294967295) | 长BLOB字段,允许长度0~4294967295字节,值的长度+4个字节 |
TINYTEXT | 2^8-1(255) | 小TEXT字段,允许长度0~255字节,值的长度+2个字节 |
TEXT | 2^16-1(65535) | 常规TEXT字段,允许长度0~65535字节,值的长度+2个字节 |
MEDIUMTET | 2^24-1(16777215) | 中型TEXT字段,允许长度0~167772150字节,值的长度+3个字节 |
LONGTEXT | 2^32-1(4294967295) | 长TEXT字段,允许长度0~4294967295字节,值的长度+4个字节 |
VARBINARY(M) | M | 允许长度0~M个字节的变长字节字符串,值的长度+1个字节 |
BINARY(M) | M | 允许长度0~M个字节的定长字节字符串 |
BINARY和VARBINARY类似于CHAR和VARCHAR,不同的是它们包含二进制字符串而不包含非二进制字符串。
mysql> create table t (c binary(3));
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t set c = 'a';
Query OK, 1 row affected (0.00 sec)
# 分别用以下几种模式来查看c列内容
mysql> 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)
mysql>
当保存BINARY值时,在值的最后通过填充“0x00”(零字节)以达到指定的字段定义长度。
在保存较大文本时,通常会选择使用TEXT或BLOB。二者之间主要差别是BLOB能用来保存二进制数据,比如照片;而TEXT只能保存字符数据,比如一瓶文章。
OPTIMIZE TABLE
功能对这类表进行碎片整理。SET和ENUM
类型 | 最大值 | 说明 |
---|---|---|
Enum(“value1”,“value2”,…) | 65535 | 该类型的列只可以容纳所列值之一或为NULL |
Set(“value1”,“value2”,…) | 64 | 该类型的列可以容纳一组值或为NULL |
ENUM,即枚举类型,它的值范围需要在创建表时通过枚举方式显示指定,对1255个成员的枚举需要1个字节存储;对于25565535个成员,需要2个字节存储。最多允许有65535个成员。
mysql> create table t11 (gender enum('M','F'));
Query OK, 0 rows affected (0.04 sec)
# 插入4条不同的记录
mysql> insert into t11 values('M'),('1'),('f'),(NULL);
Query OK, 4 rows affected (0.01 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from t11;
+--------+
| gender |
+--------+
| M |
| M |
| F |
| NULL |
+--------+
4 rows in set (0.00 sec)
mysql>
SET和ENUM类型非常相似,也是一个字符串对象,里面可以包含0~64个成员。根据成员的不同,存储上也各不相同:
SET与ENUM除了存储外,最大的区别在于SET类型一次可以选取多个成员。
mysql> create table t22 (col set('a','b','c','d'));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t22 values('a,b'),('a,d,a'),('a,b'),('a,c'),('a,f');
ERROR 1265 (01000): Data truncated for column 'col' at row 5
mysql>
mysql> insert into t22 values('a,b'),('a,d,a'),('a,b'),('a,c');
Query OK, 4 rows affected (0.01 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from t22
-> ;
+------+
| col |
+------+
| a,b |
| a,d |
| a,b |
| a,c |
+------+
4 rows in set (0.00 sec)
mysql>
a,f
,f不在值集中。a,d,a
,a出现了2次,只会保存一个。日期和时间类型包括:DATETIME、DATE、TIMESTAMP、TIME和YEAR。其中的每种类型都有其取值的范围,如赋予它一个不合法的值,将会被“0”代替。
类型 | 占用控件 | 取值范围 | 说明 | 零值表示 |
---|---|---|---|---|
DATE | 4字节(bytes) | 1000-01-01 9999-12-31 | 日期,格式YYYY-MM-DD | 0000-00-00 |
TIME | 3字节 | -838:58:59 835:59:59 | 时间值或持续时间,格式HH:MM:SS | 00:00:00 |
DATETIME | 8字节 | 1000-01-01 00:00:00 9999-12-31 23:59:59 |
混合日期和时间值,格式YYYY-MM-DD HH:MM:SS | 0000-00-00 00:00:00 |
TIMESTAMP | 4字节 | UTC’1970-01-01 00:00:00’/2038结束时间是第2147483647秒,北京时间2038-1-19 11:14:07,格林尼治时间2038年1月19日凌晨03:14:07 | 混合日期和时间值,时间戳 | 00000000000000 |
YEAR | 1字节 | 1901~2155 | 年份可指定两位数和四位数的格式,格式YYYY | 0000 |
每种日期时间类型都有一个有效值范围,如果超出这个范围,在默认的SQLMode下会报错,并以零值(见上表)存储。
插入或更新时,日期时间类型允许“不严格”语法,以DATETIME为例(其他日期时间类型雷同):
YYYY-MM-DD HH:MM:SS
或YY-MM-DD HH:MM:SS
格式的字符串。任何符号都可以用作日期部分或时间部分的间隔符。
例如:14-06-18 14:54:10
、14*06*18 14.54.10
、14+06+18 14=54=10
是等价的。对于包含日期时间的字符串值,如果月、日、时、分、秒的值小于10,不需要指定两位数。
例如:2014-2-3 2:3:6
、2014-02-03 02:03:06
是等价的。
YYYYMMDDHHMMSS
或YYMMDDHHMMSS
格式的字符串。如果字符串对于日期时间类型是合法的就可以解释为日期时间类型。
例如:20140618145410
和 140618145410
将被解释为2014-06-18 14:54:10
,但是 20140618145480
是不合法的(秒数不合法),将被解释为0000-00-00 00:00:00
。
YYYYMMDDHHMMSS
或YYMMDDHHMMSS
格式的数字。如果该数字对日期时间类型是合法的就可以解释为日期时间类型。
例如:20140618145410
和140618145410
将被解释为2014-06-18 14:54:10
。数值的长度应为6、8、12、14。如果数值长度是8或14位长,则假定为YYYYMMDD
或YYYYMMDDHHMMSS
格式。如果数值为6或12位长,则假定为YYMMDD
或YYMMDDHHMMSS
格式。
DATETIME
用于表示年月日时分秒
,是DATE
和TIME
的组合,并且记录的年份(见上表)比较长久。如果实际应用中有这样的需求,就可以使用DATETIME
类型。
DATETIME
是从1000-01-01 00:00:00
到9999-12-31 23:59:59
的时间。
TIMESTAMP
用于表示 年月日 时分秒,但是记录的年份(见上表)比较短暂。
TIMESTAMP
和时区相关,更能反映当前时间。当插入日期时,会先转换为本地时区后再存放;当查询日期时,会将日期转换为本地时区后再显示。所以不同时区的人看到的同一时间是不一样的。
表中的第一个TIMESTAMP
列自动设置为系统时间CURRENT_TIMESTAMP
。当插入或更新一行,但没有明确给TIMESTAMP列赋值,也会自动设置为当前系统时间。如果表中有第二个TIMESTAMP列,则默认值设置为0000-00-00 00:00:00
,而且不能强制修改默认值为CURRENT_TIMESTAMP
。
TIMESTAMP的属性受Mysql版本和服务器SQLMode的影响较大。如果记录的日期需要让不同时区的人使用,最好使用TIMESTAMP。
如果需要经常插入或者更新日期为当前系统时间,则通常使用TIMESTAMP
来表示。TIMESTAMP
值返回后显示为YYYY-MM-DD HH:MM:SS
格式的字符串,显示宽度为19字符。如果想要获得数字值,应在TIMESTAMP
列添加+0
。
create table t3 (
id1 timestamp not null default current_timestamp,
id2 datetime default null
)
mysql> show variables like 'time_zone';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| time_zone | SYSTEM |
+---------------+--------+
1 row in set (0.00 sec)
mysql>
时区值为SYSTEM
,表示与主机的时区值一致,即东八区。
mysql> insert into t3 values(now(),null);
mysql> select * from t3;
+---------------------+------+
| id1 | id2 |
+---------------------+------+
| 2022-07-07 10:42:22 | NULL |
+---------------------+------+
1 row in set (0.00 sec)
mysql>
mysql> set time_zone='+9:00';
Query OK, 0 rows affected (0.01 sec)
mysql> select * from t3;
+---------------------+------+
| id1 | id2 |
+---------------------+------+
| 2022-07-07 11:42:22 | NULL |
+---------------------+------+
1 row in set (0.00 sec)
mysql>
mysql> set time_zone='SYSTEM';
Query OK, 0 rows affected (0.01 sec)
mysql> select * from t3;
+---------------------+------+
| id1 | id2 |
+---------------------+------+
| 2022-07-07 10:42:22 | NULL |
+---------------------+------+
1 row in set (0.00 sec)
mysql>
TIMESTAMP的取值范围是19700101080001到2038年的某一天,因此它不合适存放比较久远的日期。
DATE 用于表示 年月日,如果实际应用值需要保存 年月日 就可以使用 DATE。
TIME 用于表示 时分秒,如果实际应用值需要保存 时分秒 就可以使用 TIME。
YEAR 用于表示年份,YEAR 有2位(最好使用4位)和4位格式的年。默认是4位。如果实际应用只保存年份,那么用1 bytes保存YEAR类型完全可以。不但能够节约存储空间,还能提高表的操作效率。
在4位格式中,允许的值是19012155和0000。在2位格式中,允许的值是7069,表示从1970~2069年。
总结:TIMESTAMP和DATETIME 都可用来表示YYYY-MM-DD HH:MM:SS 类型的日期, 除了存储方式和存储范围以及大小不一样,没有太大区别。但对于跨时区的业务,TIMESTAMP更为合适。
处理日期和时间字段的函数有很多,有的经常会在查询中使用到,下面介绍下几个相关函数的使用方法。
CURDATE
和CURRENT_DATE
两个函数作用相同,返回当前系统的日期值。CURTIME
和CURRENT_TIME
两个函数作用相同,返回当前系统的时间值。NOW()
和SYSDATE()
两个函数作用相同,返回当前系统的日期和时间值。UNIX_TIMESTAMP
获取UNIX时间戳函数,返回一个以UNIX时间戳为基础的无符号整数。FROM_UNIXTIME
将UNIX时间戳转换为时间格式,与UNIX_TIMESTAMP互为反函数。TO_DAYS()
提取日期值并返回自公元0年到现在的天数。DAY()
获取指定日期或时间中的天值。DATE()
获取指定日期或时间中的日期。TIME()
获取指定日期或时间中的时间。MONTH
获取指定日期中的月份。WEEK
获取指定日期是一年中的第几周。YEAR
获取年份。QUARTER
获取日期所在的季度值。DATE_ADD
和ADDDATE
两个函数功能相同,都是向日期添加指定的时间间隔。DATE_SUB
和SUBDATE
两个函数功能相同,都是向日期减去指定的时间间隔。ADDTIME
时间加法运算,在原始时间上添加指定的时间。SUBTIME
时间减法运算,在原始时间上减去指定的时间。DATEDIFF
获取两个日期之间间隔,返回参数 1 减去参数 2 的值。DATE_FORMAT
格式化指定的日期,根据参数返回指定格式的值。示例:
CREATE TABLE `sys_test` (
`id` varchar(32) NOT NULL COMMENT '主键',
`create_by` varchar(32) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(32) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-- `create_date` date DEFAULT CURRENT_DATE COMMENT '创建日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='测试表';
DEFAULT CURRENT_TIMESTAMP
子句,只能TIMESTAMP类型列上指定。DEFAULT CURRENT_TIMESTAMP
子句可以指定到TIMESTAMP或者DATETIME类型列上。DEFAULT CURRENT_DATE
子句。原因是date类型的default value
一定要是一个常量,不能是一个函数或者是表达式。所以不能给MySQL的date类型的列设置默认值。有些应用生成的时间戳是比这个多出三位,是毫秒表示,如果要转换,需要先将最后三位去掉(标准的10位数字,如果是13位的话可以以除以1000的方式),否则返回NULL
#将时间转换为时间戳unix_timestamp
SELECT UNIX_TIMESTAMP('2019-02-22 13:25:07'); #1550813107
#将时间戳转换为时间from_unixtime
SELECT FROM_UNIXTIME(1550813107); #2019-02-22 13:25:07
#NOW
SELECT UNIX_TIMESTAMP(NOW()); #1550813420
SELECT FROM_UNIXTIME(1550813420); #2019-02-22 13:30:20
参考MySQL的10位或13位时间戳获取,表示及13位时间戳的存储
参考MySQL DATE_FORMAT() 函数
#MySQL 按时间日期查询
DROP TABLE IF EXISTS tb_test;
CREATE TABLE IF NOT EXISTS tb_test(
id INT NOT NULL AUTO_INCREMENT COMMENT 'ID',
name VARCHAR(100) DEFAULT NULL COMMENT '名称',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8 COMMENT '时间测试表';
#插入数据
INSERT INTO tb_test (name) VALUES
('luo'),
('lei'),
('luolei'),
('xing'),
('dxx');
#修改数据
UPDATE tb_test SET name='luo1', update_time='2021-01-23' WHERE id=100;
UPDATE tb_test SET name='luo2', update_time='2022-02-23' WHERE id=101;
UPDATE tb_test SET name='luo3', update_time='2023-03-23' WHERE id=102;
#根据年月日查数据
SELECT *FROM tb_test WHERE DATE_FORMAT(update_time, '%Y-%m-%d')='2019-02-22';
#根据年月查数据
SELECT *FROM tb_test WHERE DATE_FORMAT(update_time, '%Y-%m')='2021-01';
#根据年查数据
SELECT *FROM tb_test WHERE DATE_FORMAT(update_time, '%Y')='2022';
#根据日期区间查询数据,并排序
SELECT *FROM tb_test WHERE DATE_FORMAT(update_time, '%Y') BETWEEN '2019' AND '2023' ORDER BY update_time ASC;