首页 > 数据库 >MySQL数据类型之日期型

MySQL数据类型之日期型

时间:2023-04-23 10:35:29浏览次数:51  
标签:set TIMESTAMP time 数据类型 DATETIME 日期 sec mysql 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: 0

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)

在上面的表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 changed

mysql> 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: 
Benchmark
	Average number of seconds to run all queries: 29.898 seconds
	Minimum number of seconds to run all queries: 29.898 seconds
	Maximum number of seconds to run all queries: 29.898 seconds
	Number of clients running queries: 100
	Average number of queries per client: 10000

在my.inf文件中指定时区:

# mysqlslap -uroot --number-of-queries=1000000 --concurrency=100 --query='SELECT NOW()' -p
Enter password: 
Benchmark
	Average number of seconds to run all queries: 27.597 seconds
	Minimum number of seconds to run all queries: 27.597 seconds
	Maximum number of seconds to run all queries: 27.597 seconds
	Number of clients running queries: 100
	Average number of queries per client: 10000

从运行结果中可以发现,显式指定时区的性能要远远好于直接使用操作系统时区。所以,日期字段推荐使用DATETIME,没有时区转化。即便使用 TIMESTAMP,也需要在数据库中显式地配置时区,而不是用系统时区。


标签:set,TIMESTAMP,time,数据类型,DATETIME,日期,sec,mysql,MySQL
From: https://blog.51cto.com/u_6784072/6216465

相关文章

  • ant design of vue的a-rang-picker时间控制既不能选今天以后的日期且开始时间跟结束时
    在项目中这个问题在困扰我,虽然我知道它是有一个Api是disableDate来控制时间的选择;但是只能够实现开始时间跟结束时间之间差不能超过3天。效果图接下来就是代码时间呀<a-col><a-form-model-itemlabel="任务时间范围"prop="priceRangeDate"><a-range-picker......
  • 【IT老齐002】MySQL集群模式与应用场景
    【IT老齐002】MySQL集群模式与应用场景单库模式优点简单粗暴适合数据量干万以下小型应用企业网站,创业公司首选缺点不具备可用性与并发性读写分离集群模式读写分离中间件insert、update、delete负载均衡到从库select路由到主库MySQL主从复制binlog......
  • Mysql解决Authentication plugin ‘caching_sha2_password‘ cannot be loaded
    1、登录Mysqlmysql-uroot-p2、修改账户密码加密规则并更新用户密码//修改加密规则ALTERUSER'root'@'localhost'IDENTIFIEDBY'password'PASSWORDEXPIRENEVER;//更新一下用户的密码ALTERUSER'root'@'localhost'IDENTIFIEDWITHmysql_native_pa......
  • archlinux安装配置MySQL8.x版本
    一:到官网下载Community版本的MySQL:https://dev.mysql.com/downloads/mysql/ 二:解压下载的mysql:xz-dmysql-8.0.33-linux-glibc2.17-x86_64-minimal.tar.xz先将.xz文件解压成tar文件,然后再用:tarxvfmysql-8.0.33-linux-glibc2.17-x86_64-minimal.tar将.tar文件解压出来;......
  • mysql设置允许外部访问
    配置mysql允许外部进行登录访问;登录进入mysql;mysql-uroot-p输入密码进入,usermysql;selecthost,userfromuser; 3.更新user表中root用户域属性,’%'表示允许外部访问updateusersethost='%'whereuser='root'; 4.执行以上语句之后再执行:FLUSHPRIVILEGES; ......
  • Docker安装MySQL
    创建挂载目录mkdir-p/app/mysql&&cd$_docker安装MySQLdockerrun-d-p3306:3306--privileged=true-v/app/mysql/log:/var/log/mysql-v/app/mysql/data:/var/lib/mysql-v/app/mysql/conf:/etc/mysql/conf.d-eMYSQL_ROOT_PASSWORD=123456--namemysql5.7......
  • 实验三 控制语句与组合数据类型应用编程
    实验任务1源代码1importrandom23print('用列表存储随机整数:')4lst=[random.randint(0,100)foriinrange(5)]5print(lst)67print('\n用集合存储随机整数:')8s1={random.randint(0,100)foriinrange(5)}9print(s1)1011print('\n用集合存......
  • Mysql Mybatis 批量修改数据
    MysqlMybatis批量修改数据MapperIntegerupdateListPO(List<ProjectQuotationItemPO>upateList);方法一:<updateid="updateListPO"><foreachcollection="list"separator=";"item="item">UPDATEpro......
  • 控制语句与组合数据类型应用编程
    importrandomprint('用列表存储随机整数:')lst=[random.randint(0,100)foriinrange(5)]print(lst)print('\n用集合存储随机整数:')s1={random.randint(0,100)foriinrange(5)}print(s1)print('\n用集合存储随机整数:')s2=set()whilelen(s2)......
  • 实验3 控制语句与组合数据类型应用编程
    实验任务1task1.py1importrandom23print('用列表存储随机整数:')4lst=[random.randint(0,100)foriinrange(5)]5print(lst)67print('\n用集合存储随机整数:')8s1={random.randint(0,100)foriinrange(5)}9print(s1)1011print(......