Function 替换索引中使用的函数
当我更改基础函数时,构建在函数上的索引会发生什么变化 比如说,我有一个函数Function 替换索引中使用的函数,function,postgresql,indexing,plpgsql,Function,Postgresql,Indexing,Plpgsql,当我更改基础函数时,构建在函数上的索引会发生什么变化 比如说,我有一个函数clean\u name()定义为: CREATE OR REPLACE FUNCTION clean_name(n text) RETURNS TEXT AS $BODY$ DECLARE rec TEXT; BEGIN EXECUTE 'SELECT Regexp_replace(' || quote_literal(n) || ', ''[a-z]'', '''', ''g'');' INTO rec; R
clean\u name()
定义为:
CREATE OR REPLACE FUNCTION clean_name(n text)
RETURNS TEXT AS
$BODY$
DECLARE
rec TEXT;
BEGIN
EXECUTE
'SELECT Regexp_replace(' || quote_literal(n) || ', ''[a-z]'', '''', ''g'');'
INTO rec;
RETURN rec;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE
;
然后创建一个索引:
CREATE INDEX my_table_upper_name_btree
ON schema.my_table USING GIST (my_text_field);
但后来我决定重新定义函数,以删除大写字母。我创建的索引会发生什么变化?它会自己改变吗?我是否再次删除
和创建
<代码>真空[分析][完全]
(所讨论的函数与此类似,而是使用一系列相当长的替换,这些替换仍在调整中,但预计会稳定。)如果更改函数,则必须重新生成索引
create table t (i integer);
insert into t (i)
select generate_series(1, 100000);
analyze t;
返回相反整数的简单函数:
create or replace function f(i integer)
returns integer as $$
select i * -1;
$$ immutable language sql;
以及上面的索引:
create index t_i_index on t(f(i));
索引用于:
explain select * from t order by f(i);
QUERY PLAN
---------------------------------------------------------------------------
Index Scan using t_i_index on t (cost=0.00..3300.26 rows=100000 width=4)
现在,函数更改为返回整数本身:
create or replace function f(i integer)
returns integer as $$
select i;
$$ immutable language sql;
并且不再使用索引:
explain select * from t order by f(i);
QUERY PLAN
---------------------------------------------------------------
Sort (cost=11116.32..11366.32 rows=100000 width=4)
Sort Key: i
-> Seq Scan on t (cost=0.00..1443.00 rows=100000 width=4)
如果重新生成索引
reindex index t_i_index;
它再次被使用:
explain select * from t order by f(i);
QUERY PLAN
---------------------------------------------------------------------------
Index Scan using t_i_index on t (cost=0.00..4376.26 rows=100000 width=4)
IMMUTABLE
表示“不改变”或“不改变”。为了严格避免违反该规则,您必须做的是删除函数和依赖它的所有内容,然后重新创建它和使用它的索引
如果您将功能替换到位,您将对后果负责。就我个人而言,我认为PostgreSQL应该禁止或替换函数作为不可变的
函数,因为这会迫使您跳过额外的设置忽略不可变的检查,即使它可能会导致不正确的查询
配置选项
如果更改不可变函数的行为,则基于该函数的索引无效。服务器无法判断函数的行为是否已更改;您可能只是将其替换为在各个方面都具有相同行为的优化版本。因此它不会使索引失效,尽管它可能会失效,因为如果函数的行为确实不同,那么基于函数的查询可能会得到不正确的查询结果。我惊讶地发现,Postgres如此依赖其管理员的良好行为来防止索引使用的函数发生更改。我实际上认为这是非常有问题的。没有什么能阻止错误的行为,我认为这是一个设计问题,而不是用户错误。
所以我决定制作一个方便的小系统,使用事件触发器(和一点点正则表达式黑客)来执行这种强制。我认为它能很好地保持水分,但我还没有用任何高压方式对它进行测试
使用这些:
CREATE OR REPLACE FUNCTION pg_index_monitor()
RETURNS event_trigger LANGUAGE plpgsql AS $$
DECLARE
obj record;
BEGIN
FOR obj IN (
WITH
index_functions AS
(
select
unnest(regexp_matches(indexprs, '(?<=(funcid(\s)))(\d+)', 'g'))::oid as objid
, indexrelid
FROM pg_index
WHERE
indexprs IS NOT NULL
)
SELECT
*
FROM pg_event_trigger_ddl_commands()
JOIN index_functions USING (objid)
JOIN pg_class ON indexrelid = oid
where
object_type = 'function'
)
LOOP
RAISE EXCEPTION 'This function cannot be modified as it is being used by index "%".', obj.relname;
END LOOP;
END
$$
;
DROP EVENT TRIGGER IF EXISTS pg_index_monitor_trigger;
CREATE EVENT TRIGGER pg_index_monitor_trigger
ON ddl_command_end
EXECUTE FUNCTION pg_index_monitor();
然后尝试编辑该链接函数:
CREATE OR REPLACE FUNCTION test(text) RETURNS text AS $$
select 'abc'::text;
$$
LANGUAGE sql
IMMUTABLE
;
[P0001]错误:此函数无法修改,因为它正由索引“some_index”使用。
我对答案感兴趣,不管版本如何。然后需要说明-最好与您实际使用的版本一起使用。好的,这并不意外。我希望“REINDEX”也能说服规划者再次使用索引,不是吗?@Dylan Yes REINDEX有效且更简单。我已经更新了答案。服务器无法判断函数的行为是否发生了变化,但在我的示例中,当函数是内联函数时,服务器可以判断。
CREATE OR REPLACE FUNCTION test(text) RETURNS text AS $$
select 'abc'::text;
$$
LANGUAGE sql
IMMUTABLE
;