MySQL数据类型之日期型
日期类型
日期类型 | 占用空间(字节数) | 表示范围 |
---|---|---|
date | 4 | 1000-01-01 ~ 9999-12-31 |
datetime | 8 | 1000-01-01 00:00:00.000000 ~ 9999-12-31 23:59:59.999999 |
timestamp | 4 | 1970-01-01 00:00:00.000000UTC ~ 2038-01-19 03:14:07.000000UTC |
year | 1 | 1901-2155 |
time | 3 | -838:59:59.000000 ~ 838:59:59.000000 |
datetime
从MySQL5.6版本开始,DATETIME类型支持毫秒,DATETIME(N)中的N表示毫秒的精度。例如,DATETIME(6)表示可以存储6位的毫秒值。同时,一些日期函数也支持精确到毫秒,例如常见的函数 NOW、SYSDATE:
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2021-05-15 17:33:09 |
+---------------------+
1 row in set (0.01 sec)mysql> select now(6);
+----------------------------+
| now(6) |
+----------------------------+
| 2021-05-15 17:33:19.068396 |
+----------------------------+
1 row in set (0.00 sec)
用户可以将DATETIME初始化值设置为当前时间,并设置自动更新当前时间的属性。例如数据库的每个表都会有一个字段create_time来都会记录创建时间,使用update_time来记录这条记录每次修改的时间。
mysql> show create table user;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user | CREATE TABLE `user` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(20) NOT NULL,`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)mysql> insert into user(name) values('morris');
Query OK, 1 row affected (0.01 sec)mysql> select * from user;
+----+--------+----------------------------+----------------------------+
| id | name | create_time | update_time |
+----+--------+----------------------------+----------------------------+
| 1 | morris | 2021-05-15 17:40:00.332704 | 2021-05-15 17:40:00.332704 |
+----+--------+----------------------------+----------------------------+
1 row in set (0.00 sec)mysql> update user set name='marry' where id = 1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql> select * from user;
+----+-------+----------------------------+----------------------------+
| id | name | create_time | update_time |
+----+-------+----------------------------+----------------------------+
| 1 | marry | 2021-05-15 17:40:00.332704 | 2021-05-15 17:40:19.785901 |
+----+-------+----------------------------+----------------------------+
1 row in set (0.00 sec)
在上面的表User中,列create_time表示创建时间,DEFAULT CURRENT_TIMESTAMP表示记录插入时,若没有指定时间,默认就是当前时间。列update_time表示当前记录最后的修改时间,DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) 表示每次修改都会修改为当前时间。
在做表结构设计规范时,强烈建议你每张业务核心表都增加一个DATETIME类型的update_time字段,并设置修改自动更新机制,方便标识每条记录最后修改的时间,这样在数据库的同步时也可以利用到这个字段。
TIMESTAMP
除了DATETIME,日期类型中还有一种TIMESTAMP的时间戳类型,其实际存储的内容为‘1970-01-01 00:00:00’到现在的毫秒数。在MySQL中,由于类型TIMESTAMP占用4个字节,因此其存储的时间上限只能到‘2038-01-19 03:14:07’。
同类型DATETIME一样,从MySQL 5.6版本开始,类型TIMESTAMP也能支持毫秒。与DATETIME不同的是,若带有毫秒时,类型TIMESTAMP占用7个字节,而DATETIME无论是否存储毫秒信息,都占用8个字节。
类型TIMESTAMP最大的优点是可以带有时区属性,因为它本质上是从毫秒转化而来。如果你的业务需要对应不同的国家时区,那么类型TIMESTAMP是一种不错的选择。比如新闻类的业务,通常用户想知道这篇新闻发布时对应的自己国家时间,那么TIMESTAMP是一种选择。
另外,有些国家会执行夏令时。根据不同的季节,人为地调快或调慢1个小时,带有时区属性的TIMESTAMP类型本身就能解决这个问题。
参数time_zone指定了当前使用的时区,默认为SYSTEM使用操作系统时区,用户可以通过该参数指定所需要的时区。
如果想使用TIMESTAMP的时区功能,你可以通过下面的语句将之前的用户表User的创建时间字段类型从DATETIME(6)修改为TIMESTAMP(6):
mysql> alter table user change create_time create_time timestamp(6) not null default current_timestamp(6);
Query OK, 1 row affected (3.07 sec)
Records: 1 Duplicates: 0 Warnings: 0
这时通过设定不同的 time_zone,可以观察到不同时区下的注册时间:
mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| SYSTEM |
+-------------+
1 row in set (0.00 sec)mysql> select * from user;
+----+-------+----------------------------+----------------------------+
| id | name | create_time | update_time |
+----+-------+----------------------------+----------------------------+
| 1 | marry | 2021-05-15 17:40:00.332704 | 2021-05-15 17:40:19.785901 |
+----+-------+----------------------------+----------------------------+
1 row in set (0.00 sec)mysql> set time_zone='-08:00';
Query OK, 0 rows affected (0.00 sec)mysql> select * from user;
+----+-------+----------------------------+----------------------------+
| id | name | create_time | update_time |
+----+-------+----------------------------+----------------------------+
| 1 | marry | 2021-05-15 01:40:00.332704 | 2021-05-15 17:40:19.785901 |
+----+-------+----------------------------+----------------------------+
1 row in set (0.00 sec)
从上述例子中,你可以看到,中国的时区是+08:00,美国的时区是-08:00,因此改为美国时区后,可以看到用户注册时间比之前延迟了16个小时。当然了,直接加减时区并不直观,需要非常熟悉各国的时区表。在MySQL中可以直接设置时区的名字,如:
mysql> set time_zone='America/Los_Angeles';
Query OK, 0 rows affected (0.01 sec)mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2021-05-15 03:09:53 |
+---------------------+
1 row in set (0.00 sec)mysql> set time_zone='Asia/Shanghai';
Query OK, 0 rows affected (0.00 sec)mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2021-05-15 18:10:39 |
+---------------------+
1 row in set (0.00 sec)
在上面设置时区的名字时可能会报如下错误:
mysql> set time_zone='America/Los_Angeles';
ERROR 1298 (HY000): Unknown or incorrect time zone: 'America/Los_Angeles'
这时需要安装timezone的表,可以到http://dev.mysql.com/downloads/timezones.html下载对应版本与系统的sql语句,一般是下载posix标准的那张表,下载完后然后导入到mysql的mysql库中:
mysql> use mysql
Database changedmysql> source /root/timezone_posix.sql
... ...
Query OK, 3214 rows affected, 1 warning (0.14 sec)
Records: 3214 Duplicates: 0 Warnings: 1
DATETIME vs TIMESTAMP vs INT,怎么选?
在做表结构设计时,对日期字段的存储,开发人员通常会有3种选择:DATETIME、TIMESTAMP、INT。
INT类型就是直接存储’1970-01-01 00:00:00’到现在的毫秒数,本质和TIMESTAMP一样,因此用INT不如直接使用TIMESTAMP。
当然,有些同学会认为INT比TIMESTAMP性能更好。但是,由于当前每个CPU每秒可执行上亿次的计算,所以无须为这种转换的性能担心。更重要的是,在后期运维和数据分析时,使用INT存储日期,是会让DBA和数据分析人员发疯的,INT的可运维性太差。
也有的同学会热衷用类型 TIMESTEMP 存储日期,因为类型 TIMESTAMP 占用 4 个字节,比 DATETIME 小一半的存储空间。
但若要将时间精确到毫秒,TIMESTAMP要7个字节,和DATETIME 8字节差不太多。另一方面,现在距离TIMESTAMP的最大值‘2038-01-19 03:14:07’已经很近,这是需要开发同学好好思考的问题。
总的来说,我建议你使用类型DATETIME。对于时区问题,可以由前端或者服务这里做一次转化,不一定非要在数据库中解决。
不要忽视TIMESTAMP的性能问题
虽然从毫秒数转换到类型TIMESTAMP本身需要的CPU指令并不多,这并不会带来直接的性能问题。但是如果使用默认的操作系统时区,则每次通过时区计算时间时,要调用操作系统底层系统函数 __tz_convert(),而这个函数需要额外的加锁操作,以确保这时操作系统时区没有修改。所以,当大规模并发访问时,由于热点资源竞争,会产生两个问题。
性能不如 DATETIME:DATETIME不存在时区转化问题。
性能抖动: 海量并发时,存在性能抖动问题。
为了优化TIMESTAMP的使用,强烈建议你使用显式的时区,而不是操作系统时区。比如在配置文件中显示地设置时区,而不要使用系统时区:
[mysqld]
default-time-zone = '+8:00'
最后,通过命令mysqlslap来测试TIMESTAMP设置时区与不设置的性能,命令如下:
不设置时区,采用默认时区SYSTEM:
# mysqlslap -uroot --number-of-queries=1000000 --concurrency=100 --query='SELECT NOW()' -p
Enter password:
BenchmarkAverage number of seconds to run all queries: 29.898 secondsMinimum number of seconds to run all queries: 29.898 secondsMaximum number of seconds to run all queries: 29.898 secondsNumber of clients running queries: 100Average number of queries per client: 10000
在my.inf文件中指定时区:
# mysqlslap -uroot --number-of-queries=1000000 --concurrency=100 --query='SELECT NOW()' -p
Enter password:
BenchmarkAverage number of seconds to run all queries: 27.597 secondsMinimum number of seconds to run all queries: 27.597 secondsMaximum number of seconds to run all queries: 27.597 secondsNumber of clients running queries: 100Average number of queries per client: 10000
从运行结果中可以发现,显式指定时区的性能要远远好于直接使用操作系统时区。所以,日期字段推荐使用DATETIME,没有时区转化。即便使用 TIMESTAMP,也需要在数据库中显式地配置时区,而不是用系统时区。
MySQL数据类型之日期型相关推荐
- mysql decimal型转化为float_5分钟搞懂MySQL数据类型之数值型DECIMAL类型
速成指南 5分钟搞懂MySQL数据类型 之数值型--DECIMAL类型 DECIMAL类型的语法:DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL].其中M指定的是数字的总位 ...
- MySQL数据类型之数值型
整型 类型 占用字节数 最小值~最大值(有符号) 最小值~最大值(无符号) tinyint 1 -128~127 0~255 smallint 2 -215~215-1 0~2^16-1 medium ...
- MySQL数据类型之字符型
字符类型 类型 说明 N的含义 是否有字符集 最大长度 char(n) 定长字符 字符 是 255 varchar(n) 变长字符 字符 是 65535 binary(n) 定长二进制字节 字节 否 ...
- mysql数据类型查询命令_Linux命令:MySQL系列之三--mysql数据类型及SQL结构化查询语句使用...
MySQL 存储引擎,也被称为表类型: MyISAM表:无事务处理功能,支持表锁 .frm:表结构定义文件 .MYD:表数据文件 .MYI:表索引文件 InnoDB表:支持事务处理功能,支持行锁 .f ...
- 二、mysql数据类型
二.mysql数据类型 1.数值型 decimal(65) decimal最大支持65位 bit(10) 最大支持10位的二进制存储模式 bin(column),hex(column) 使用bin(二 ...
- MySQL数据类型 -- 日期时间型
在MySQL关系型数据库中,MySQL支持的数据类型非常丰富.它主要分为3大类,即:数值型,日期时间性,字符型.而实际上这三类数据类型可以进一步的细分扩展,可以根据业务需要选择最适合的一种.本文主要介 ...
- 八、一篇文章快速搞懂MySQL 常见的数据类型(整型、小数、字符型、日期型详解)
常见的数据类型 1.数值型: 整型 小数: 定点数 浮点数 2.字符型: 较短的文本:char.varchar 较长的文本:text.blob(较长的二进制数据) 3.日期型: 一.整型 1)分类: ...
- js获取mysql数据库数据类型_怎么利用JS将从数据库中读取出来的日期型格式化为想要的类型...
在页面初始化时,用JavaScript将从数据库中读取出来的日期型格式化为想要的类型.格式化为yyyy年MM月dd日 HH时mm分ss秒,大家可以参考下代码,自由发挥下. 代码如下://传入从数据库中 ...
- MySQL数据类型--日期时间
作者:壹叶随风 一.博客前言 自接触学习MySQL已有一段时间了,对于MySQL的基础知识还是有一定的了解的.在这一路学习过来,每次不管看书还是网上看的资料,对于MySQL数据类型中的时间日期类型总是 ...
最新文章
- ros-kinetic install error: sudo rosdep init ImportError: No module named 'rosdep2'
- Google Guava –期货
- lucene 高亮显示
- Python使用秦九韶算法求解多项式的值
- html元素自己属性代码,jQuery如何操作HTML的元素和属性?(代码详解例)
- FTP服务器的搭建及创建虚拟用户进行认证访问
- 位置采集[置顶] iPhone手机上的GPS位置信息采集与分享应用
- linux 路由添加
- json react 展示工具_基于jsoneditor二次封装一个可实时预览的json编辑器组件(react版)...
- 敏捷开发框架—Scrum
- 直通车推广:打造潮流女装爆款
- 一级指针, 二级指针
- 小米10pro第二个摄像头下面_小米10 Pro拍照翻车?暂不支持超广角超级夜景,官方回应...
- Apple现行公开的framework简介
- three.js贴图之CubeTextureLoader全景贴图
- 微电影拍摄制作的基本流程有哪些?
- 转:条件变量(Condition Variables)
- excel报表导入失败问题记录
- 相控阵天线(六):直线阵列天线特殊综合方法(变形泰勒综合法、贝利斯综合法、伍德沃德抽样法)
- 可将视频转换成Gif动画的相关软件