为什么删除索引会出现不一致的行为?
我遇到了一个错误,提示无法删除索引,因为它不存在,这个错误出现在代码样本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
原因是 schema1 与 schema2 都不在 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 的模式中的模式,你可以(也必须)添加模式名。