Files
backend_v2/db/migrations/2026-09-22-03-entity-key-unique.sql
toom1996 d15d2a4701 update
2026-09-28 10:52:50 +08:00

51 lines
2.9 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 实体键唯一索引:单表发布模型下「一个实体一行」的结构性保证。
--
-- 为什么必须有:旧流程靠晋升时的实体键 upsert 把同一实体的多条草稿并成一行(自愈)。
-- 单表之后没有 upsert 阶段,只剩入库时的「先查后插」;一次瞬时读失败或多实例并发,
-- 就会留下两行,且两行都会通过审核进入公开视图 —— 前台出现重复内容。
--
-- 部分索引(WHERE is_deleted = 0):仅约束活着行,保证「同一实体至多一行活着」。
-- 注:入库服务层 RunwayEntityState / StreetSnapEntityState 现已**不再**以 is_deleted = 0 过滤,
-- 软删实体也会被查到并由 worker 跳过重爬(「删除即永久」)。本索引仍保持部分索引是为了
-- 兼容存量「软删行同键共存」的数据、避免建全量唯一索引时因历史重复而失败;结构性唯一性靠它兜底,
-- 行为上的「删除即永久」由服务层查重保证。
-- 建索引前先体检:有重复则中止,避免索引创建失败留下半成品状态。
DO $$
DECLARE dup int;
BEGIN
SELECT count(*) INTO dup FROM (
SELECT brand_id, season_code, collection_type
FROM brand_runways WHERE is_deleted = 0
GROUP BY 1, 2, 3 HAVING count(*) > 1
) t;
IF dup > 0 THEN
RAISE EXCEPTION 'brand_runways 有 % 组重复实体键,请先人工合并再加唯一索引', dup;
END IF;
-- 口径已随任务 3c 的实体键细化同步为 (city, year, title):否则本文件在「同城同年多专题」
-- 的合法数据上不再幂等(重复执行会误报重复而中止)。
SELECT count(*) INTO dup FROM (
SELECT city, year, COALESCE(title, '')
FROM street_snaps WHERE is_deleted = 0
GROUP BY 1, 2, 3 HAVING count(*) > 1
) t;
IF dup > 0 THEN
RAISE EXCEPTION 'street_snaps 有 % 组重复实体键,请先人工合并再加唯一索引', dup;
END IF;
END $$;
CREATE UNIQUE INDEX IF NOT EXISTS uq_br_entity
ON brand_runways (brand_id, season_code, collection_type) WHERE is_deleted = 0;
-- 索引表达式必须与上面的体检、以及 StreetSnapEntityState 的查重口径**逐字一致**:
-- (city, year, COALESCE(title, ''))。早期版本这里误建成 (city, year) —— 比体检更窄,
-- 于是体检放行「同城同年不同专题」的合法数据后,建索引才抛原生 23505
-- (could not create unique index ... duplicate key)。COALESCE(title, '') 的取舍见 2026-09-22-04。
--
-- ⚠️ CREATE UNIQUE INDEX IF NOT EXISTS 只检查**索引名**是否存在:若库里已有一个同名的
-- 旧 (city, year) 索引,本句会静默跳过、留下错误结构(这正是它一度掩盖问题的原因)。
-- 纠正这类存量库由 2026-09-22-04 承担;全新库 / 重复执行由本文件承载最终表达式。
CREATE UNIQUE INDEX IF NOT EXISTS uq_ss_entity
ON street_snaps (city, year, COALESCE(title, '')) WHERE is_deleted = 0;