如果索引不存在则创建索引

Gui*_*doS 74 postgresql index plpgsql functions postgresql-8.4

我正在开发一个函数,如果索引不存在,它允许我添加索引。我遇到了无法获得要比较的索引列表的问题。有什么想法吗?

这与使用此代码解决的列创建问题类似:https :
//stackoverflow.com/a/12603892/368511

Erw*_*ter 117

PostgreSQL 中的索引名称

  • 索引名称在单个数据库模式中是唯一的。
  • 索引名称不能与同一模式中的任何其他索引、(外部)表、(物化)视图、序列或用户定义的复合类型相同。
  • 同一架构中的两个表不能具有相同名称的索引。(符合逻辑。)

如果您不关心索引的名称,请让 Postgres 自动命名它:

CREATE INDEX ON tbl1 (col1);
Run Code Online (Sandbox Code Playgroud)

与(几乎)相同:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);
Run Code Online (Sandbox Code Playgroud)

除了 Postgres 将避免命名冲突并自动选择下一个免费名称:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...
Run Code Online (Sandbox Code Playgroud)

就试一试吧。但是,很明显,您希望创建多个冗余索引。所以盲目地创建一个新的不是一个好主意。

测试是否存在

Postgres 9.5 或更新版本

现在可用:

CREATE INDEX IF NOT EXISTS ...
Run Code Online (Sandbox Code Playgroud)

也适用于CREATE INDEX CONCURRENTLY IF NOT EXISTS.

但是,手册警告

请注意,不能保证现有索引与已创建的索引相同。

这是对对象名称的简单检查。(也适用于以下旧版本的变体。)
要在同一个表中查找相同列的现有索引:

SELECT pg_get_indexdef(indexrelid)
FROM   pg_index
WHERE  indrelid = 'public.big'::regclass
AND   (indkey::int2[])[:] = ARRAY (
   SELECT attnum
   FROM   unnest('{usr_id, created_at}'::text[]) WITH ORDINALITY i(attname, ord)
   JOIN  (
      SELECT attname, attnum
      FROM   pg_attribute
      WHERE  attrelid = 'public.big'::regclass
      ) a USING (attname)
   ORDER BY ord
   );
Run Code Online (Sandbox Code Playgroud)

限制:

  • 仅适用于列,不适用于其他索引表达式。
  • 还报告部分索引(带WHERE子句)和覆盖索引(带INCLUDE子句)。
  • 报告任何类型的索引,而不仅仅是 B 树索引。

在继续之前研究结果(如果有),或根据您的需要优化查询......

进一步阅读:

Postgres 9.4

您可以使用新函数to_regclass()进行检查而不抛出异常:

DO
$$
BEGIN
   IF to_regclass('myschema.mytable_mycolumn_idx') IS NULL THEN
      CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
   END IF;

END
$$;
Run Code Online (Sandbox Code Playgroud)

如果该名称的索引(或另一个对象)不存在,则返回 NULL。看:

这不适用于CREATE INDEX CONCURRENTLY,因为该变体不能包含在外部事务中。请参阅下面@Gregory 的评论

Postgres 9.3 或更高版本

将模式限定名称转换为regclass

SELECT 'myschema.myname'::regclass;
Run Code Online (Sandbox Code Playgroud)

如果它抛出异常,则该名称是空闲的。
或者,要在不抛出异常的情况下进行测试,请使用以下DO语句:

DO
$$
BEGIN
   IF NOT EXISTS (
      SELECT
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relname = 'mytable_mycolumn_idx'
      AND    n.nspname = 'myschema'
   ) THEN
    
        CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
    END IF;
END
$$;
Run Code Online (Sandbox Code Playgroud)

DO语句是在 Postgres 9.0 中引入的。在早期版本中,您必须创建一个函数来执行相同的操作。手册中有
详细介绍。手册中 关于索引的基础知识。pg_class

  • 虽然是一个很好的答案,但请注意,您不能以这种方式添加索引 `CONCURRENTLY`。您将收到“错误:无法从函数或多命令字符串执行 CREATE INDEX CONCURRENTLY”。 (7认同)