暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL | 5年前的add_months代码挖了一个"坑"

前言

昨日将修改方法发给开发妹子,以为可以让她们通过程序改造,结果今天直接扔回来了。

为什么无法使用索引?

DBA小哥,我们发现这个SQL还是有问题?

啥问题?

你瞧啊?用to_number就可以走索引,但我们根据这个修改了一下为什么就不能呢?

看起来,确实很奇怪。但我仍然觉得有必要确认一下类型,所以我用pg_typeof查看了下她写的这一堆代码。

太奇怪了,右边条件传入的值已经是numeric,为什么不能使用索引呢?仔细观察发现使用了很多函数,所以我决定还是先将每个函数 check一下。

看起来确实有点可疑,原来它的add_months是自己写的。系统的默认只支持 date类型,而他们自己开发的则支持 timestamp类型。所以我决定用current_timestamp来代替,反正这个数字是计算上个月的日期。

cmp=> select to_char( add_months ( now(),- 1 ), 'yyyymm' );
 to_char 
---------
 202101
(1 row)

cmp=> select to_char(current_timestamp + '-1 months','YYYYMM');
 to_char 
---------
 202101
(1 row)

接下来我用改造的条件拿来run了一下,这次可以使用索引了。

那么整个问题也就水落石出了,他们自己编写的函数无法使用索引,那么,第三方插件的add_months能吗?

cmp=> \df oracle.add_months 
                                      List of functions
 Schema |    Name    |      Result data type       |        Argument data types        | Type 
--------+------------+-----------------------------+-----------------------------------+------
 oracle | add_months | timestamp without time zone | timestamp with time zone, integer | func
(1 row)

好奇心趋势我使用了orafce的add_months进行了测试。

索引仍可使用。因此问题在于开发自己写的add_months出现问题,导致索引不可用。再拿两个函数来做进一步的对比。

第三方的add_months非常简单,而开发侧的add_months则有点过于复杂,代码里面还需要进行判断。基于此代码在网络上搜索,发现它来自于这篇文章。

据本文所述,第三方add_months在02-28号减去1个月,显示的并非是月末01-31号,而是01-28号。因此,解决方案是自己开发add_months并进行判断。

相同的代码,我们根据它遇到的问题进行了测试,发现最新版本的orafce没有此问题。

这篇文章发布在2016年,已经过了5年,这一问题之前一直存在,但现在已经得到解决。还使用之前的代码,就相当于给自己挖一个坑。

后记

妹子,不要用你们自己写的add_months,用current_timestamp或者orafce的add_months就可以了。你自己写的add_months代码已经是5年的代码了,现在不要再用了,我把上面测试的结果图发给了她。

过了一会,她说道:"不行,current_timestamp计算是有错误的!"

哦,我赶紧测试了一下。

cmp=> select '2015-02-28 11:11:11+08'::timestamp + '-1 months';
      ?column?       
---------------------
 2015-01-28 11:11:11
(1 row)

我靠,确实还有坑,不过我转念一想,不对啊,你不是查yyyymm不需要日期只需要年份和月份吗?是不是在套路我啊。于是我说道:那你就用orafce.add_months吧"


文章转载自励志成为PostgreSQL大神,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论