Files
sodalive-backend-spring-boot/docs/20260608_크리에이터_랭킹/create-ranking-tables.sql

131 lines
7.5 KiB
SQL

-- MySQL 크리에이터 랭킹 스냅샷 테이블
-- 날짜/시간 표시 컬럼은 TIMESTAMP를 사용한다.
-- 같은 기간 재생성 시 삭제 기준:
-- delete from creator_ranking_snapshot
-- where aggregation_start_at_utc = :aggregationStartAtUtc
-- and aggregation_end_at_utc = :aggregationEndAtUtc;
create table creator_ranking_snapshot (
id bigint not null auto_increment comment '크리에이터 랭킹 스냅샷 ID',
aggregation_start_at_utc timestamp not null comment '집계 시작 시각(UTC, 포함)',
aggregation_end_at_utc timestamp not null comment '집계 종료 시각(UTC, 미포함)',
creator_id bigint not null comment '크리에이터 회원 ID(member.id)',
nickname varchar(100) not null comment '스냅샷 생성 시점 크리에이터 닉네임',
profile_image_url varchar(500) null comment '스냅샷 생성 시점 크리에이터 프로필 이미지 URL',
final_score double not null comment '최종 랭킹 점수',
content_live_score double not null comment '콘텐츠/라이브 카테고리 점수',
engagement_score double not null comment '참여 반응 카테고리 점수',
support_score double not null comment '응원 카테고리 점수',
fan_loyalty_score double not null comment '팬 충성도 카테고리 점수',
live_can_amount bigint not null comment '라이브 계열 사용 캔 합계',
content_purchase_can_amount bigint not null comment '콘텐츠 구매 사용 캔 합계',
content_like_count bigint not null comment '콘텐츠 좋아요 수',
content_comment_count bigint not null comment '콘텐츠 댓글 및 대댓글 수',
channel_donation_can_amount bigint not null comment '채널 후원 사용 캔 합계',
channel_donation_count bigint not null comment '채널 후원 건수',
fan_talk_count bigint not null comment '최상위 팬 Talk 수',
final_follower_count bigint not null comment '집계 종료 시점 활성 팔로우 수',
follow_increase bigint not null comment '집계 기간 팔로우 증가 수',
created_at timestamp not null default current_timestamp comment '생성 시각',
updated_at timestamp not null default current_timestamp on update current_timestamp comment '수정 시각',
primary key (id)
) engine=InnoDB default charset=utf8mb4 comment='크리에이터 랭킹 주간 스냅샷';
create index idx_creator_ranking_snapshot_period_score
on creator_ranking_snapshot (aggregation_end_at_utc, final_score desc);
create index idx_creator_ranking_snapshot_replace_period
on creator_ranking_snapshot (aggregation_start_at_utc, aggregation_end_at_utc);
create index idx_creator_ranking_snapshot_period_creator
on creator_ranking_snapshot (aggregation_start_at_utc, aggregation_end_at_utc, creator_id);
create table creator_ranking_snapshot_job (
id bigint not null auto_increment comment '크리에이터 랭킹 스냅샷 생성 job ID',
aggregation_start_at_utc timestamp not null comment '집계 시작 시각(UTC, 포함)',
aggregation_end_at_utc timestamp not null comment '집계 종료 시각(UTC, 미포함)',
trigger_type varchar(20) not null comment '실행 트리거(SCHEDULED, MANUAL)',
status varchar(20) not null comment 'job 상태(PENDING, PROCESSING, DONE, FAILED)',
last_error text null comment '마지막 실패 사유',
processing_started_at timestamp null comment '처리 시작 시각',
processed_at timestamp null comment '처리 완료 시각',
created_at timestamp not null default current_timestamp comment '생성 시각',
updated_at timestamp not null default current_timestamp on update current_timestamp comment '수정 시각',
primary key (id)
) engine=InnoDB default charset=utf8mb4 comment='크리에이터 랭킹 스냅샷 생성 job 이력';
create index idx_creator_ranking_snapshot_job_period_status
on creator_ranking_snapshot_job (aggregation_start_at_utc, aggregation_end_at_utc, status);
create index idx_creator_ranking_snapshot_job_status_created_at
on creator_ranking_snapshot_job (status, created_at);
-- 이미 위 CREATE DDL이 적용된 DB의 시간 정책 변경용 DDL
-- 목적:
-- 1. 현재 기본 랭킹 타입(WEEKLY)을 명시한다.
-- 2. 공개 조회 노출 시작 시각(visible_from_at)을 저장한다.
-- 3. 최신 생성 스냅샷이 아니라 visible_from_at <= now 조건의 최신 공개 스냅샷을 조회할 수 있게 인덱스를 보강한다.
-- 주의:
-- 운영 DB 반영 시 중복 스냅샷이 있으면 uk_creator_ranking_snapshot_period_creator 생성 전 정리한다.
-- visible_from_at backfill 기준은 aggregation_end_at_utc + 9시간이다.
-- 예: 2026-06-07 15:00:00 UTC 집계 종료는 2026-06-08 00:00:00 KST이고,
-- 노출 전환 2026-06-08 09:00:00 KST는 2026-06-08 00:00:00 UTC다.
alter table creator_ranking_snapshot
add column ranking_type varchar(30) null comment '랭킹 타입(현재 WEEKLY, 향후 다중 타입 확장)' after id,
add column visible_from_at timestamp null comment '공개 조회 노출 시작 시각(UTC)' after aggregation_end_at_utc;
update creator_ranking_snapshot
set ranking_type = 'WEEKLY'
where ranking_type is null;
update creator_ranking_snapshot
set visible_from_at = timestampadd(hour, 9, aggregation_end_at_utc)
where visible_from_at is null;
alter table creator_ranking_snapshot
modify column ranking_type varchar(30) not null comment '랭킹 타입(현재 WEEKLY, 향후 다중 타입 확장)',
modify column visible_from_at timestamp not null comment '공개 조회 노출 시작 시각(UTC)';
create unique index uk_creator_ranking_snapshot_period_creator
on creator_ranking_snapshot (ranking_type, aggregation_start_at_utc, aggregation_end_at_utc, creator_id);
drop index idx_creator_ranking_snapshot_period_score on creator_ranking_snapshot;
create index idx_creator_ranking_snapshot_period_score
on creator_ranking_snapshot (ranking_type, aggregation_end_at_utc, final_score desc);
create index idx_creator_ranking_snapshot_visible_score
on creator_ranking_snapshot (ranking_type, visible_from_at desc, final_score desc);
drop index idx_creator_ranking_snapshot_replace_period on creator_ranking_snapshot;
drop index idx_creator_ranking_snapshot_period_creator on creator_ranking_snapshot;
alter table creator_ranking_snapshot_job
add column ranking_type varchar(30) null comment '랭킹 타입(현재 WEEKLY, 향후 다중 타입 확장)' after id,
add column visible_from_at timestamp null comment '공개 조회 노출 시작 시각(UTC)' after aggregation_end_at_utc;
update creator_ranking_snapshot_job
set ranking_type = 'WEEKLY'
where ranking_type is null;
update creator_ranking_snapshot_job
set visible_from_at = timestampadd(hour, 9, aggregation_end_at_utc)
where visible_from_at is null;
alter table creator_ranking_snapshot_job
modify column ranking_type varchar(30) not null comment '랭킹 타입(현재 WEEKLY, 향후 다중 타입 확장)',
modify column visible_from_at timestamp not null comment '공개 조회 노출 시작 시각(UTC)';
drop index idx_creator_ranking_snapshot_job_period_status on creator_ranking_snapshot_job;
create index idx_creator_ranking_snapshot_job_period_status
on creator_ranking_snapshot_job (ranking_type, aggregation_start_at_utc, aggregation_end_at_utc, status);
create index idx_creator_ranking_snapshot_job_visible_status
on creator_ranking_snapshot_job (ranking_type, visible_from_at, status);
create index idx_creator_ranking_snapshot_job_trigger_period
on creator_ranking_snapshot_job (ranking_type, aggregation_start_at_utc, aggregation_end_at_utc, trigger_type, created_at);