oracle迁移函数,将函数索引从Oracle迁移到PostgreSQL

我们使用AWSSchema ConversionTool(SCT)来转换数据库的元数据。通过AWS转换后的脚本在PostgreSQL中执行,发现函数索引无法成功执行。

通过Oracle查询发现其使用了substr和to_char等函数。CREATE INDEX"HB_E2E"."IDX_CUST_ID_I" ON"HB_E2E"."FTP_DIPAN"(SUBSTR(TO_CHAR("CUST_ID"),-1))

而在PostgreSQL中执行则报ERROR: functions in index expression must be marked IMMUTABLE

b40113d9e4ec8325e6cd1f42d64e69a1.png

手动执行上述函数,并不报错。

207df03b004c31aa1a5c5bce99463353.png

根据PostgreSQL文档,函数可以是3种类型,每一个函数都有一个易变性分类可能是VOLATILE、STABLE或者IMMUTABLE。如果CREATEFUNCTION命令没有指定一个分类,则默认是VOLATILE。

VOLATILE函数可以做任何事情,包括修改数据库(比如Update)。在使用相同的参数连续调用时,它能返回不同的结果。优化器不会对这类函数的行为做任何假定。在每一行需要volatile函数值时,一个使用volatile函数的查询都会重新计算该函数。

STABLE函数不能修改数据库,并且被确保对一个语句中的所有行用给定的相同参数返回相同的结果。这种分类允许优化器把该函数的多个调用优化成一个调用。特别是,在一个索引扫描条件中使用包含这样一个函数的表达式是安全的(因为一次索引扫描只会计算一次比较值,而不是为每一行都计算一次,在一个索引扫描条件中不能使用VOLATILE函数)。

IMMUTABLE函数不能修改数据库并且被确保用相同的参数永远返回相同的结果。这种分类允许优化器在一个查询用常量参数调用该函数时提前计算该函数。例如,一个SELECT... WHERE x = 2 + 2这样的查询可以被简化为SELECT... WHERE x = 4,因为整数加法操作符底层的函数被标记为IMMUTABLE

通过查询pg_proc,可以确认函数类型,例如sysdate函数。SELECT proname, provolatile,proargtypes, proargtypes[0]::regtype AS argtype, prosrc FROMpg_proc WHERE proname like ‘sysdate%’;

9261831e9b3d8d08e6fa917be6b1ebc3.png

Provolatile为s,则说明是STABLE函数。

上述有点难以理解,我们来用案例实际说明一下。这里使用current_timestamp来说明。

712c57077a7ba6aae538d534a0f5d327.png

可以看到current_timestamp是的Provolatile状态s,是STABLE函数。

STABLE函数不能修改数据库,并且被确保对一个语句中的所有行用给定的相同参数返回相同的结果。

我们理解如下:这个函数不能修改数据库,它只能查询时间。

并且被确保对一个语句中的所有行用给定的相同参数返回相同的结果。

这个是什么意思呢?当你查一张大表,而这张表每一行要使用这个函数的时候,时间其实是在流逝的,但是你表上所有数据行都必须使用最开始的那个时间。(可以理解为事务开始的时间)。

我们来找类似的几个时间函数测试一下。

f72bb39816ce90302dd5308a3dc09d2d.png

除了clock_timestamp是VOLATILE,now和sysdate都是STABLE

我们创建一张表。createtable test_function

(

id         numeric,

now_time    timestamp without time zone,

sysdate_timetimestamp without time zone,

clock_time  timestamp without time zone

);

插入10000行数据insertinto test_function

selectgenerate_series(1,10000),now(),oracle.sysdate(),clock_timestamp();

插入完成后可以看到,当查询这张表的时候,now(),oracle.sysdate()这种为STABLE的,时间不会发生变化,而clock_timestamp为VOLATILE类型则发生了变化。

5ae9acdea5763f70feef978e54746729.png

至此,要创建函数索引,就必须把函数设置成IMMUTABLE。而实现办法可以自己建一个IMMUTABLE函数,该函数接受输入参数作为numeric类型。然后在创建函数索引的地方使用自己创建的。由于我这里的函数索引使用了2种函数,一个是substr,一个是to_char,substr已经是IMMUTABLE的,所以只需要将to_char函数建成IMMUTABLE就行了。CREATE ORREPLACE FUNCTION immutable_to_char(numeric) RETURNS charactervarying

AS

'selectaws_oracle_ext.to_char($1)'

LANGUAGESQL IMMUTABLE;

CREATE INDEXidx_cust_id_i ON hb_e2e.ftp_dipan USING BTREE(aws_oracle_ext.substr(immutable_to_char(cust_id::numeric),lengthb(immutable_to_char(cust_id::numeric))) ASC);

再次执行asc排序类的sql,发现已经可以使用这个函数索引了。

365d8f614273e39c2c14ae7c6ba512ea.png

参考文档:

函数稳定性讲解- retalk PostgreSQL function's [volatile|stable|immutable ]

https://github.com/digoal/blog/blob/master/201212/20121226_01.md

MigratingFunction based indexes from Oracle to PostgreSQL

https://askdba.org/weblog/2018/01/migrating-function-based-indexes-from-oracle-to-postgresql/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值