postgres 在制作索引时如何使用模式搜索路径?

jor*_*npg 5 postgresql index

使用 Postgres 9.1.4 和 PostGIS 1.5,作为 Rails 3.2.x 应用程序的一部分。

我有一个包含模式 A 和 B 的数据库,模式 A 为空,模式 B 包含表 foo 和 bar,在非 PK 字段中的每个表上都有索引,例如email.

如果我用 设置我的模式搜索路径SET search_path TO A,B;,那么我可以运行:

CREATE TABLE foo (...);
Run Code Online (Sandbox Code Playgroud)

并在模式 A 中创建表 foo。但以下迁移失败:

CREATE TABLE bar (...);
CREATE UNIQUE INDEX index_bar_on_email ON bar USING btree (email);
Run Code Online (Sandbox Code Playgroud)

Index name 'index_bar_on_email' on table 'bar' already exists
Run Code Online (Sandbox Code Playgroud)

这表明create tablecreate unique index处理搜索路径的方式不同。有没有办法哄 PG 在模式 A 中创建索引?

更新

这个问题似乎与 Rails 如何与 Postgres 接口有关。创建 Users 表后,在 Rails 尝试创建索引之前运行以下查询:

SELECT DISTINCT i.relname, d.indisunique, d.indkey, t.oid, am.amname
 FROM pg_class t, pg_class i, pg_index d, pg_am am
 WHERE i.relkind = 'i'
 AND d.indexrelid = i.oid
 AND d.indisprimary = 'f'
 AND t.oid = d.indrelid
 AND t.relname = 'users'
 AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN ('B','A') )
 AND i.relam = am.oid
 ORDER BY i.relname

SELECT a.attnum, a.attname, t.typname
 FROM pg_attribute a, pg_type t
 WHERE a.attrelid = 311384
 AND a.attnum IN (2)
 AND a.atttypid = t.oid
Run Code Online (Sandbox Code Playgroud)

基于其中一个或两个的结果,这似乎是与模式无关的查询,我猜测非空返回告诉 Rails 这个索引已经存在,所以它甚至不费心去尝试。

现在,我只想重命名索引,但这可能是 Rails Postgres 适配器中的一个错误。

Cra*_*ger 6

鉴于以下设置:

regress=> CREATE SCHEMA A;
CREATE SCHEMA
regress=> CREATE SCHEMA B;
CREATE SCHEMA
regress=> SET search_path = B, public;
SET
regress=> CREATE TABLE bar(email text);
CREATE TABLE
CREATE UNIQUE INDEX index_bar_on_email ON bar USING btree (email);
CREATE INDEX
Run Code Online (Sandbox Code Playgroud)

我无法重现您在 PostgreSQL 9.2 中报告的问题:

regress=> SET search_path = A, B;
SET
regress=> CREATE TABLE bar(email text);
CREATE TABLE
regress=> CREATE UNIQUE INDEX index_bar_on_email ON bar USING btree (email);
CREATE INDEX
Run Code Online (Sandbox Code Playgroud)

但是,与使用 相比search_path,使用显式模式限定更安全。例如,我将上面的内容重写为:

regress=> RESET search_path;
RESET
regress=> SHOW search_path ;
  search_path   
----------------
 "$user",public
(1 row)

CREATE TABLE B.bar(email text);
CREATE UNIQUE INDEX b.index_bar_on_email ON b.bar USING btree (email);
CREATE TABLE A.bar(email text);
CREATE UNIQUE INDEX index_bar_on_email ON A.bar USING btree (email);
Run Code Online (Sandbox Code Playgroud)

索引是在其关联表的架构中自动创建的;看:

regress=> \di B.
                  List of relations
 Schema |        Name        | Type  | Owner | Table 
--------+--------------------+-------+-------+-------
 b      | index_bar_on_email | index | craig | bar
(1 row)

regress=> \di A.
                  List of relations
 Schema |        Name        | Type  | Owner | Table 
--------+--------------------+-------+-------+-------
 a      | index_bar_on_email | index | craig | bar
(1 row)
Run Code Online (Sandbox Code Playgroud)

根据问题变化更新:

是的,您所展示的确实看起来像是 Rails 适配器问题。它正在检查索引是否存在于任何架构中。应该检查 中给定名称的第一个表是否search_path具有命名索引。

我会以不同的方式编写查询。我会pg_class完全放弃加入,而是使用演员表来为我regclass处理search_path解决方案。我会使用生成的 oid 来搜索索引。比较原始,然后更新,如下。请注意,更新的查询确实需要search_path首先设置。

regress=> SELECT DISTINCT i.relname, d.indisunique, d.indkey, t.oid, am.amname
 FROM pg_class t, pg_class i, pg_index d, pg_am am
 WHERE i.relkind = 'i'
 AND d.indexrelid = i.oid
 AND d.indisprimary = 'f'
 AND t.oid = d.indrelid
 AND t.relname = 'bar'
 AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN ('b','a') )
 AND i.relam = am.oid
 ORDER BY i.relname
;
      relname       | indisunique | indkey |  oid  | amname 
--------------------+-------------+--------+-------+--------
 index_bar_on_email | t           | 1      | 28585 | btree
 index_bar_on_email | t           | 1      | 28592 | btree
(2 rows)

regress=> SELECT DISTINCT i.relname, d.indisunique, d.indkey, 'bar'::regclass::oid, am.amname
 FROM pg_class i, pg_index d, pg_am am
 WHERE i.relkind = 'i'
 AND d.indexrelid = i.oid
 AND d.indisprimary = 'f'
 AND 'bar'::regclass = d.indrelid
 AND i.relam = am.oid
 ORDER BY i.relname                                                              
;
      relname       | indisunique | indkey | regclass | amname 
--------------------+-------------+--------+----------+--------
 index_bar_on_email | t           | 1      | 28585    | btree
(1 row)
Run Code Online (Sandbox Code Playgroud)