我在我正在使用的网站中的表中有一个日期时间列,我想经常将其用作键。
由于它将非常频繁地来回传输,我希望在不影响性能的情况下尽可能减少数据传输开销,并保持数据存储(最终在 cookie 中)的可靠性。
为此,我正在思考
to_base64(unix_timestamp(date_column))
。
然后我可以根据日期列的时间戳值将其转换为 Base64。例如,如果我的日期时间为
2024-11-02 07:25:16
,则其 unix_timestamp()
将为 1730528716
,其 to_base64()
为 MTczMDUyODcxNg==
。
现在的问题是,我认为费尽心思去获取一个
int(11)
值(至少到 2038 年 1 月中旬左右)只是为了将其打包为一串 0-9 的字符串是不公平的,而我可以正在转换其实际的整数表示形式。
如果我用
to_base64(unhex(hex(unix_timestamp())))
:“破解”列,我可以从 MySQL 本身获得我想要的值
> select date_column, unix_timestamp(date_column), to_base64(unix_timestamp(date_column)), to_base64(unhex(hex(unix_timestamp(date_column))));
+---------------------+-----------------------------+----------------------------------------+----------------------------------------------------+
| date_column | unix_timestamp(date_column) | to_base64(unix_timestamp(date_column)) | to_base64(unhex(hex(unix_timestamp(date_column)))) |
+---------------------+-----------------------------+----------------------------------------+----------------------------------------------------+
| 2024-11-02 07:25:16 | 1730528716 | MTczMDUyODcxNg== | ZyXFzA== |
+---------------------+-----------------------------+----------------------------------------+----------------------------------------------------+
1 row in set (0.000 sec)
因此,一方面,我在http服务器和mysql以及实际的客户端浏览器和http服务器以及base64计算中的每个客户端-服务器通信中节省了一些字节。但是通过上面的黑客,我非常怀疑我最终会真正保存任何东西......而我可以只是将整数值作为原始整数返回或进行(希望)快速转换。
我所做的一些其他尝试:
to_base64(convert(unix_timestamp(date_column) using binary))
to_base64(cast(unix_timestamp(date_column) as binary))
to_base64(cast(unix_timestamp(date_column) as int))
MTczMDUyODcxNg== (wrong)
我注意到通用值中也存在这种行为,例如:
select 10, to_base64(10), to_base64('10'), to_base64(unhex(hex(10)))
10 | MTA= | MTA= | Cg==
(在这个例子中我没有保存角色FWIW)
那么,有没有什么便宜的方法可以从
unix_timestamp()
结果中获得base64“更短”的值?
由于这将在应用程序的关键部分中使用,因此只要从数字序列“转换”为实际数字表示的成本便宜,我拍摄的字符传输和计算越少,这是值得的。
如果最适合这种情况,我可能会考虑将日期存储为 unix 时间戳(不是
datetime
而是整数),这样我也可以从 64 位整数存储中受益。
首先解释为什么这些操作会导致有效负载变大,以及您的“黑客”如何提供帮助。
to_base64()
将其参数视为字符串,因此您的时间戳值 1730528716 隐式变为 10 个字符的字符串“1730528716”。
将整数转换为字符串总是会扩展输入,因为每个十进制数字代表大约 3 位信息,但 ASCII 字符串中的每个字符使用 8 位。
Base64 将任意三个 8 位字符的字符串转换为四个 6 位数字。但 ASCII 码中的数字字符仍占 8 位。因此,base64 总是将其字符串输入扩展 33%。
这就是为什么10个字符的字符串的base64编码是14个字节。
您所做的“黑客”是
unhex(hex())
,它将时间戳值转换为四个二进制字节而不是 10 个字符。二进制字节似乎是一个“字符串”,用于输入 to_base64()
。
这意味着它可以跳过到字符串的转换,并将 Base64 应用到四个字节而不是十个字节。
你问是否可以更快地完成
unhex(hex())
。您需要它到底有多快?这些已经是廉价的转换。在我的笔记本电脑上,我执行该操作 100 万次,但仍然需要不到 0.07 秒:
mysql> select benchmark(1000000, unhex(hex(1730528716))) as _result;
+---------+
| _result |
+---------+
| 0 |
+---------+
1 row in set (0.07 sec)
减少有效负载的另一个想法是存储少于完整的时间戳。您可以将其减少到小时的粒度,而不是以秒为单位存储时间戳。但这可能不适合您对时间戳的使用。
mysql> select length(unhex(hex(1730528716))) as ts_seconds_length,
length(unhex(hex(round(1730528716/3600)))) as ts_hours_length;
+-------------------+-----------------+
| ts_seconds_length | ts_hours_length |
+-------------------+-----------------+
| 4 | 3 |
+-------------------+-----------------+
时间戳还测量自 1970-01-01 纪元以来的秒数。如果您需要以秒为单位的时间戳,但您对那么早的时间戳不感兴趣,则只能计算自 2010 年以来的秒数。这会将时间戳减少到 9 位数字,而不是 10 位数字
mysql> select unix_timestamp('2024-11-02 07:25:16') - unix_timestamp('2010-01-01 00:00:00') as trunc_ts;
+-----------+
| trunc_ts |
+-----------+
| 468224716 |
+-----------+