|
5 | 5 | - MySQL |
6 | 6 | --- |
7 | 7 |
|
8 | | -我们平时开发中不可避免的就是要存储时间,比如我们要记录操作表中这条记录的时间、记录转账的交易时间、记录出发时间等等。你会发现时间这个东西与我们开发的联系还是非常紧密的,用的好与不好会给我们的业务甚至功能带来很大的影响。所以,我们有必要重新出发,好好认识一下这个东西。 |
9 | | - |
10 | | -这是一篇短小精悍的文章,仔细阅读一定能学到不少东西! |
| 8 | +我们平时开发中不可避免的就是要存储时间,比如我们要记录操作表中这条记录的时间、记录转账的交易时间、记录出发时间、用户下单时间等等。你会发现时间这个东西与我们开发的联系还是非常紧密的,用的好与不好会给我们的业务甚至功能带来很大的影响。所以,我们有必要重新出发,好好认识一下这个东西。 |
11 | 9 |
|
12 | 10 | ## 不要用字符串存储日期 |
13 | 11 |
|
14 | | -我记得我在大学的时候就这样干过,而且现在很多对数据库不太了解的新手也会这样干,可见,这种存储日期的方式的优点还是有的,就是简单直白,容易上手。 |
| 12 | +和绝大部分对数据库不太了解的新手一样,我在大学的时候就这样干过,甚至认为这样是一个不错的表示日期的方法。毕竟简单直白,容易上手。 |
15 | 13 |
|
16 | 14 | 但是,这是不正确的做法,主要会有下面两个问题: |
17 | 15 |
|
18 | 16 | 1. 字符串占用的空间更大! |
19 | 17 | 2. 字符串存储的日期效率比较低(逐个字符进行比对),无法用日期相关的 API 进行计算和比较。 |
20 | 18 |
|
21 | | -## Datetime 和 Timestamp 之间抉择 |
| 19 | +## Datetime 和 Timestamp 之间的抉择 |
22 | 20 |
|
23 | | -Datetime 和 Timestamp 是 MySQL 提供的两种比较相似的保存时间的数据类型。他们两者究竟该如何选择呢? |
| 21 | +Datetime 和 Timestamp 是 MySQL 提供的两种比较相似的保存时间的数据类型,可以精确到秒。他们两者究竟该如何选择呢? |
24 | 22 |
|
25 | | -**通常我们都会首选 Timestamp。** 下面说一下为什么这样做! |
| 23 | +下面我们来简单对比一下二者。 |
26 | 24 |
|
27 | | -### DateTime 类型没有时区信息 |
| 25 | +### 时区信息 |
28 | 26 |
|
29 | | -**DateTime 类型是没有时区信息的(时区无关)** ,DateTime 类型保存的时间都是当前会话所设置的时区对应的时间。这样就会有什么问题呢?当你的时区更换之后,比如你的服务器更换地址或者更换客户端连接时区设置的话,就会导致你从数据库中读出的时间错误。不要小看这个问题,很多系统就是因为这个问题闹出了很多笑话。 |
| 27 | +**DateTime 类型是没有时区信息的(时区无关)** ,DateTime 类型保存的时间都是当前会话所设置的时区对应的时间。这样就会有什么问题呢?当你的时区更换之后,比如你的服务器更换地址或者更换客户端连接时区设置的话,就会导致你从数据库中读出的时间错误。 |
30 | 28 |
|
31 | 29 | **Timestamp 和时区有关**。Timestamp 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间,说简单点就是在不同时区,查询到同一个条记录此字段的值会不一样。 |
32 | 30 |
|
@@ -98,28 +96,32 @@ SET GLOBAL time_zone = '+8:00'; |
98 | 96 | SET GLOBAL time_zone = 'Europe/Helsinki'; |
99 | 97 | ``` |
100 | 98 |
|
101 | | -### DateTime 类型耗费空间更大 |
| 99 | +### 占用空间 |
| 100 | + |
| 101 | +下图是 MySQL 日期类型所占的存储空间(官方文档传送门:<https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html>): |
102 | 102 |
|
103 | | -Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间。但是,这样同样造成了一个问题,Timestamp 表示的时间范围更小。 |
| 103 | + |
104 | 104 |
|
105 | | -- DateTime:1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 |
106 | | -- Timestamp:1970-01-01 00:00:01 ~ 2037-12-31 23:59:59 |
| 105 | +在 MySQL 5.6.4 之前,DateTime 和 Timestamp 的存储空间是固定的,分别为 8 字节和 4 字节。但是从 MySQL 5.6.4 开始,它们的存储空间会根据毫秒精度的不同而变化,DateTime 的范围是 5~8 字节,Timestamp 的范围是 4~7 字节。 |
107 | 106 |
|
108 | | -> Timestamp 在不同版本的 MySQL 中有细微差别。 |
| 107 | +### 表示范围 |
109 | 108 |
|
110 | | -## 再看 MySQL 日期类型存储空间 |
| 109 | +Timestamp 表示的时间范围更小,只能到 2038 年: |
111 | 110 |
|
112 | | -下图是 MySQL 5.6 版本中日期类型所占的存储空间: |
| 111 | +- DateTime:1000-01-01 00:00:00.000000 ~ 9999-12-31 23:59:59.499999 |
| 112 | +- Timestamp:1970-01-01 00:00:01.000000 ~ 2038-01-19 03:14:07.499999 |
113 | 113 |
|
114 | | - |
| 114 | +### 性能 |
115 | 115 |
|
116 | | -可以看出 5.6.4 之后的 MySQL 多出了一个需要 0 ~ 3 字节的小数位。DateTime 和 Timestamp 会有几种不同的存储空间占用。 |
| 116 | +由于 TIMESTAMP 需要根据时区进行转换,所以从毫秒数转换到 TIMESTAMP 时,不仅要调用一个简单的函数,还要调用操作系统底层的系统函数。这个系统函数为了保证操作系统时区的一致性,需要进行加锁操作,这就降低了效率。 |
117 | 117 |
|
118 | | -为了方便,本文我们还是默认 Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间。 |
| 118 | +DATETIME 不涉及时区转换,所以不会有这个问题。 |
119 | 119 |
|
120 | | -## 数值型时间戳是更好的选择吗? |
| 120 | +为了避免 TIMESTAMP 的时区转换问题,建议使用指定的时区,而不是依赖于操作系统时区。 |
121 | 121 |
|
122 | | -很多时候,我们也会使用 int 或者 bigint 类型的数值也就是时间戳来表示时间。 |
| 122 | +## 数值时间戳是更好的选择吗? |
| 123 | + |
| 124 | +很多时候,我们也会使用 int 或者 bigint 类型的数值也就是数值时间戳来表示时间。 |
123 | 125 |
|
124 | 126 | 这种存储方式的具有 Timestamp 类型的所具有一些优点,并且使用它的进行日期排序以及对比等操作的效率会更高,跨系统也很方便,毕竟只是存放的数值。缺点也很明显,就是数据的可读性太差了,你无法直观的看到具体时间。 |
125 | 127 |
|
@@ -149,12 +151,19 @@ mysql> select FROM_UNIXTIME(1578707612); |
149 | 151 |
|
150 | 152 | ## 总结 |
151 | 153 |
|
152 | | -MySQL 中时间到底怎么存储才好?Datetime?Timestamp? 数值保存的时间戳? |
| 154 | +MySQL 中时间到底怎么存储才好?Datetime?Timestamp?还是数值时间戳? |
| 155 | + |
| 156 | +并没有一个银弹,很多程序员会觉得数值型时间戳是真的好,效率又高还各种兼容,但是很多人又觉得它表现的不够直观。 |
153 | 157 |
|
154 | | -好像并没有一个银弹,很多程序员会觉得数值型时间戳是真的好,效率又高还各种兼容,但是很多人又觉得它表现的不够直观。这里插一嘴,《高性能 MySQL 》这本神书的作者就是推荐 Timestamp,原因是数值表示时间不够直观。下面是原文: |
| 158 | +《高性能 MySQL 》这本神书的作者就是推荐 Timestamp,原因是数值表示时间不够直观。下面是原文: |
155 | 159 |
|
156 | 160 | <img src="https://oss.javaguide.cn/github/javaguide/%E9%AB%98%E6%80%A7%E8%83%BDmysql-%E4%B8%8D%E6%8E%A8%E8%8D%90%E7%94%A8%E6%95%B0%E5%80%BC%E6%97%B6%E9%97%B4%E6%88%B3.jpg" style="zoom:50%;" /> |
157 | 161 |
|
158 | | -每种方式都有各自的优势,根据实际场景才是王道。下面再对这三种方式做一个简单的对比,以供大家实际开发中选择正确的存放时间的数据类型: |
| 162 | +每种方式都有各自的优势,根据实际场景选择最合适的才是王道。下面再对这三种方式做一个简单的对比,以供大家实际开发中选择正确的存放时间的数据类型: |
| 163 | + |
| 164 | +| 类型 | 存储空间 | 日期格式 | 日期范围 | 是否带时区信息 | |
| 165 | +| ------------ | -------- | ------------------------------ | ------------------------------------------------------------ | -------------- | |
| 166 | +| DATETIME | 5~8字节 | YYYY-MM-DD hh:mm:ss[.fraction] | 1000-01-01 00:00:00[.000000] ~ 9999-12-31 23:59:59[.999999] | 否 | |
| 167 | +| TIMESTAMP | 4~7字节 | YYYY-MM-DD hh:mm:ss[.fraction] | 1970-01-01 00:00:01[.000000] ~ 2038-01-19 03:14:07[.999999] | 是 | |
| 168 | +| 数值型时间戳 | 4字节 | 全数字如1578707612 | 1970-01-01 00:00:01之后的时间 | 否 | |
159 | 169 |
|
160 | | - |
|
0 commit comments