-- 1.0.520.verify.sql — 每条 SELECT 都必须返回真值(0 或 NULL 即判失败并中断启动) -- ── 1 · 新键到位:四列、列序正确 ───────────────────────────────────────────────────── -- 与 1.0.517.verify 同法,用 GROUP_CONCAT 比列序列字符串,不对 information_schema 施加 COLLATE -- (部分 MySQL 版本上它是 utf8mb3,强加 utf8mb4_bin 会让 verify 脚本自己把启动打挂)。 SELECT IFNULL((SELECT GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mdp_stg_so' AND INDEX_NAME = 'uk_source_key'), '') = 'tenant_id,source_system,source_table,source_biz_key'; -- tenant_id 必须是第 1 列:贴源的绝大多数读法都以 tenant_id 打头, -- 放在末列虽然唯一性等价,却让这个索引无法为租户内检索提供前缀。 SELECT (SELECT SEQ_IN_INDEX FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mdp_stg_so' AND INDEX_NAME = 'uk_source_key' AND COLUMN_NAME = 'tenant_id') = 1; -- 必须仍然是 UNIQUE:若退化成普通索引,upsert 的 ON DUPLICATE KEY 会整个失效, -- 贴源从「覆盖」变成「无限追加」,比原缺陷更糟。 SELECT (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mdp_stg_so' AND INDEX_NAME = 'uk_source_key' AND NON_UNIQUE = 0) = 4; -- ── 2 · 跨租户覆盖路径已关闭 ───────────────────────────────────────────────────────── -- 本条是本批的核心断言:mdp_stg_so 上不得再存在任何「不含 tenant_id 的唯一约束」。 -- 只钉 uk_source_key 是不够的 —— 任何一个漏了 tenant_id 的唯一索引都会重新变成 -- ON DUPLICATE KEY 的冲突判据,把跨租户覆盖路径再打开一次。 SELECT (SELECT COUNT(*) FROM ( SELECT INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mdp_stg_so' AND NON_UNIQUE = 0 AND INDEX_NAME <> 'PRIMARY' GROUP BY INDEX_NAME HAVING SUM(COLUMN_NAME = 'tenant_id') = 0) x) = 0; -- 存量在新键下无冲突(唯一索引在位时必然成立,作为落库后的兜底自检)。 SELECT (SELECT COUNT(*) FROM ( SELECT 1 FROM `mdp_stg_so` GROUP BY `tenant_id`,`source_system`,`source_table`,`source_biz_key` HAVING COUNT(*) > 1) x) = 0; -- ── 3 · 贴源层与标准层口径已对齐 ───────────────────────────────────────────────────── -- 本批的意义就是消除两层不一致,故把 mdp_std_so 的键一起钉住,防止有人反向「对齐」到窄键。 SELECT IFNULL((SELECT GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'mdp_std_so' AND INDEX_NAME = 'uk_source_key' AND NON_UNIQUE = 0), '') = 'tenant_id,source_system,source_table,source_biz_key'; -- ── 4 · 1.0.356 建立的作用域 CHECK 未被本批动过 ────────────────────────────────────── -- 该 CHECK 保证 tenant_id 非空且不是平台/默认租户,是「键里有 tenant_id」能真正隔离的前提: -- 若 tenant_id 可为 NULL,MySQL 唯一索引会把多个 NULL 视为互不相同,隔离与去重会同时失效。 SELECT (SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = DATABASE() AND TABLE_NAME = 'mdp_stg_so' AND CONSTRAINT_NAME = 'ck_mdp_stg_so_valid_scope') = 1; -- 存量 tenant_id 必须真的可用:无 NULL、无 0/1/默认租户。 -- 键里有 tenant_id 但该列是空的,隔离等于没做。 SELECT (SELECT COUNT(*) FROM `mdp_stg_so` WHERE `tenant_id` IS NULL OR `tenant_id` IN (0, 1, 1300000000001)) = 0;