【问题标题】:How to delete duplicate indexes如何删除重复的索引
【发布时间】:2020-02-23 07:45:33
【问题描述】:

我正在寻找一个自动删除重复索引的脚本,而不是手动逐个检查和删除表。

是否可以通过SQL代码或PL/pgSQL代码删除?

脚本正在使用查找重复索引:

SELECT
    indrelid::regclass AS TableName
    ,array_agg(indexrelid::regclass) AS Indexes
FROM pg_index 
GROUP BY 
    indrelid
    ,indkey 
HAVING COUNT(*) > 1;

【问题讨论】:

  • 自动删除数据库对象基本上是个坏主意。这些物体的存在,或者在某个时候确实存在,是有目的的。对于您要丢弃的每个对象,您需要询问:该目的是否仍然有效。如果是,那么您有替代解决方案吗?您的提议似乎属于“我想更改数据库,但我不想花时间去理解它”的类别。查看并考虑@jjanes 给出的警告。它会做你所要求的,但它会做你想做的。它们很可能是非常不同的东西。

标签: sql postgresql indexing


【解决方案1】:

有可能,但似乎不明智。

psql 中,您可以使用 \gexec 运行任意 SQL 查询/语句,这些查询/语句由另一个查询的结果组成。在 pl/pgsql 中,您可以使用 dynamic queries 来执行您想要从其他查询的结果组成的任何语句。

但是您的查询会将不同的索引标识为重复项。例如,同一列上的 btree 索引和 gin_trgm_ops 索引并不是真正的重复,因为它们支持不同的操作,盲目地删除一个可能是错误的。此外,indkey 对于任何表达式都包含 0,因此它会将不同表达式上的表达式索引标识为相同。

因此,虽然您可以在 psql 中执行此操作以删除重复数组中除第一次出现之外的所有重复项,但您实际上可能不应该:

select 'drop index '||unnest(indexes[2:]) from (SELECT
    indrelid::regclass AS TableName
    ,array_agg(indexrelid::regclass) AS Indexes
FROM pg_index 
GROUP BY 
    indrelid
    ,indkey 
HAVING COUNT(*) > 1) foo \gexec

您可以通过按索引的定义进行分组来优化它,在使用正则表达式剥离索引名称之后,以排除将并非真正重复的索引分组在一起。

SELECT              
    indrelid::regclass AS TableName
    ,array_agg(indexrelid::regclass) AS Indexes
FROM pg_index 
GROUP BY 
    indrelid
    ,indkey 
    ,regexp_replace(pg_get_indexdef(pg_index.indexrelid),'^CREATE (UNIQUE )?INDEX (\w+|".+")','')  
HAVING COUNT(*) > 1

我不保证正则表达式对所有恶意制作的索引名称都是安全的。它还将唯一索引和非唯一索引混为一谈——大概您实际上想将它们混为一谈,然后确保其中一个唯一索引是幸存下来的索引。为了完整起见,您可能还想对 indisvalid 做一些事情。

【讨论】:

    猜你喜欢
    • 2019-02-22
    • 2020-11-22
    • 2018-01-04
    • 2014-07-06
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-07
    相关资源
    最近更新 更多