使用 MySQL 的 TIMESTAMP 与直接存储时间戳
Posted
技术标签:
【中文标题】使用 MySQL 的 TIMESTAMP 与直接存储时间戳【英文标题】:Using MySQL's TIMESTAMP vs storing timestamps directly 【发布时间】:2011-10-25 03:22:36 【问题描述】:对于以 mysql 的 TIMESTAMP 格式与自定义 UNSIGNED INT 格式保存日期和时间值,我处于两难境地。这里的主要考虑因素是检索速度、php 中适当的范围计算以及偶尔格式化为人类可读值。
每种类型所需的存储空间及其范围:
DATETIME 8 bytes '1000-01-01 00:00:00' to '9999-12-31 23:59:59'
TIMESTAMP 4 bytes '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC
UNSIGNED INT 4 bytes (Maximum Value 4294967295)
我根本不需要 DATETIME 的范围。我在 TIMESTAMP 和 UNSIGNED INT 之间纠结。
支持 UNSIGNED INT 的论据:
UNIX 时间戳 4294967295 转换为 Sun,2106 年 2 月 7 日 06:28:15 GMT,这比 TIMESTAMP 还多,对我来说已经足够好了 直接在 PHP 中比较这些时间戳会更快,而不是通过 strtotime() 转换 TIMESTAMP,然后进行比较TIMESTAMP 给我的唯一优势是当我手动从 mysql 表中读取值并需要“查看”它们时。
是否有任何令人信服的理由使用 TIMESTAMP 而不是 UNSIGNED INT?
【问题讨论】:
查看相关:datetime vs timestamp? 32 位时间戳只会持续到 2038 年 1 月,而且许多库仍在使用 32 位 time_t 而不是 64 位,因此您可能会遇到可移植性问题。在内部,PHP 无论如何都以数字格式存储时间戳/日期时间,并且仅在检索时转换为漂亮的 yyyy-mm-dd 类型字符串。 【参考方案1】:与往常一样,这取决于您需要保存的内容。 例如,如果您正在使用来自某个 API 的数据并将时间作为数字(秒,这在市场数据中很常见)发送给您,那么将其存储为 unsigned int 而不是每次都转换为字符串可能会更容易和更快在插入之前。
【讨论】:
【参考方案2】:TIMESTAMP 的参数
它以UTC时区隐式存储数据。无论您的会话时区是什么。如果您需要使用不同的时区,这很有用。 您可以使用DEFAULT CURRENT_TIMESTAMP
或 ON UPDATE CURRENT_TIMESTAMP
自动设置时间戳列(在 MySQL 5.6.5 之前,每个表只有一列)
您可以使用 datetime 函数进行日期比较、加法、减法、范围查找等,而无需使用 FROM_UNIXTIME()
函数 - 它可以更轻松地编写可以使用索引的查询
在 PHP 中
>> date('Y-m-d h:i:s',4294967295);
'1969-12-31 11:59:59'
所以范围实际上是相同的
您仍然可以使用 UNIX_TIMESTAMP() 函数检索整数 unix 时间戳,而无需额外开销:http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_unix-timestamp当 UNIX_TIMESTAMP() 用于 TIMESTAMP 列时,函数 直接返回内部时间戳值,没有隐式 “字符串到 Unix 时间戳”的转换
【讨论】:
echo date('Y-m-d h:i:s',4294967295);
for me 给出 2106-02-07 06:28:15 - 你使用的是 32 位操作系统吗?
不,它是 64b 的 Windows,但我认为我正在运行 32b 的 PHP。如果您希望您的应用程序是可移植的,那么您需要考虑这一点。如果您可以控制生产环境,那就没关系了。
至于您的第二个项目符号,只能将一列设为 DEFAULT CURRENT_TIMESTAMP 或 ON UPDATE CURRENT_TIMESTAMP,如此处所指出的(至少在 MySQL v5.1 上):dev.mysql.com/doc/refman/5.1/en/timestamp-initialization.html
@Boaz Rymland:没错。这在 MySQL 5.6.5 中有所改变,它还为 DATETIME 数据类型添加了自动初始化值。 dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html
不应该将时间戳存储为 UTC 吗?【参考方案3】:
TIMESTAMP 的唯一真正用途是当您希望在更新行时自动更新该字段(这是该字段的默认行为),或者当数据存储要求非常严格以至于每行 4 个字节确实使对你来说不一样。
确实应该在 DATETIME 和 UNSIGNED INT 之间进行比较,我推荐 DATETIME,因为:
您可以使用 MySQL 的原生日期/时间函数按日期范围等进行选择。 很容易选择这些日期作为 UNIX 时间戳以便在 PHP 中轻松格式化:SELECT UNIX_TIMESTAMP(field) FROM table
,无需选择原始值并使用 strtotime
如果需要(正如您所指出的),直接读取和编辑数据库中的字段更容易。
日期范围没有限制
在我看来,仅第二点确实消除了以整数存储的任何理由。
【讨论】:
DATETIME 的缺点是它不会在字段中存储 GMT 偏移量。您要么需要在存储到 GMT 之前转换所有内容(或任何您想要的 'zulu' 时间),然后在处理多个时区时将其转换回来。存储在 INT 中消除了其中一些要求。 DATETIME 的一个优点是我很懒惰,它适用于单个语言环境/时区。 感谢UNIX_TIMESTAMP
的评论——我以前不知道这个。
我一直在使用 Carbon DateTime 库将所有内容存储为无符号整数......这是值得考虑的有趣信息。 +1!
如果你使用 DATETIME,你如何处理夏令时?当我们将时钟倒回一小时时,我们会回到与前一小时相同的时间。 Unix 时间没有那个潜在的问题。【参考方案4】:
这可能不是一个“科学”的答案,但我总是发现 MySql 在 TIMESTAMP 列上处理转换、算术、比较等的方式令人困惑。 UNSIGNED INT 列更直接,我总是知道会发生什么。
附:可能支持 TIMESTAMP 列的另一件事是它能够在每次更新或插入后自动设置为当前时间,但这不是你不能没有的。
【讨论】:
以上是关于使用 MySQL 的 TIMESTAMP 与直接存储时间戳的主要内容,如果未能解决你的问题,请参考以下文章
数据库中存日期使用datetime与timestamp类型与Java相应收接类型的实验使用LocalDateTime与Timestamp类测试
BEFORE 触发器和 ON UPDATE CURRENT_TIMESTAMP 之间的性能差异 - MySQL
mysql(自动添加系统时间)timestamp类型字段的CURRENT_TIMESTAMP与ON UPDATE CURRENT_TIMESTAMP属性