如何在 Postgres 中删除表的所有索引?

Posted

技术标签:

【中文标题】如何在 Postgres 中删除表的所有索引?【英文标题】:How can I drop all indexes of a table in Postgres? 【发布时间】:2016-03-04 18:50:53 【问题描述】:

我一直遇到这个问题:我在一个表上有 20 个索引,我需要删除这些索引才能进行测试。删除表并不会删除所有这些元数据。

似乎没有通配符drop index ix_table_* 或任何有用的命令。您可以编写一些围绕 psql 的 bash 循环。 一定有更好的东西!想法?

【问题讨论】:

***.com/a/6777904/3961156 当您说“所有索引”时,您的意思是包括通过隐式创建索引实现的约束(UNIQUEPKEXCLUDE)? 不,在这种情况下只是索引。 【参考方案1】:

假设您只想删除普通索引:

DO
$do$
DECLARE
   _sql text;
BEGIN   
   SELECT 'DROP INDEX ' || string_agg(indexrelid::regclass::text, ', ')
   FROM   pg_index  i
   LEFT   JOIN pg_depend d ON d.objid = i.indexrelid
                          AND d.deptype = 'i'
   WHERE  i.indrelid = 'table_name'::regclass  -- possibly schema-qualified
   AND    d.objid IS NULL                      -- no internal dependency
   INTO   _sql;
   
   IF _sql IS NOT NULL THEN                    -- only if index(es) found
     EXECUTE _sql;
   END IF;
END
$do$;

不涉及作为约束的实现细节创建的索引(UNIQUEPKEXCLUDE)。The documentation:

DEPENDENCY_INTERNAL (i)

依赖对象是作为被引用对象创建的一部分而创建的 对象,实际上只是其内部实现的一部分。

您可以将其包装在一个函数中以重复执行。 相关:

Table name as a PostgreSQL function parameter

相关:

DROP FUNCTION without knowing the number/type of parameters?

旁白:这是个误会:

删除表并不会删除所有这些元数据。

删除表总是级联到表上的所有索引。

【讨论】:

您知道为什么删除表不会级联到索引吗?因为它没有。表和索引是由我使用 sql alchemy 声明性基类和 mixin 类生成的——这对我来说仍然是一个黑盒子。 @Erin:你确定,在不同的架构中没有第二个同名表吗? 花了一段时间才明白这个查询的输入是'tbl' @BenjaminCrouzier:我改成'your_table_name_here' 更清楚了。 为了只清除用户表中的索引,使用这个条件:where not indrelid::regclass::varchar like 'pg_%'【参考方案2】:

这就是我从 postgres 中删除所有索引的方式,不包括所有 pkey。

CREATE OR REPLACE FUNCTION drop_all_indexes() RETURNS INTEGER AS $$
DECLARE
  i RECORD;
BEGIN
  FOR i IN 
    (SELECT relname FROM pg_class
       -- exclude all pkey, exclude system catalog which starts with 'pg_'
      WHERE relkind = 'i' AND relname NOT LIKE '%_pkey%' AND relname NOT LIKE 'pg_%')
  LOOP
    -- RAISE INFO 'DROPING INDEX: %', i.relname;
    EXECUTE 'DROP INDEX ' || i.relname;
  END LOOP;
RETURN 1;
END;
$$ LANGUAGE plpgsql;

执行:

SELECT drop_all_indexes();

在实际执行'DROP INDEX xxx'之前,我会使用'--'注释掉'EXECUTE ...'行,并取消注释'RAISE INFO'行,使用'select func_name();'运行它并仔细检查我没有放弃我不应该放弃的东西。

对于我们的应用程序,我们在一个文件 app.sql 中包含所有架构语句,包括创建索引。在整个项目投入生产之前,我们要清理所有历史创建的索引,然后使用以下命令重新创建它们:

psql -f /path/to/app.sql

希望这会有所帮助。

【讨论】:

这个解决方案非常适合我。非常感谢!我需要做的只是稍微更改选择查询以满足我的要求。 RAISE INFO 的想法为我节省了很多时间。【参考方案3】:

下面的查询会删除所有 与任何约束(主键、唯一键)相关的用户索引

SELECT
    format('DROP INDEX %I.%I;', n.nspname, c_ind.relname)
  FROM pg_index ind
  JOIN pg_class c_ind ON c_ind.oid = ind.indexrelid
  JOIN pg_namespace n ON n.oid = c_ind.relnamespace
  LEFT JOIN pg_constraint cons ON cons.conindid = ind.indexrelid
  WHERE
    n.nspname NOT IN ('pg_catalog','information_schema') AND 
    n.nspname !~ '^pg_toast'::TEXT AND
    cons.oid IS NULL

你可以使用psql的\gexec元命令特性来执行语句

【讨论】:

ps。如果有帮助,这里有一些类似的删除约束:SELECT format ('ALTER TABLE %I.%I DROP CONSTRAINT %I;', nsp.nspname, rel.relname, con.conname) FROM pg_catalog.pg_constraint con INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace WHERE nsp.nspname = 'cam' order by con.conname -- hacky way to ensure FKs come before PKs

以上是关于如何在 Postgres 中删除表的所有索引?的主要内容,如果未能解决你的问题,请参考以下文章

在 postgres 中更新具有大量删除的表的主键序列

如何在 postgres 中删除特定模式中的每个表?

如何从命令行重新索引 Postgres 9.1.3

如何删除两个大表的析取行?

如何列出为 postgres 中的表创建的索引

如果用户有依赖对象,如何在 postgres 中删除用户