GaussDB(DWS)兼容模式差异案例分享(一):current_timestamp
GaussDB(DWS)支持多种兼容模式,为了兼容目标数据库,各模式之间或多或少存在一些行为差异。这里分享一个时间函数的结果差异案例分析。
用户问题描述
数据库版本:PostgreSQL 9.2.4 (GaussDB 8.1.2)
1,ORACLE兼容模式行为
postgres=# SELECT to_char(to_timestamp(cast(extract(epoch from current_timestamp) as bigint)),'yyyy-MM-dd HH24:MI:SS') ;
to_char
---------------------
2021-11-26 10:03:35
(1 row)
2,MYSQL兼容模式行为
mysql=# SELECT to_char(to_timestamp(cast(extract(epoch from current_timestamp) as bigint)),'yyyy-MM-dd HH24:MI:SS') ;
to_char
---------------------
2021-11-26 18:03:35
(1 row)
问题分析过程
1,问题表现为不同兼容模式下的结果差异,首先分析原始SQL语句,排查存在可能的差异函数或表达式。
(可参考“产品文档 - Oracle、Teradata 和MySQL 语法兼容性差异”章节)
这里存在兼容性差异的部分为current_timestamp,来看下差异表现:
postgres=# select current_timestamp;
pg_systimestamp
-------------------------------
2021-11-26 17:23:14.984677+08
(1 row)
mysql=# select current_timestamp;
current_timestamp
----------------------------
2021-11-26 17:23:14.984677
(1 row)
从以上结果可以看出current_timestamp在不同兼容模式下存在时区差异,但时间是一致的,那为什么会引起结果差异呢,继续往下看。
2,原始SQL通过extract epoch获取当前时间戳秒数,但时区和不含时区相差了8个小时,刚好是东八区到UTC时区的时差。
postgres=# select extract(epoch from current_timestamp);
date_part
-----------------
1637918872.4682
(1 row)
mysql=# select extract(epoch from current_timestamp);
date_part
------------------
1637947674.18979
(1 row)
4,查看extract发现它并不是一个函数,而是表达式。
postgres=# \df extract
List of functions
Schema | Name | Result data type | Argument data types | Type | fencedmode | propackage
--------+------+------------------+---------------------+------+------------+------------
(0 rows)
5,构造一个查询计划,查看extract实际调用函数。
postgres=# explain verbose select extract(epoch from '2021-11-26 00:00:00'::timestamp) from t1;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-distinct | E-width | E-costs
----+----------------------------------------------+--------+------------+---------+---------
1 | -> Data Node Scan on "__REMOTE_FQS_QUERY__" | 0 | | 0 | 0.00
Targetlist Information (identified by plan id)
-------------------------------------------------------------------------------------------------------------------------------------
1 --Data Node Scan on "__REMOTE_FQS_QUERY__"
Output: (date_part('epoch'::text, '2021-11-26 00:00:00'::timestamp without time zone))
Node/s: All datanodes
Remote query: SELECT date_part('epoch'::text, '2021-11-26 00:00:00'::timestamp without time zone) AS date_part FROM public.t1
(10 rows)
postgres=# explain verbose select extract(epoch from '2021-11-26 00:00:00'::timestamptz) from t1;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-distinct | E-width | E-costs
----+----------------------------------------------+--------+------------+---------+---------
1 | -> Data Node Scan on "__REMOTE_FQS_QUERY__" | 0 | | 0 | 0.00
Targetlist Information (identified by plan id)
-------------------------------------------------------------------------------------------------------------------------------------
1 --Data Node Scan on "__REMOTE_FQS_QUERY__"
Output: (date_part('epoch'::text, '2021-11-26 00:00:00+08'::timestamp with time zone))
Node/s: All datanodes
Remote query: SELECT date_part('epoch'::text, '2021-11-26 00:00:00+08'::timestamp with time zone) AS date_part FROM public.t1
(10 rows)
通过计划看出入参为带时区/不带时区时调用的函数是不一样的
date_part('epoch'::text, '2021-11-26 00:00:00'::timestamp without time zone)
date_part('epoch'::text, '2021-11-26 00:00:00+08'::timestamp with time zone)
6,验证date_part行为,时间域为epoch时存在差异,此表现和PG一致,符合预期。
postgres=# SELECT date_part('epoch'::text, '2021-11-26 01:02:03+08'::timestamptz);
date_part
------------
1637859723
(1 row)
postgres=# SELECT date_part('epoch'::text, '2021-11-26 01:02:03'::timestamp);
date_part
------------
1637888523
(1 row)
问题规避
1,对于current_timestamp结果类型不确定的问题,建议手动指定类型,即current_timestamp::timestamptz。
SELECT to_char(to_timestamp(cast(extract(epoch from current_timestamp::timestamptz) as bigint)),'yyyy-MM-dd HH24:MI:SS') ;
2,GaussDB(DWS)版本8.1.2之后支持unix_timestamp函数获取时间戳秒数,可以替换extract(epoch from timestamptz)语法。
问题总结
引起该结果差异的是两点差异,使用时需特别注意:
1,current_timestamp在ORACLE兼容模式返回timestamptz带时区,在MYSQL兼容模式下返回tiemstamp不带时区。
2,extract(epoch from timestamp)和date_part(‘epoch’,timestamp)入参带时区时以当前时区为准,不带时区时被当作UTC时区。
想了解GuassDB(DWS)更多信息,欢迎微信搜索“GaussDB DWS”关注微信公众号,和您分享最新最全的PB级数仓黑科技~
- 点赞
- 收藏
- 关注作者
评论(0)