Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Function 替换索引中使用的函数_Function_Postgresql_Indexing_Plpgsql - Fatal编程技术网

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
;