ソースを参照

docs(乐收赢): 两份商户号 SQL 的注释按实测订正 —— 那条偏索引已经不在了

两份脚本都是**只读诊断/一次性 DDL**,本次改动**不含任何可执行语句的变化**(下面有量法)。
改的是注释里几处**已经不成立的说法**:

- `lsy-merchant-multi-per-tenant.sql`:原写「本脚本尚未执行」。实测 `pay_lsy_merchant`
  上带 unique 的索引只剩 3 条(pkey / uk_lsy_merchant_mch_no / uk_lsy_merchant_tenant_ent),
  `uk_lsy_merchant_tenant_level` **已经不在库上** ⇒ 本脚本的 DROP 已生效。
  ★ 读数与推断分开写:**「索引已不存在」是读数;「是谁、什么时候执行的」没量到。**
  可确定的只有「当天早些时候它还在」—— 那次 500 的报错原文里点了它的名。
  再跑一次本脚本是无害空操作(`DROP INDEX IF EXISTS`)。
- `lsy-merchant-slot-diag.sql`:①④ 两处把「槽位」当约束的说法改成历史名词
  (去企业化后一个租户允许多个商户号,②读到多行**不是异常**);⑤ 的期望从
  「恰好 3 行且第 1 条带 WHERE」改成逐条点名那 3 条。①的 CASE 标签
  `'★ 租户级(占着 uk_...)'` → `'无企业 ID'`(这是唯一一处非注释变化,只影响诊断输出的一列文字)。

为什么要提交:这两份文件此前**只存在于工作区**。本仓已发生过「做好过、后面又没了」
(见记忆 `uncommitted-deliverables-vanish`),未提交的交付不算交付。

量法(证明「不含可执行语句的变化」):把两份文件分别按「去掉空行与 `--` 开头的行」后
逐行比对 HEAD 与工作区 ——
- `lsy-merchant-multi-per-tenant.sql`:非注释行各 1 行,`identical=True`;
- `lsy-merchant-slot-diag.sql`:非注释行各 39 行,差异**只有**上面那句 CASE 标签。

不涉及 Java 代码、不涉及库变更;**不需要重新部署**(脚本是给人手工执行的,应用不读它们)。
alphaH 2 週間 前
親
コミット
a957ab8ce6

+ 8 - 1
java/src/main/resources/db/lsy-merchant-multi-per-tenant.sql

@@ -1,7 +1,14 @@
 -- 一个租户允许多个乐收赢商户号(2026-09-30 去企业化收尾)
 -- 手工执行: psycopg2 / psql 连接 payment_platform_java 库
 --
--- 【本脚本尚未执行】执行由用户做。
+-- ★ 2026-09-30 实测:**那条索引已经不在库上了**,本脚本的 DROP 已生效。
+--   读数:`SELECT indexname, indexdef FROM pg_indexes WHERE tablename='pay_lsy_merchant'
+--          AND indexdef ILIKE '%unique%'` 只回 3 行 —— pay_lsy_merchant_pkey /
+--          uk_lsy_merchant_mch_no / uk_lsy_merchant_tenant_ent,没有
+--          uk_lsy_merchant_tenant_level。(该过滤条件是有效的:它确实捞出了两个 uk_*。)
+--   ★ 声明与推断分开:**「索引已不存在」是读数;「是谁、什么时候执行的」没有量到。**
+--     可确定的是它当天早些时候还在 —— 那次 500 的报错原文里点了它的名。
+--   再跑一次本脚本是**无害的空操作**(DROP INDEX IF EXISTS)。
 --
 -- ── 背景 ─────────────────────────────────────────────────────────────
 -- db/lsy-tenant-level.sql 在 2026-09-22 建了这条索引:

+ 23 - 13
java/src/main/resources/db/lsy-merchant-slot-diag.sql

@@ -7,24 +7,30 @@
 -- 【怎么跑】五条 SELECT 相互独立,可以整段跑,也可以一条一条跑。
 --   没有 psql 元命令(\echo 之类),图形客户端 / psycopg2 都能直接执行。
 --
