前言
昨日将修改方法发给开发妹子,以为可以让她们通过程序改造,结果今天直接扔回来了。
为什么无法使用索引?
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吧"




