为什么删除索引会出现不一致的行为?

后端开发 2026-07-11

我遇到了一个错误,提示无法删除索引,因为它不存在,这个错误出现在代码样本B 上,而不是样本A。两个代码样本有些相似。

以下是示例(在PostgreSQL 12.0数据库服务器上运行):

Sample A

create schema if not exists schema1;

CREATE TABLE IF NOT EXISTS "schema1"."nobleman" (
  "name" TEXT,
  "age" DOUBLE PRECISION,
  "city" TEXT,
  "id" text NOT NULL DEFAULT uuid_generate_v4(),
  PRIMARY KEY("id")
);

CREATE INDEX "name_appln_index" ON "schema1"."nobleman" ("name", "age");

------

create schema if not exists schema2;

CREATE TABLE IF NOT EXISTS "schema2"."nobleman" (
  "name" TEXT,
  "age" DOUBLE PRECISION,
  "city" TEXT,
  "id" text NOT NULL DEFAULT uuid_generate_v4(),
  PRIMARY KEY("id")
);

CREATE INDEX "name_appln_index" ON "schema2"."nobleman" ("name", "age");

drop index "name_appln_index";

Sample B(在不同的数据库中运行)

CREATE SCHEMA IF NOT EXISTS schema1;

CREATE TABLE IF NOT EXISTS "schema1"."transformation" (
  "name" TEXT,
  "application" TEXT,
  "type" TEXT,
  "specs" TEXT,
  "sourceid" text[] DEFAULT null,
  "id" text NOT NULL,
  PRIMARY KEY("id")
);

CREATE  UNIQUE  INDEX "name_appln_index" 
    ON "schema1"."transformation" ( "name" ASC, "application" ASC);

----

CREATE SCHEMA IF NOT EXISTS schema2;

CREATE TABLE IF NOT EXISTS "schema2"."transformation" (
  "name" TEXT,
  "application" TEXT,
  "type" TEXT,
  "specs" TEXT,
  "sourceid" text[] DEFAULT null,
  "id" text NOT NULL,
  PRIMARY KEY("id")
);

CREATE  UNIQUE  INDEX "name_appln_index" 
    ON "schema2"."transformation" ( "name" ASC, "application" ASC);

ALTER TABLE "schema2"."transformation" ADD COLUMN "_tenantid" VARCHAR(256);

CREATE UNIQUE INDEX "name_appln_tnt_index" ON "schema2"."transformation" ("name" ASC, "application" ASC, "_tenantid" ASC);

drop index "name_appln_index";

于是,接下来就是一个谜题。在 Sample A 中的DROP INDEX成功,并删除与相应表在 schema2 相关联的索引。(关于此的查询/响应在此未显示。)

对于 Sample B,DROP INDEX失败并报错。我也在PostgreSQL 17.x的服务器上进行了测试。

为什么对样本B 会报错?

解决方案

你的两个代码示例 在任何标准配置的PostgreSQL版本上都会导致以下错误:

ERROR:  index "name_appln_index" does not exist

原因是 schema1schema2 都不在 search_path 的模式中,因此如果不在限定符中包含该模式,便找不到该索引。

如果第一个代码示例对你有效并且在 schema2 中删除了该索引,那么参数 search_path 必须被设置为包含 schema2——但那样的话,第二个代码示例也不会再导致错误。

我就让你自己去找出两种情况下参数为何设置不同吧,但我也可以再提供一些背景知识。它可能会让人困惑:这条语句可以成功:

CREATE  UNIQUE  INDEX "name_appln_index" 
    ON "schema2"."transformation" ( "name" ASC, "application" ASC);

但这条语句失败:

drop index "name_appln_index";

毕竟两条语句都在未对索引限定模式的情况下使用它。如果你在第一条语句中尝试写 CREATE INDEX schema2.name.appln_index,甚至会造成语法错误!

解释是:索引是 始终 与其表位于同一个模式中,因此通过创建索引 ON schema2.transformation,你也会在 schema2 中自动创建它,而且它不可能出现在其他地方。但在 DROP INDEX 语句中没有提及表,因此如果你想使用不在你 search_path 的模式中的模式,你可以(也必须)添加模式名。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章