192 lines
6.7 KiB
Markdown
192 lines
6.7 KiB
Markdown
# 国家数据大屏数据查询技术文档
|
||
|
||
## 目标
|
||
|
||
国家数据大屏接口 `/console/datav/country-dashboard` 原来在页面请求时实时扫描订单、用户、游戏流水和 wallet 分表。线上慢查询主要集中在 `wallet_gold_asset_record_1..12` 的游戏流水、游戏人数统计。当前改为 SQL 指标预聚合,页面优先查询汇总表;汇总缺失或请求范围不符合预聚合口径时,才回退原实时 SQL。
|
||
|
||
## 查询入口
|
||
|
||
- Controller: `DatavRestController#countryDashboard`
|
||
- Service: `CountryDashboardServiceImpl#query`
|
||
- DAO: `CountryDashboardDAO`
|
||
- Mapper: `CountryDashboardDAO.xml`
|
||
|
||
查询参数:
|
||
|
||
- `periodType`: `DAY` / `WEEK` / `MONTH` / `ALL`
|
||
- `startDate`, `endDate`: 闭区间日期,后端转为 `[startDate 00:00:00, endDate + 1 day 00:00:00)`
|
||
- `statTimezone`: 统计时区,默认 `Asia/Riyadh`,支持 `Asia/Riyadh` / `UTC` / `Asia/Shanghai`
|
||
- `countryKeyword`: 国家码或国家名模糊匹配
|
||
- `sysOrigin`: 系统来源,预聚合查询必须传
|
||
|
||
## 预聚合表
|
||
|
||
### `country_dashboard_daily_metric`
|
||
|
||
日级 SQL 指标表,按 `stat_date + sys_origin + country_code` 唯一。
|
||
|
||
用途:
|
||
|
||
- 保留日级汇总结果。
|
||
- 作为 `ALL` 周期金额汇总的数据来源。
|
||
- 作为历史回填和排查的基础日表。
|
||
|
||
### `country_dashboard_period_metric`
|
||
|
||
周期汇总表,按 `period_type + period_key + stat_timezone + sys_origin + country_code` 唯一。
|
||
|
||
周期键示例:
|
||
|
||
- `DAY`: `2026-05-07`
|
||
- `WEEK`: `2026-W19`
|
||
- `MONTH`: `2026-05`
|
||
- `ALL`: `ALL`
|
||
|
||
页面查询优先读取这张表。
|
||
|
||
### `country_dashboard_period_user_metric`
|
||
|
||
周期用户去重明细表,按 `period_type + period_key + stat_timezone + sys_origin + country_code + user_id + metric_type` 唯一。
|
||
|
||
当前维护的 `metric_type`:
|
||
|
||
- `COUNTRY_NEW_USER`: 新增用户人数
|
||
- `LUCKY_GIFT_USER`: 幸运礼物用户人数
|
||
- `GAME_USER`: 游戏用户人数
|
||
|
||
`WEEK/MONTH/ALL` 的人数类指标不再从日表简单相加,而是基于这张明细表聚合,避免同一个用户跨多天被重复计算。
|
||
|
||
## 查询路由
|
||
|
||
`CountryDashboardServiceImpl#shouldUsePrecomputedMetrics` 会先判断是否能走预聚合。
|
||
|
||
走预聚合的条件:
|
||
|
||
- `sysOrigin` 不为空。
|
||
- 对应 `statTimezone` 的周期预聚合已经存在。
|
||
- `DAY`: 查询范围内每一天都有 `country_dashboard_period_metric` 数据。
|
||
- `WEEK/MONTH`: 查询范围必须按周期边界对齐,当前未结束的周/月允许到今天。
|
||
- `ALL`: 无 `startDate/endDate` 时固定走 `period_type=ALL, period_key=ALL`。如果汇总表未回填,返回空汇总,不再回退全历史实时扫描。
|
||
|
||
`DAY/WEEK/MONTH` 不满足条件时回退原实时 SQL,保证数据不因预聚合缺失而返回错误。`ALL` 不回退实时 SQL,是为了避免一次后台点击触发全历史 wallet 分表扫描。
|
||
|
||
## 刷新任务
|
||
|
||
任务类:`CountryDashboardDailyMetricTask`
|
||
|
||
默认任务:
|
||
|
||
- 每 10 分钟刷新最近 1 天:`red-circle.country-dashboard.refresh-today-cron`
|
||
- 每天 00:20 刷新最近 8 天:`red-circle.country-dashboard.refresh-recent-cron`
|
||
|
||
默认平台:
|
||
|
||
```yaml
|
||
red-circle:
|
||
country-dashboard:
|
||
refresh-sys-origins: LIKEI
|
||
```
|
||
|
||
需要刷新多个平台时配置为逗号分隔,例如:
|
||
|
||
```yaml
|
||
red-circle:
|
||
country-dashboard:
|
||
refresh-sys-origins: LIKEI,TARAB
|
||
```
|
||
|
||
刷新链路:
|
||
|
||
1. 按利雅得时区刷新日表 `country_dashboard_daily_metric`。
|
||
2. 按配置的统计时区刷新对应 `DAY` 周期表和用户去重明细。
|
||
3. 按配置的统计时区刷新受影响的 `WEEK`、`MONTH`。
|
||
4. 基于同一 `stat_timezone` 下已存在的 `DAY` 周期表和日级用户明细刷新 `ALL`。
|
||
|
||
默认刷新时区:
|
||
|
||
```yaml
|
||
red-circle:
|
||
country-dashboard:
|
||
refresh-timezones: Asia/Riyadh,UTC,Asia/Shanghai
|
||
```
|
||
|
||
## 指标来源
|
||
|
||
SQL 预聚合指标:
|
||
|
||
- 新增用户:`user_base_info`
|
||
- 新用户充值、官方充值、Google 充值:`order_purchase_history`
|
||
- MifaPay 充值:`order_user_purchase_pay`
|
||
- 代理充值:`likei_wallet.user_freight_balance_running_water`
|
||
- 工资兑换:`user_salary_account_running_water`, `user_salary_diamond_running_water`
|
||
- 幸运礼物流水/返奖:`game_lucky_gift_count`
|
||
- 游戏流水/返奖:`wallet_gold_asset_record_1..12`, `game_lucky_box_count`
|
||
- 游戏人数:`country_dashboard_period_user_metric` 的 `GAME_USER`
|
||
|
||
仍实时从 Mongo 聚合的指标:
|
||
|
||
- 礼物消耗:`gift_give_running_water`
|
||
- 幸运礼物主播分成:`gift_give_running_water`
|
||
- 日活:`user_daily_active_log`
|
||
- 留存:`user_daily_active_log` + 注册 cohort
|
||
|
||
## 上线和回填
|
||
|
||
上线前可以先执行:
|
||
|
||
- `sql/20260507_country_dashboard_daily_metric.sql`
|
||
- `sql/20260507_country_dashboard_period_metric.sql`
|
||
- `sql/20260508_country_dashboard_period_metric_timezone.sql`
|
||
|
||
为避免遗漏,console 的刷新和手动回填入口会先执行同等的 `CREATE TABLE IF NOT EXISTS` 检查,再写入预聚合数据。
|
||
|
||
首次上线后,预聚合表为空时接口会回退实时 SQL。为了尽快切到预聚合,需要先回填最近常用查询范围,例如最近 8 天、当前周、当前月。
|
||
|
||
`ALL` 的数据由已回填的日表和日级用户明细汇总而来。如果需要后台“全部”展示完整历史,必须先完成历史日数据回填;否则 `ALL` 只代表当前已经进入预聚合表的数据范围。
|
||
|
||
手动回填入口:
|
||
|
||
```bash
|
||
curl -X POST 'http://127.0.0.1:{console_port}/console/datav/country-dashboard/backfill?startDate=2026-04-08&endDate=2026-05-07&sysOrigin=LIKEI'
|
||
```
|
||
|
||
该入口默认回填 `Asia/Riyadh`、`UTC`、`Asia/Shanghai` 三个统计时区。需要指定时区时可以传:
|
||
|
||
```bash
|
||
curl -X POST 'http://127.0.0.1:{console_port}/console/datav/country-dashboard/backfill?startDate=2026-04-08&endDate=2026-05-07&sysOrigin=LIKEI&statTimezones=Asia/Riyadh,UTC,Asia/Shanghai'
|
||
```
|
||
|
||
该入口会按天重算日表,并按每个 `stat_timezone` 重算 `DAY` 周期,再刷新受影响的 `WEEK`、`MONTH` 和 `ALL`。
|
||
|
||
## 验证 SQL
|
||
|
||
检查某天是否已刷新:
|
||
|
||
```sql
|
||
SELECT stat_date, sys_origin, COUNT(1)
|
||
FROM country_dashboard_daily_metric
|
||
WHERE sys_origin = 'LIKEI'
|
||
GROUP BY stat_date, sys_origin
|
||
ORDER BY stat_date DESC;
|
||
```
|
||
|
||
检查周期汇总:
|
||
|
||
```sql
|
||
SELECT stat_timezone, period_type, period_key, sys_origin, COUNT(1)
|
||
FROM country_dashboard_period_metric
|
||
WHERE sys_origin = 'LIKEI'
|
||
GROUP BY stat_timezone, period_type, period_key, sys_origin
|
||
ORDER BY stat_timezone, period_type, period_key DESC;
|
||
```
|
||
|
||
检查用户去重明细:
|
||
|
||
```sql
|
||
SELECT stat_timezone, period_type, period_key, metric_type, COUNT(1)
|
||
FROM country_dashboard_period_user_metric
|
||
WHERE sys_origin = 'LIKEI'
|
||
GROUP BY stat_timezone, period_type, period_key, metric_type
|
||
ORDER BY stat_timezone, period_type, period_key DESC, metric_type;
|
||
```
|