PostgreSQL 中相似的 DROP INDEX 语句为何结果不同?
结论
DROP INDEX "name_appln_index" 没有指定 schema。PostgreSQL 会根据当前会话的 search_path 查找这个未限定名称。如果目标索引所在的 schema 不在搜索路径中,或者搜索路径先匹配到其他 schema,就可能找不到目标索引,或操作到非预期的索引。
即使 CREATE INDEX 使用了带 schema 的表名,索引也会创建在该表所属的 schema 中。因此,两组脚本里的同名索引分别属于 schema1 和 schema2。不同 schema 中可以有同名索引,但未限定的 DROP INDEX 每次只解析一个名称,不会自动删除各个 schema 中的所有同名索引。
为什么 Sample A 和 Sample B 结果不同
Sample A 在 schema1.nobleman 和 schema2.nobleman 上分别创建了名为 name_appln_index 的索引,之后执行:
DROP INDEX "name_appln_index";
Sample B 也在两个 schema 中创建了名为 name_appln_index 的索引。这些是通过 CREATE UNIQUE INDEX 创建的独立索引。UNIQUE 和索引列上的 ASC 都不会改变 DROP INDEX 对 schema 名称的解析规则。
两组脚本在不同数据库中执行,数据库或会话的 search_path 可能不同。这可能导致未限定名称在一组环境中可以解析,在另一组环境中却找不到。仅凭脚本无法确认两边实际的 search_path,也无法判断报错对应哪个 schema 中的索引。
确认索引所在 schema
在发生错误的同一数据库和会话中检查搜索路径:
SHOW search_path;
SELECT current_schemas(true);
再查询索引在两个 schema 中的实际位置:
SELECT schemaname, tablename, indexname
FROM pg_indexes
WHERE indexname = 'name_appln_index'
ORDER BY schemaname, tablename;
查询结果可以确认索引是否存在,以及它属于 schema1 还是 schema2。
按 schema 删除目标索引
确认目标后,使用带 schema 的名称。例如,要删除 schema2 中的索引:
DROP INDEX "schema2"."name_appln_index";
要删除 schema1 中的同名索引,则写为:
DROP INDEX "schema1"."name_appln_index";
如果索引不存在时不想报错,可以使用 IF EXISTS:
DROP INDEX IF EXISTS "schema2"."name_appln_index";
这条语句仍然只针对指定 schema 中的索引,不会删除其他 schema 中的同名索引。如果实际错误信息并非“索引不存在”,应结合完整错误文本进一步判断。
备注:内容仅供参考。
