-- Yumi Game King: canonical GAME_CONSUME_GOLD -> draw chances, deterministic ranking and settlement. -- -- Performance review: -- 1. The event path first resolves the very small set of enabled activities by -- (sys_origin, enabled, start_time, end_time), then inserts a unique activity/event ledger row -- and updates one aggregate primary key. It never scans wallet shards or arbitrary expenses. -- 2. Ranking reads the materialized aggregate through -- (activity_id, total_consumed DESC, consume_reached_time ASC, user_id ASC); settlement freezes -- only Top 30 and does not GROUP BY the append-only ledger. -- 3. Draw idempotency, settlement idempotency, finite-stock reservation and reward delivery claims -- all use primary/unique keys. Unlimited stock (-1) is not updated and therefore avoids a hot row. -- 4. Backfill binds sys_origin + GAME_CONSUME_GOLD and keysets by (occurred_at,id) through the added -- index. The public lastId is resolved to its scoped occurred_at before each page, preserving the -- lastId-only contract without sorting/rescanning the whole activity window. -- 5. The activity tables are empty, but the backfill index targets the existing production -- task_center_event_archive_outbox (about 35 million rows / 50 GiB at review time). Treat that ALTER -- as an independent online DDL: run it before the application rollout, monitor metadata-lock waits, -- temporary disk usage and replica lag until completion, and do not hide it inside a service restart. -- 6. The ALTER explicitly requires ALGORITHM=INPLACE and LOCK=NONE. If the target MySQL version or table -- state cannot honor those guarantees, the migration must fail instead of silently falling back to a -- table-copy or write-blocking algorithm. It performs no UPDATE/DELETE/backfill. -- 7. The one-row-per-sysOrigin scope lock is touched only by admin enable/save transactions; it keeps -- concurrent overlap checks correct without serializing the high-volume game event path. SET NAMES utf8mb4; CREATE TABLE IF NOT EXISTS `yumi_game_king_activity` ( `id` BIGINT NOT NULL, `activity_code` VARCHAR(64) NOT NULL, `activity_name` VARCHAR(128) NOT NULL, `activity_desc` VARCHAR(1000) NOT NULL DEFAULT '', `sys_origin` VARCHAR(32) NOT NULL, `time_zone` VARCHAR(64) NOT NULL DEFAULT 'Asia/Riyadh', `start_time` DATETIME(3) NOT NULL, `end_time` DATETIME(3) NOT NULL, `settlement_delay_minutes` INT NOT NULL DEFAULT 30, `settlement_time` DATETIME(3) NOT NULL, `coin_per_draw` BIGINT NOT NULL, `ranking_type` VARCHAR(32) NOT NULL DEFAULT 'TYCOON', `ranking_period` VARCHAR(32) NOT NULL DEFAULT 'OVERALL', `enabled` TINYINT(1) NOT NULL DEFAULT 0, `settlement_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_STARTED', `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_activity_code` (`activity_code`), KEY `idx_yumi_gk_activity_window` (`sys_origin`, `enabled`, `start_time`, `end_time`), KEY `idx_yumi_gk_activity_settle` (`settlement_status`, `settlement_time`, `end_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Yumi Game King activity'; CREATE TABLE IF NOT EXISTS `yumi_game_king_scope_lock` ( `sys_origin` VARCHAR(32) NOT NULL, `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`sys_origin`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Serializes enabled-window checks per Yumi tenant'; CREATE TABLE IF NOT EXISTS `yumi_game_king_prize` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `prize_name` VARCHAR(128) NOT NULL, `prize_image` VARCHAR(500) NOT NULL DEFAULT '', `weight` BIGINT NOT NULL, `stock` BIGINT NOT NULL DEFAULT -1 COMMENT '-1 unlimited, 0 depleted, positive remaining', `resource_group_id` BIGINT NOT NULL, `reward_group_name` VARCHAR(128) NOT NULL DEFAULT '', `reward_items_json` TEXT NOT NULL, `enabled` TINYINT(1) NOT NULL DEFAULT 1, `sort_order` TINYINT NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_prize_position` (`activity_id`, `sort_order`), KEY `idx_yumi_gk_prize_enabled` (`activity_id`, `enabled`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Seven fixed Yumi Game King prizes'; CREATE TABLE IF NOT EXISTS `yumi_game_king_rank_reward` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `start_rank` SMALLINT NOT NULL, `end_rank` SMALLINT NOT NULL, `resource_group_id` BIGINT NOT NULL, `reward_name` VARCHAR(128) NOT NULL DEFAULT '', `reward_items_json` TEXT NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_rank_range` (`activity_id`, `start_rank`, `end_rank`), KEY `idx_yumi_gk_rank_start` (`activity_id`, `start_rank`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Six fixed end-settlement rank reward ranges'; CREATE TABLE IF NOT EXISTS `yumi_game_king_consume_ledger` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `event_id` VARCHAR(128) NOT NULL, `user_id` BIGINT NOT NULL, `sys_origin` VARCHAR(32) NOT NULL, `amount` BIGINT NOT NULL, `event_time` DATETIME(3) NOT NULL, `payload_json` TEXT NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_ledger_event` (`activity_id`, `event_id`), KEY `idx_yumi_gk_ledger_user` (`activity_id`, `user_id`, `event_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Idempotent canonical game-consumption ledger'; CREATE TABLE IF NOT EXISTS `yumi_game_king_user` ( `activity_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `total_consumed` BIGINT NOT NULL DEFAULT 0, `used_chances` BIGINT NOT NULL DEFAULT 0, `consume_reached_time` DATETIME(3) NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`activity_id`, `user_id`), KEY `idx_yumi_gk_user_rank` ( `activity_id`, `total_consumed` DESC, `consume_reached_time` ASC, `user_id` ASC ) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Overall game-consumption aggregate and draw chance usage'; CREATE TABLE IF NOT EXISTS `yumi_game_king_user_daily` ( `activity_id` BIGINT NOT NULL, `stat_date` DATE NOT NULL, `user_id` BIGINT NOT NULL, `total_consumed` BIGINT NOT NULL DEFAULT 0, `consume_reached_time` DATETIME(3) NOT NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`activity_id`, `stat_date`, `user_id`), KEY `idx_yumi_gk_daily_rank` ( `activity_id`, `stat_date`, `total_consumed` DESC, `consume_reached_time` ASC, `user_id` ASC ) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Activity-timezone daily game-consumption aggregate'; CREATE TABLE IF NOT EXISTS `yumi_game_king_draw_record` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `request_id` VARCHAR(64) NOT NULL, `prize_id` BIGINT NOT NULL, `prize_name` VARCHAR(128) NOT NULL, `prize_image` VARCHAR(500) NOT NULL DEFAULT '', `resource_group_id` BIGINT NOT NULL, `delivery_status` VARCHAR(32) NOT NULL, `retry_count` INT NOT NULL DEFAULT 0, `failure_reason` VARCHAR(500) NOT NULL DEFAULT '', `draw_time` DATETIME(3) NOT NULL, `deliver_time` DATETIME(3) NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_draw_request` (`activity_id`, `user_id`, `request_id`), KEY `idx_yumi_gk_draw_user` (`activity_id`, `user_id`, `create_time`), KEY `idx_yumi_gk_draw_manage` (`activity_id`, `delivery_status`, `id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Idempotent Yumi Game King draw records'; CREATE TABLE IF NOT EXISTS `yumi_game_king_settlement_record` ( `id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `rank_no` SMALLINT NOT NULL, `total_consumed` BIGINT NOT NULL, `rank_reward_id` BIGINT NOT NULL, `resource_group_id` BIGINT NOT NULL, `business_no` VARCHAR(128) NOT NULL, `delivery_status` VARCHAR(32) NOT NULL, `retry_count` INT NOT NULL DEFAULT 0, `failure_reason` VARCHAR(500) NOT NULL DEFAULT '', `deliver_time` DATETIME(3) NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_settle_user` (`activity_id`, `user_id`), UNIQUE KEY `uk_yumi_gk_settle_rank` (`activity_id`, `rank_no`), UNIQUE KEY `uk_yumi_gk_settle_business` (`business_no`), KEY `idx_yumi_gk_settle_status` (`activity_id`, `delivery_status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Frozen deterministic Top30 settlement records'; CREATE TABLE IF NOT EXISTS `yumi_game_king_delivery_item` ( `id` BIGINT NOT NULL, `owner_type` VARCHAR(20) NOT NULL COMMENT 'DRAW or SETTLEMENT', `owner_id` BIGINT NOT NULL, `activity_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `resource_group_id` BIGINT NOT NULL, `delivery_status` VARCHAR(32) NOT NULL, `retry_count` INT NOT NULL DEFAULT 0, `failure_reason` VARCHAR(500) NOT NULL DEFAULT '', `deliver_time` DATETIME(3) NULL, `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `update_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`id`), UNIQUE KEY `uk_yumi_gk_delivery_owner` (`owner_type`, `owner_id`), KEY `idx_yumi_gk_delivery_status` (`delivery_status`, `update_time`, `id`), KEY `idx_yumi_gk_delivery_activity` (`activity_id`, `delivery_status`, `id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Group-level reward delivery and UNKNOWN reconciliation'; SET @current_schema := DATABASE(); SET @add_task_center_game_king_backfill_sql := IF( NOT EXISTS ( SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = @current_schema AND table_name = 'task_center_event_archive_outbox' AND index_name = 'idx_task_center_game_king_backfill' ), 'ALTER TABLE `task_center_event_archive_outbox` ADD INDEX `idx_task_center_game_king_backfill` (`sys_origin`, `event_type`, `occurred_at`, `id`), ALGORITHM=INPLACE, LOCK=NONE', 'SELECT 1' ); PREPARE add_task_center_game_king_backfill_stmt FROM @add_task_center_game_king_backfill_sql; EXECUTE add_task_center_game_king_backfill_stmt; DEALLOCATE PREPARE add_task_center_game_king_backfill_stmt;