acquire-core-x/db/schema.d/99-bulk-derive.sql
hyeongwoo ab7983318d Wave I: 대량·다양 데이터 (다년치 135만 매입 → 총 1,130만 행)
기존 3개월치(~20만행)를 5.5년치 대량 히스토리로 확대. 성장추세·계절성·
가맹점 생애주기 반영. ID 오프셋 대역(1천만+)으로 기존/라이브 채번과 비충돌,
전부 idempotent 가드.

- 98-bulk-seed.sql: 가맹점 40→200(MCC·요율·개점일·CLOSED/HOLD 다양) +
  매입 135만건(2021-01~2026-04, 성장추세 연 0.5→1.4배·12월 계절피크·주중주말·
  다양 채널/발급사/카드종류/금액구간). 27초.
- 99-bulk-derive.sql: 승인 135만·원장 2.6M(RECON+SETTLE)·정산 1.29M·
  가맹점집계 358k. 시퀀스 정렬. 31초.
- 99b-bulk-econ.sql: 정산경제 파생 — 수수료3층분해 1.29M·프레젠트먼트 1.29M·
  ISO8583 클리어링 1.29M·순액정산(발급사×일) 16k·펀딩 355k.
- 99c-bulk-index.sql: 운영 인덱스 14개(biz_date/merchant/status 등) + ANALYZE.

검증 (실측)
- 총 1,130만 행, DB 1.8GB. 연도별 성장 2021년 14.5만→2025년 35.3만건.
- 3층 항등식 1,293,145/1,293,145, 펀딩 항등식 355,284/355,284 (100% 성립).
- 대시보드/정산경제 화면 정상: 활성가맹점 191, 총매입 3,997억, 입금률 95.7%.
- 집계쿼리 0.5초(인덱스). 최근 3개월 라이브 데이터 무손상.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 12:24:42 +09:00

43 lines
2.5 KiB
SQL

-- ===========================================================================
-- 99-bulk-derive.sql : 대량 히스토리 매입(98-bulk)의 파생 테이블 적재.
-- 승인/원장/정산/가맹점집계. ID 는 오프셋 대역(비충돌). idempotent 가드.
-- ===========================================================================
-- 승인 (매입 1:1, 99%)
INSERT INTO approval (approval_id, purchase_id, approved, approved_at)
SELECT purchase_id, purchase_id, (random() < 0.99),
created_at
FROM purchase p WHERE p.purchase_id >= 10000000
AND NOT EXISTS (SELECT 1 FROM approval a WHERE a.approval_id = p.purchase_id);
-- 원장: 정산완료(S) 건 RECON + SETTLE 이중기표
INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date, created_at)
SELECT 100000000 + row_number() OVER (ORDER BY purchase_id), purchase_id, 'RECON', net, biz_date,
biz_date::timestamptz + interval '20 hours'
FROM purchase WHERE purchase_id >= 10000000 AND status = 'S'
AND NOT EXISTS (SELECT 1 FROM ledger l WHERE l.ledger_id >= 100000000 LIMIT 1);
INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date, created_at)
SELECT 200000000 + row_number() OVER (ORDER BY purchase_id), purchase_id, 'SETTLE', net, biz_date,
biz_date::timestamptz + interval '21 hours'
FROM purchase WHERE purchase_id >= 10000000 AND status = 'S'
AND NOT EXISTS (SELECT 1 FROM ledger l WHERE l.ledger_id >= 200000000 LIMIT 1);
-- 정산 (S건, T+1 지급)
INSERT INTO settlement (settlement_id, purchase_id, merchant_id, net, biz_date, status, settled_at)
SELECT 30000000 + row_number() OVER (ORDER BY purchase_id), purchase_id, merchant_id, net, biz_date,
'SETTLED', biz_date::timestamptz + interval '1 day 10 hours'
FROM purchase WHERE purchase_id >= 10000000 AND status = 'S'
AND NOT EXISTS (SELECT 1 FROM settlement s WHERE s.settlement_id >= 30000000 LIMIT 1);
-- 가맹점 일집계
INSERT INTO merchant_summary (merchant_id, biz_date, txn_count, gross_amount, fee_amount, net_amount)
SELECT merchant_id, biz_date, count(*), sum(amount), sum(fee), sum(net)
FROM purchase WHERE purchase_id >= 10000000
GROUP BY merchant_id, biz_date
ON CONFLICT (merchant_id, biz_date) DO NOTHING;
-- 시퀀스 정렬 (라이브 채번이 오프셋 대역 뒤로 가도록)
SELECT setval('purchase_seq', (SELECT max(purchase_id) FROM purchase));
SELECT setval('approval_seq', (SELECT max(approval_id) FROM approval));
SELECT setval('ledger_seq', (SELECT max(ledger_id) FROM ledger));
SELECT setval('settlement_seq', (SELECT max(settlement_id) FROM settlement));