GaussDB(DWS)兼容模式差异案例分享(一):current_timestamp

举报
你是猴子请来的救兵吗 发表于 2021/11/26 18:00:46 2021/11/26
【摘要】 GaussDB(DWS)支持多种兼容模式,为了兼容目标数据库,各模式之间或多或少存在一些行为差异。持续分享中……

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级数仓黑科技~

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。