--- 背景:pay_lsy_merchant 上三条唯一约束都由数据库把关:
---   uk_lsy_merchant_tenant_level  UNIQUE(tenant_id) WHERE enterprise_id IS NULL   ← 偏索引
+-- 背景:pay_lsy_merchant 上两条唯一约束由数据库把关:
 --   uk_lsy_merchant_tenant_ent    UNIQUE(tenant_id, enterprise_id)
 --   uk_lsy_merchant_mch_no        UNIQUE(mch_no)                                  ← 全局,不带 tenant_id
--- (代码侧的预检只负责把冲突说清楚,不负责挡住 —— 挡住的是这三条。见
+-- (代码侧的预检只负责把冲突说清楚,不负责挡住 —— 挡住的是这两条。见
 --   LsyMerchantService#rejectUniqueConflicts 的 javadoc。)
 --
+-- ★ 2026-09-30 补记:原先还有第三条 uk_lsy_merchant_tenant_level
+--   (UNIQUE(tenant_id) WHERE enterprise_id IS NULL),**已经被删掉**
+--   (见 db/lsy-merchant-multi-per-tenant.sql)—— 去企业化之后一个租户允许有多个商户号。
+--   ⇒ 本脚本 ①②④ 里那个「槽位」的说法现在是**历史名词**,不是约束:
+--     同一个租户出现多条 enterprise_id IS NULL 的行**是合法的**,② 读到多行不是异常。
+--   ③⑤ 那两条与它无关,仍然有效。
+--
 -- 想查别的租户:把下面所有的 2 换成目标 tenant_id 即可。
 
 
 -- ============================================================================
--- ① 租户 2 的全部商户号登记行(租户级排在前面)
---    看这一条就够判断「谁占着槽位、我删掉的是哪一行」
+-- ① 租户 2 的全部商户号登记行(enterprise_id 为空的行排在前面)
+--    看这一条就够判断「我删掉的是哪一行」
 -- ============================================================================
 SELECT id,
        tenant_id,
        enterprise_id,
-       CASE WHEN enterprise_id IS NULL THEN '★ 租户级(占着 uk_lsy_merchant_tenant_level)'
+       CASE WHEN enterprise_id IS NULL THEN '无企业 ID'
             ELSE '企业级'
        END AS "槽位",
        mch_no,
@@ -40,8 +46,9 @@ SELECT id,
 
 
 -- ============================================================================
--- ② 谁占着租户 2 的租户级槽位(应当恰好 0 或 1 行)
---    新增「企业 ID 留空」的行时,撞的就是这一行
+-- ② 租户 2 里 enterprise_id 为空的行
+--    ★ 2026-09-30 之前这里「应当恰好 0 或 1 行」(偏索引拦着);索引已删,
+--      **多行是合法的** —— 一个租户本来就允许多个商户号。
 -- ============================================================================
 SELECT id, tenant_id, mch_no, merchant_name, review_status, status, created_time
   FROM pay_lsy_merchant
@@ -64,9 +71,9 @@ HAVING count(*) > 1;
 
 
 -- ============================================================================
--- ④ 每租户槽位占用总览
---    「租户级行数」只要 > 1 就是线上数据已经违反约束(不可能);= 1 表示该租户
---    已经不能再新增「企业 ID 留空」的行
+-- ④ 每租户登记行总览
+--    ★ 索引删掉之前,「租户级行数」> 1 是「线上数据已经违反约束(不可能)」;
+--      现在它就是**正常的多商户号**,不构成任何异常。
 -- ============================================================================
 SELECT tenant_id,
        count(*) FILTER (WHERE enterprise_id IS NULL)     AS "租户级行数",
@@ -78,8 +85,11 @@ SELECT tenant_id,
 
 
 -- ============================================================================
--- ⑤ 线上三条唯一索引的真实定义(核对与代码的假设是否一致)
---    期望恰好 3 行,且第 1 条带 WHERE ... IS NULL
+-- ⑤ 线上唯一索引的真实定义(核对与代码的假设是否一致)
+--    期望恰好 3 行,逐条对:pay_lsy_merchant_pkey / uk_lsy_merchant_mch_no /
+--    uk_lsy_merchant_tenant_ent;**不应**再出现 uk_lsy_merchant_tenant_level。
+--    (2026-09-30 实测读数就是这 3 行 —— 这条 SELECT 的 ILIKE 过滤是有效的,
+--      证据是它确实把两个 uk_* 捞出来了,不是「过滤条件把所有行都滤掉了」。)
 -- ============================================================================
 SELECT indexname, indexdef
   FROM pg_indexes