zhx dc8435f869 增加幸运礼物 AB 实验:按用户哈希分流灰度发布配置版本
- lucky_gift_experiments/overrides 表(006 迁移,含分组统计索引与 binary user_key)
- 创建实验=同事务发布 treatment+登记;两组强制同策略;实验期常规发布拒绝
- Check/单抽/批量/外部抽按用户钉住组内版本;结束实验重发布获胜快照全量收敛
- AdminLuckyGiftService 新增 5 个实验 RPC(放量字段 proto3 optional)
- admin 实验管理 HTTP API + lucky-gift:experiment 权限(迁移 103)
- 设计文档 docs/幸运礼物AB实验.md;域/真库/admin 回归测试

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 00:22:12 +08:00

54 lines
4.4 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.

SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
USE hyapp_lucky_gift;
-- AB 实验事实表:两组各钉住一个不可变 rule_version运行时按 bucket_salt + user 哈希分流。
-- active 生成列只在未完成状态为 1配合唯一键保证同一奖池同时最多一个未完成实验
-- completed 后 active 为 NULL不占用唯一键历史实验可以保留任意多条。
CREATE TABLE IF NOT EXISTS lucky_gift_experiments (
app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
experiment_id VARCHAR(64) NOT NULL COMMENT '实验 ID',
pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
name VARCHAR(128) NOT NULL COMMENT '实验名称',
control_rule_version BIGINT NOT NULL COMMENT '对照组钉住的规则版本',
treatment_rule_version BIGINT NOT NULL COMMENT '实验组钉住的规则版本',
treatment_traffic_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '实验组流量比例 ppm0..1000000',
bucket_salt VARCHAR(64) NOT NULL COMMENT '分桶盐;实验生命周期内不可变,保证同一用户分组稳定',
status VARCHAR(16) NOT NULL DEFAULT 'running' COMMENT 'running/paused/completed',
active TINYINT AS (IF(status IN ('running', 'paused'), 1, NULL)) STORED COMMENT '未完成实验为 1completed 为 NULL',
winner_arm VARCHAR(16) NOT NULL DEFAULT '' COMMENT '结束实验时选择的获胜组 control/treatment',
winner_rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '获胜组钉住的规则版本',
final_rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '结束时重发布的收敛版本,全量流量由它承接',
created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建管理员 ID',
started_at_ms BIGINT NOT NULL COMMENT '实验开始时间UTC epoch ms',
ended_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '实验结束时间UTC epoch ms',
created_at_ms BIGINT NOT NULL COMMENT '创建时间UTC epoch ms',
updated_at_ms BIGINT NOT NULL COMMENT '更新时间UTC epoch ms',
PRIMARY KEY (app_code, experiment_id),
UNIQUE KEY uk_lucky_gift_experiments_active_pool (app_code, pool_id, active),
KEY idx_lucky_gift_experiments_pool (app_code, pool_id, started_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 AB 实验';
-- 白名单 override把指定用户强制固定到某个组用于放量前验证。
-- user_key内部用户为十进制 user_id外部用户为 "ext:" + external_user_id。
CREATE TABLE IF NOT EXISTS lucky_gift_experiment_overrides (
app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
experiment_id VARCHAR(64) NOT NULL COMMENT '实验 ID',
-- user_key 必须字节精确binary collationFNV 分桶按字节计算ci 排序规则会让大小写不同的外部用户在白名单上碰撞/静默失配。
user_key VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '用户标识:内部十进制 user_id 或 ext:external_user_id',
arm VARCHAR(16) NOT NULL COMMENT '强制组 control/treatment',
created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '操作管理员 ID',
created_at_ms BIGINT NOT NULL COMMENT '创建时间UTC epoch ms',
PRIMARY KEY (app_code, experiment_id, user_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 AB 实验用户白名单';
-- 实验分组统计按 (app, pool, rule_version, 时间窗) 聚合;没有含 rule_version 的索引时热池会退化为大范围回表扫描。
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_draw_records' AND INDEX_NAME = 'idx_lucky_draw_pool_version') = 0,
'ALTER TABLE lucky_draw_records ADD KEY idx_lucky_draw_pool_version (app_code, pool_id, rule_version, created_at_ms)', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 兜底006 首版曾以表默认 ci 排序规则建过 overrides 表;重复执行时归一到 binary。
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_experiment_overrides' AND COLUMN_NAME = 'user_key' AND COLLATION_NAME <> 'utf8mb4_bin') = 1,
'ALTER TABLE lucky_gift_experiment_overrides MODIFY user_key VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT ''用户标识:内部十进制 user_id 或 ext:external_user_id''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;