kev*_*jom 4 sql database postgresql psql
我们有一个表foo,其架构如下所示
hi=# \d foo
Table "public.foo"
Column | Type | Modifiers
------------+--------------------------+------------------------
id | uuid | not null
bar_id | uuid | not null
hi | character varying(128) | not null
yo | character varying(4000) |
updated_at | timestamp with time zone | not null default now()
created_at | timestamp with time zone | not null default now()
Indexes:
"foo$pk" PRIMARY KEY, btree (id)
"foo$uk" UNIQUE CONSTRAINT, btree (bar_id, hi, yo)
Foreign-key constraints:
"foo$bar$fk" FOREIGN KEY (bar_id) REFERENCES bar(id)
Run Code Online (Sandbox Code Playgroud)
我们里面有大约100M的记录,正如你所看到的,这个表有一个约束,我们想要做的是由于业务原因用约束UNIQUE替换它。EXCLUDE所以我们想要做出的改变如下所示
ALTER TABLE foo ADD CONSTRAINT "foo$one$uk"
EXCLUDE ( bar_id WITH =, hi WITH =, yo WITH =) WHERE (hi = 'Tom') DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE foo ADD CONSTRAINT "foo$two$uk"
EXCLUDE ( bar_id WITH =, hi WITH =) WHERE (hi = 'Lisa') DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE foo DROP CONSTRAINT IF EXISTS "foo$uk";
Run Code Online (Sandbox Code Playgroud)
证据表明,在具有(m3.large + 300GB 通用 SSD)的 AWS RDS 实例上运行这 3 条语句大约需要 12 小时才能完成。但我们也注意到,运行第一个语句几乎消耗了所有时间,第二个语句很快(几分钟内),第三个语句立即返回。所以我想知道幕后发生了什么,为什么会发生这种情况?
每当添加约束时,都应检查现有数据以确保不存在违反现有约束的情况。
排除约束描述如下,参见 5.3.6:
确保使用指定的运算符在指定的列或表达式上比较任意两行。
因此,根据 的行数,您可能对 1 亿行hi = 'Tom'执行 O(n 2 ) 操作。是的,这需要一段时间。
另请注意:
添加排除约束将自动创建约束声明中指定类型的索引。
这会产生一些开销,但不如比较每对现有行那么多。
至于第二个约束,我不确定,但有两种可能导致它运行得更快。
要么行数显着减少WHERE hi = 'Lisa',要么引擎可以利用已检查前一个约束的事实中的信息,以便更有效地检查新约束。
显然,第三个更改(删除约束)不需要检查任何内容。
您可以选择在创建约束检查时禁用它。(我不知道 PostgreSQL 是否支持。)