1.0.520.verify.sql 4.2 KB

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