【问题标题】:Is it possible to temporarily disable an index in Postgres?是否可以暂时禁用 Postgres 中的索引?
【发布时间】:2011-09-03 00:18:50
【问题描述】:

我想暂时禁用表中的一个索引,但我找不到任何文档表明它是可能的。

原因:我有一个索引,它可能会导致与它旨在加速的任何查询无关的查询问题。这是一个新的索引,自从它被引入以来,整个系统似乎变慢了。我只是希望能够可靠地消除它作为罪魁祸首,这似乎是最简单的方法,也欢迎其他解决方案建议以及更好的问题建议。

【问题讨论】:

    标签: performance debugging postgresql indexing


    【解决方案1】:

    你可以戳系统目录来禁用索引:

    update pg_index set indisvalid = false where indexrelid = 'test_pkey'::regclass
    

    这意味着索引不会用于查询,但仍会更新。它是用于并发索引构建的标志之一。请注意,我只是做了一个快速测试,看看索引是否仍然在更新,请注意。

    【讨论】:

    【解决方案2】:
    begin;
    drop index foo_ndx;
    explain analyze select * from foo;
    rollback;
    

    我认为没有办法只禁用一个,尽管您可以在事务中执行此操作以使从中恢复非常简单。您还可以禁用 indexscan 以禁用所有索引。

    另外,请确保您在查询时使用explain analyze。

    【讨论】:

    • 谢谢。不幸的是,我的问题是我不知道哪些查询被放慢了:我安装索引的所有东西都超级活泼,只是整个系统都坏了。所以我需要在几分钟内全局禁用索引,而不仅仅是在一个事务中。
    • 给你一个赞成票,因为这是对单个查询执行此操作的正确方法。如果不是因为我的问题愚蠢的普遍性,你会解决它。
    • 使用EXPLAIN ANALYZE 的建议很明确,可以开始弄清楚发生了什么。然后你可以说,“为什么INDEX 的存在导致index_scan 从X 到Y 的时间?”
    • 如果你不知道哪些查询很慢,那就开启长时间运行语句的记录看看吧。
    • 我读过this will obtain an ACCESS EXCLUSIVE lock on foo_ndx,这对其他并发查询有何影响?他们会使用、不使用索引,还是在此事务完成之前阻塞?
    【解决方案3】:

    我已经创建(并审查了)一个函数,它可以在各种情况下执行此操作。你肯定需要小心它,但它确实有效。

    CREATE OR REPLACE PROCEDURE global.enable_indexes(
        IN schema_name TEXT
    ,   IN table_name TEXT
    ,   IN index_name TEXT
    ,   IN enable_use BOOLEAN
    ,   IN enable_updates BOOLEAN
    ,   IN skip_essentials BOOLEAN DEFAULT TRUE
    ) AS
    $$
    DECLARE
        each_record RECORD;
    BEGIN
    
    /*
    USAGE:
    
    schema_name:
    - filters down by schema name
    - if NULL then does not filter
    table_name:
    - filters down by table name (careful - not schema qualified)
    - if NULL then does not filter
    index_name:
    - filters down by index name (careful - not schema qualified)
    - if NULL then does not filter
    enable_use:
    - This SETs the index as being available for use.
    - If enable_updates is FALSE, then automatically FALSE
    enable_updates:
    - This SETs the index to be updated (which doesn't imply that it is enabled for use)
    - When this was previously FALSE for the given index, then when setting to true will also trigger a rebuild of the index
    skip_essentials:
    - When this is true, PRIMARY and UNIQUE indexes will not be included in the scope (no changes).
    - Optional
    */
    
    
    IF array_replace(ARRAY[schema_name, table_name, index_name], NULL, '') <@ ARRAY[''] THEN
        RAISE EXCEPTION 'Error: Must specify at least one of schema_name | table_name | index_name';
    END IF;
    
    IF enable_updates IS FALSE THEN
        enable_use := FALSE;
        RAISE INFO 'FYI: Because enable_updates is FALSE, then likewise enable_use must be as well';
    END IF;
    
    FOR each_record IN
        select
            indexrelid
        ,   (schemaname||'.'||indexname) as index_name
        ,   indisvalid
        ,   indisready
        ,   (schemaname||'.'||tablename) as table_name
        ,   (CASE WHEN indisready IS FALSE and enable_use IS TRUE AND enable_updates IS TRUE THEN TRUE ELSE FALSE END) as needs_rebuilding
        FROM pg_indexes, pg_index
        WHERE
            indexrelid = (schemaname||'.'||indexname)::regclass
        AND case when schema_name <> '' THEN schemaname = schema_name ELSE TRUE END
        AND case when table_name <> '' THEN tablename = table_name ELSE TRUE END
        AND case when index_name <> '' THEN indexname = index_name ELSE TRUE END
        AND case when true THEN least(indisprimary, indisunique) = FALSE ELSE TRUE END
        AND case when skip_essentials THEN least(indisprimary, indisunique) = FALSE ELSE TRUE END
    LOOP
        BEGIN
    
        RAISE INFO 'Set index % to have use % and updates %.'
            ,   each_record.index_name
            ,   (case when each_record.indisvalid AND enable_use THEN 'enabled (not changed)' WHEN NOT each_record.indisvalid AND enable_use THEN 'enabled (changed)' else 'disabled' END)
            ,   (case when each_record.indisready AND enable_updates THEN 'enabled (not changed)' WHEN NOT each_record.indisready AND enable_updates THEN 'enabled (changed)' else 'disabled' END)
        ;
    
        UPDATE pg_index
        SET
            indisvalid = enable_use
        ,   indisready = enable_updates
        WHERE
            indexrelid = each_record.indexrelid
        ;
    
        IF each_record.needs_rebuilding THEN
            RAISE INFO '... Reindexing and Analyzing %', each_record.index_name;
            EXECUTE format('REINDEX INDEX %1$s; ANALYZE %2$s;', each_record.index_name, each_record.table_name);
        END IF;
    
        COMMIT;
    
        END;
    
    END LOOP;
    
    END
    $$
    LANGUAGE plpgsql
    ;
    

    【讨论】:

    • 该死的程序!我有\d tags 现在没有在tags 上显示索引(这是在时间之前运行call enable_indexes('', 'tags', '', true, true, false); 然后call enable_indexes('', 'tags', '', false, false, false);。我也有f 作为pg_catalog.pg_class.relhasindex 的值@ 987654328@。我有更新了relhasindex = 't',但tags 上的索引仍未显示。现在我正在运行reindex table tags。
    • reindex table tags; 显然解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2012-05-10
    相关资源
    最近更新 更多