设置MySQL @@session.time_zone每个查询的缺点,而不是使用CONVERT_TZ?

huangapple go评论127阅读模式
英文:

Drawbacks of setting MySQL @@session.time_zone per query instead of CONVERT_TZ?

问题

我们在数据库中存储MySQL时间戳列。

我们为多个Web客户提供服务,这些客户位于多个时区,我们经常需要查询与其时区相关的数据,以允许他们使用本地时间。

以下是我们系统中的平均查询示例:

SELECT * FROM user
WHERE CONVERT_TZ(created_at, @@session.time_zone, 'America/Denver')
BETWEEN '2023-01-01 00:00:00' AND '2023-01-31 23:59:59' <--- 这些是客户提供的本地丹佛时间,因此我们必须从服务器时区进行转换。

如您所见,我们当前的解决方案是利用CONVERT_TZ函数将MySQL服务器时区对时间戳列的解释转换为客户端的本地时区。

这种重复对开发人员而言是繁重的,而且关键查询可能会被遗漏。在单个查询中,我们通常会有五个或六个或更多的CONVERT_TZ实例。

为了解决这个问题,我们考虑利用MySQL自动将时间戳自动转换为连接的time_zone变量的事实,如此处所述:https://dev.mysql.com/doc/refman/8.0/en/datetime.html#:~:text=MySQL%20converts%20TIMESTAMP,Zone%20Support%E2%80%9D。

理论上,在查询之前将MySQL的time_zone设置为我们客户的时区将自动使他们的所有查询能够使用其本地时区,无需额外的转换。

这个想法产生了以下查询:

SET @@session.time_zone = 'America/Denver';
SELECT * FROM user
WHERE created_at <--- 不再需要转换列,因为MySQL time_zone生效。
BETWEEN '2023-01-01 00:00:00' AND '2023-01-31 23:59:59'
SET @@session.time_zone = 'SYSTEM'; <--- 恢复到系统时区。

这种方法有什么缺点吗?多个会话/连接中的多个查询是否会受到其他变量的影响?在多个查询之间是否存在可能在完成之前继承不正确变量的竞争条件?

英文:

We are storing MySQL timestamp columns in our database.

We are serving multiple web customers in multiple timezones, we often have to query the data sensitive to their timezone to allow them to use their local times.

Here is an example of an average query in our system:

SELECT * FROM user
WHERE CONVERT_TZ(created_at, @@session.time_zone, &#39;America/Denver&#39;)
BETWEEN &#39;2023-01-01 00:00:00&#39; AND &#39;2023-01-31 23:59:59&#39; &lt;--- These are local denver times provided from the customer so we have to convert from the server timezone.

As you can see, our current solution is to leverage the CONVERT_TZ function to convert from the MySQL server timezone interpretation of the timestamp column into the client's local timezone.

This repetition becomes burdensome on developers and can accidentally be left out of crucial queries. We can often have five or six or more instances of CONVERT_TZ in a single query.

To solve this problem we are thinking about leveraging the fact that timestamps are converted automatically by MySQL to the connection time_zone variable as outlined here: https://dev.mysql.com/doc/refman/8.0/en/datetime.html#:~:text=MySQL%20converts%20TIMESTAMP,Zone%20Support%E2%80%9D.

In theory, setting the MySQL time_zone to our customer's timezone prior to the query would automatically make all of their queries able to their local timezone without additional conversions.

This idea yields the following query:

SET @@session.time_zone = &#39;America/Denver&#39;;
SELECT * FROM user
WHERE created_at &lt;-- No longer have to convert the column, because the MySQL time_zone takes affect.
BETWEEN &#39;2023-01-01 00:00:00&#39; AND &#39;2023-01-31 23:59:59&#39;
SET @@session.time_zone = &#39;SYSTEM&#39;; &lt;-- Revert back to system.

Are there drawbacks to this approach? Can multiple queries across sessions/connections be impacted by the variables of another? Are there race conditions between multiple queries that might inherit the incorrect variable before completing?

答案1

得分: 1

会话变量不会“泄漏”到其他会话。会话变量在查询运行时不能更改。

最大的缺点是仍然存储在不同时区的日期时间值。您可以更改会话时区,以便根据给定用户的偏好进行搜索,但在许多情况下,这会增加复杂性。以下是一些示例,但还可能有许多其他情况:

  • 检查两个用户中哪一个是先创建的
  • 按日期时间对一组行进行排序
  • 允许一个用户查询另一个用户的日期时间
  • 检查多个用户是否可以参加同一会议

等等。如果根据各自用户的偏好存储每个用户的日期时间,那么如果要比较日期时间,仍然需要转换其中一个。

将日期时间存储在用户的首选时区的另一个缺点是,如果用户移动到另一个时区并更改他们的偏好会怎么样?您将不得不更新包含被该用户引用的时间的所有行。

首选的解决方案是:将所有日期时间存储在UTC时区。

(实际上,无论选择哪个时区,只要保持一致即可。UTC只是一个良好的中立选择。)

然后,您可以比较日期时间,对其进行排序,并无需担心开发人员忘记如何正确转换它们。在插入时将值转换为UTC,然后在显示查询结果时将其转换为用户的_当前_偏好。

英文:

Session variables never "leak" into other sessions. Session variables cannot change while the query is running.

The biggest drawback is that you still have datetime values stored in different timezones. You can change the session timezone so you can search based on a given user's preference, but there are many cases when this makes things hard. Here are a few examples, but there may be many others:

  • Check which of two users was created first
  • Sort a set of rows by datetime
  • Allow one user to query the datetime of another user
  • Check if multiple users can attend the same meeting

And so on. If you store each user's datetimes according the respective user's preference, then you still need to convert one or the other if you want to compare datetimes.

Another downside of storing datetimes in a user's preferred timezone is what if that user moves to another timezone, and they change their preference? You'd have to update all rows that contain times referenced by that user.

The preferred solution is: store all datetimes in UTC.

(Actually, it doesn't matter which TZ you choose, as long as you are consistent. UTC is just a good neutral choice.)

Then you can compare datetimes, you can sort them, and you don't have to worry about developers forgetting how to convert them properly. Convert the values to UTC on insert, and convert them to the user's current preference when you display query results.

huangapple
  • 本文由 发表于 2023年2月16日 03:29:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464613.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定