如何在 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 当您说“所有索引”时,您的意思是包括通过隐式创建索引实现的约束(UNIQUE
、PK
、EXCLUDE
)?
不,在这种情况下只是索引。
【参考方案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$;
不涉及作为约束的实现细节创建的索引(UNIQUE
、PK
、EXCLUDE
)。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 中删除表的所有索引?的主要内容,如果未能解决你的问题,请参考以下文章