본문으로 건너뛰기

테이블의 행 벌 — 한 테이블에 데이터 여러 벌

문서 목록으로

한 테이블이 데이터를 여러 벌 가지는 것에 대한 설계입니다. 스키마는 하나이고 행만 갈립니다.

지금은 그것을 별개의 테이블로 읽고 있습니다. ProfileProfile_BCCN이 서로 다른 타입 두 개가 되어, 모든 언어에 AdmiralBccn 클래스가 하나씩 더 생깁니다. 그 클래스는 누구도 선언한 적이 없는 타입입니다 — 시트가 말한 것은 「이 테이블의 중국 데이터」이지 「중국용 테이블」이 아닙니다.

로드맵이 「분리해 남겼다」고 적어 둔 항목입니다.

행 태그와 다릅니다. 행 벌은 벌마다 파일이 나오고 읽는 프로그램이 고르고, 태그는 그 빌드가 담은 한 벌만 파일에 들어갑니다. 배포에 실리면 안 되는 행은 태그 쪽입니다 — 비교표.


1. 규격

named-range 레이아웃은 정의된 이름의 접미사로 지역을 표시합니다.

Profile ← 원본
Profile_BCCN ← 같은 테이블의 다른 지역 데이터
규칙내용
같은 테이블입니다스키마가 하나이고 행만 두 벌입니다
스키마가 같아야 합니다다르면 오류입니다. 지금은 조용히 다른 타입 두 개가 됩니다
파일은 두 개Profile.tcbProfile_BCCN.tcb. 접미사의 구분자를 유지합니다 — 지금은 ProfileBCCN.tcb로 나가고 있어 이름에서 변종임이 사라집니다
고르는 것은 읽는 쪽프로그램이 접미사를 지정해 그 파일을 읽습니다

원본 익스포터도 같습니다 — 파일 이름은 정의된 이름 그대로이고, 파일 의 테이블 이름은 _BC 이후를 잘라낸 것입니다.

// Profile_BCCN.json — 파일 이름에는 접미사가, 안에는 원본 이름이
{ ":Profile": {}, "Profile": {38행 … } }
// Profile.json
{ ":Profile": {}, "Profile": {41행 … } }

2. 실측

무엇
전량에서 읽히는 테이블537
그중 변종81 (전부 _BCCN)
원본이 함께 읽히는 변종81 — 전부
배포된 산출물의 변종 파일96

원본 없는 변종은 하나도 없습니다. 「원본이 없으면 어떻게 하는가」는 규칙이 필요한 경우가 아니라 오류로 두면 되는 경우입니다.

스키마가 다른 짝 6개

그리고 이것이 이 설계가 켜지면 오류가 되는 것들입니다. 지금은 다른 타입 두 개라 아무도 비교하지 않습니다.

테이블원본에만 있는 컬럼변종에만 있는 컬럼
ProfilerecruitCostBaseValuerecruitCostValue
OfferTabofferBannerId · showsStatus
RosterautoRosterAscendPerkId
CosmeticSkinstatBonus
MarketdemandModifier
EmblemchildStatBonus · statBonus

Profile이 특히 볼 만합니다 — 이름이 다른 같은 컬럼으로 보입니다. 나머지 다섯은 변종이 원본을 따라가지 못한 형태입니다. 전부 시트 오류 보고로 갑니다.

3. 왜 지금 표현이 틀린가 — 검증이 증명합니다

별개 테이블로 읽으면 참조가 원본을 향합니다. 그래서 지금 전량 검증에 「없는 행을 가리키는 참조」가 잡히는데, 실측하면 그 대부분이 가짜입니다.

Offer_BCCN.bundleCategory = 1402
OfferTab (80행) → 1402 없음 ← 우리가 여기를 봅니다
OfferTab_BCCN (49행) → 1402 있음 ← 시트가 뜻한 곳

93건이 이 하나의 원인입니다. 변종의 행은 변종의 세계에서 해석되어야 하고, 그것이 이 설계가 있어야 검증이 옳아지는 이유입니다.

4. 설계 — 표기는 소스가 정하고, 코어는 문자열만 압니다

꼬리표가 무엇을 뜻하는지 코어가 몰라야 합니다. _BCCN도 그 시트들의 어휘이고, 다른 프로젝트는 다르게 씁니다. 그래서 표기 자체를 recipe가 정규식으로 적습니다.

"TableRowSets": "^(?<table>.+?)(?<set>_BC[A-Z]+)$"

table 그룹이 테이블을 지목하고, set 그룹이 꼬리표를 잡습니다. 꼬리표는 구분자까지 포함해 잡힌 그대로 파일 이름에 붙으므로, 코어가 _를 붙이거나 떼는 판단을 하지 않습니다.

소스 항목의 정식 프로퍼티입니다. 「이 프로젝트의 테이블이 행을 여러 벌 가지는가」는 시트에 대한 질문이지 테이블을 어떻게 찾는지에 대한 질문이 아니라서, 마커 레이아웃과 이름 기반 레이아웃이 똑같이 가질 수 있습니다.

무엇어디
표기recipeSheetSourceRecipe.TableRowSets
접는 동작src/Cooking/TableRowSets.cs — 레이아웃 밖, 모델 전체에
테이블이 벌을 여럿 가진다는 개념Table.ExtraRowSets · RowSet
벌마다 파일을 쓰는 것익스포터. table.RowSets를 도는 것이 전부입니다
참조를 같은 벌에서 푸는 것검증
생성되는 코드무변경 — 타입은 테이블당 하나입니다

4.1 언제 접는가

모든 레이아웃이 파싱을 끝낸 뒤, 진단 수집기가 생긴 다음입니다.

레이아웃 안에서 하지 않는 이유는 위와 같고, 파싱 중에 하지 않는 이유는 이름이 도착하는 순서가 워크북의 것이기 때문입니다 — Profile_BCCNProfile보다 먼저 읽힐 수 있습니다.

진단 수집기 뒤인 이유는 어긋난 짝을 한 번에 보고하기 위해서입니다. 첫 짝에서 멈추면 목록을 얻을 수 없고, 이 기능을 켜는 프로젝트가 원하는 것이 그 목록입니다.

4.2 벌의 행을 테이블의 컬럼에 맞추기 — 위치가 아니라 이름으로

두 벌의 폭이 같을 필요가 없습니다. 배열 컬럼은 한쪽이 덜 채워질 수 있고, 그것은 다른 컬럼이 아니라 같은 컬럼을 덜 채운 것입니다. 위치로 맞추면 그 뒤의 모든 컬럼이 엉뚱한 이름으로 읽힙니다.

그래서 컬럼 이름으로 맞추고, 벌에 없는 컬럼은 「값 없음」으로 채웁니다 — 시트가 빈칸을 남겼을 때 레이아웃이 쓰는 것과 같은 셀입니다. 배열의 길이가 행마다 HasValue로 정해지므로, 짧은 벌은 패딩되지 않고 실제로 짧게 나옵니다.

테이블이 벌의 컬럼을 전부 선언해야 합니다. 반대는 괜찮고 그쪽이 흔한 형태입니다. 벌에만 있는 컬럼은 해결할 수 없는 경우입니다 — 생성되는 타입은 테이블에서 나오므로, 그 컬럼은 어떤 소비자도 닿을 수 없습니다.

벌이 선언하지 않은 컬럼은 optional이 됩니다

위의 규칙이 그 자리에 「값 없음」을 씁니다. 그런데 컬럼이 required로 선언되어 있으면 검사가 접기가 방금 쓴 그 값을 위반으로 보고합니다 — 한 모델 안에서 두 규칙이 서로를 부정하는 자리이고, 실측 733건이 그것입니다(Market_BCCNdemandModifier이 없습니다).

그래서 벌 하나가 어떤 컬럼을 선언하지 않으면 그 컬럼은 테이블 전체에서 optional입니다.

무엇되는 것
스칼라 컬럼행이 값 없이 있을 수 있는 컬럼. 생성 타입이 bool?이 되고 presence가 붙습니다
접힌 배열의 원소원소가 없을 수 있는 배열 (원소별 optional)

대가가 둘 있습니다. 그 컬럼의 생성 타입이 원본 벌만 읽는 소비자에게도 optional이 됩니다 — 테이블의 스키마가 벌들의 합집합이라면 optional도 합집합이라는 쪽입니다. 그리고 배열 쪽은 원소별 presence가 와이어에 실립니다.

required가 무의미해지지는 않습니다. 벌이 그 컬럼을 선언했으면 그 벌의 빈 셀은 그대로 보고됩니다. 없어지는 것은 선언조차 하지 않은 컬럼에 대한 보고뿐입니다.

격자는 컬럼 id로 맞춥니다

매트릭스 표는 컬럼 이름이 다른 축의 id이고, 레이아웃이 그것을 Value[722]처럼 위치로 다시 이름 붙입니다. 그래서 「위치가 아니라 이름으로」라는 위의 규칙이 격자에서만 무력해집니다 — 그 이름이 곧 위치이기 때문입니다.

실측이 그 결과를 보여줍니다. SystemMatrix는 마을 735개이고 그 벌은 724개인데, 벌의 마을 id가 원본의 부분집합이지만 접두사가 아닙니다.

원소721722723724~734
원본24000721240007222400072324000724~
240007212400073124000734없음

벌의 행 225개에서 원소 2개가 다른 마을의 값으로 조용히 읽히고(450칸), 뒤의 11개는 값이 없어 오류 4,950건으로 보고됩니다. 보고되는 쪽보다 보고되지 않는 쪽이 문제입니다.

그래서 컬럼은 이름 대신 「맞추는 이름」으로 맞춥니다. 기본값이 컬럼 이름이고, 레이아웃이 그것을 다른 것으로 둘 수 있습니다 — 격자는 컬럼 id를 넣습니다. 코어는 격자를 모릅니다: 아는 것은 「이 컬럼을 벌끼리 맞출 때 쓰는 이름」 하나뿐이고, 그것을 격자로 채우는 것은 레이아웃 파일입니다.

그리고 벌인 격자는 컬럼 테이블을 만들지 않습니다. 접히고 나면 자리가 원본의 것이므로 벌의 컬럼 테이블은 틀린 자리를 적은 표가 됩니다. 어느 시트가 벌인지는 레이아웃이 이미 볼 수 있습니다 — TableRowSets가 소스의 설정이기 때문입니다.

4.3 참조

같은 꼬리표를 먼저 보고, 없으면 원본을 봅니다.

2번이 관용이 아니라 흔한 경우입니다 — 537개 중 벌을 가진 것이 81개뿐이라, 벌의 행이 가리키는 대상은 대개 벌이 없습니다.

읽는 쪽에 조건이 하나 붙습니다. 한 벌을 읽는 빌드는 벌을 가진 모든 테이블의 그 벌을 읽어야 합니다. 이 검사가 런타임과 일치하는 근거가 그 조건이고, 여기 명시합니다.

참조 셀의 변환도 벌마다 돌아야 합니다. 원본 벌만 변환하면 벌의 키가 시트에 적힌 형태로 남아 아무것도 못 찾습니다 — 실측으로 119,029건이 그렇게 나왔고, 그것이 이 설계에서 가장 조용했던 결함입니다.

4.4 검증

벌마다 원본과 같은 검사를 돌립니다. 벌끼리 키가 겹치는 것은 정상입니다 — 같은 테이블의 다른 판이므로 Profile 1번과 그 벌의 1번은 같은 행의 두 판입니다.

5. 하지 않는 것

무엇
꼬리표의 뜻을 코어가 아는 것표기가 recipe에 있으므로 코어는 문자열만 봅니다
--target-side처럼 CLI로 벌을 고르는 것고르는 것은 읽는 쪽입니다. 변환은 전부 냅니다
생성되는 코드에 벌의 목록을 넣는 것파일 이름을 만드는 것은 로더의 일입니다
벌마다 다른 스키마오류입니다. 허용하면 테이블이 하나라는 전제가 깨집니다
소스마다 다른 표기테이블 이름은 모델 전체가 공유하는 하나의 이름 공간이라, 두 소스가 다르게 기술하면 모순입니다. 오류로 둡니다

6. 게이트

픽스처 시나리오 row-sets 하나가 규칙을 전부 듭니다. 꼬리표를 _alt로 쓴 것은 의도입니다 — 어느 프로젝트의 표기로 픽스처를 쓰면 그 표기를 검사하게 됩니다.

픽스처의 테이블무엇을 지키는가
Colour · Colour_alt기본형 — 타입 하나, 파일 둘, 꼬리표에 구분자가 남는 것
Paint · Paint_alt벌의 참조가 같은 벌을 향하는 것. 두 벌의 id를 겹치지 않게 두어, 원본에서 찾으면 실패하도록 했습니다
Brush (벌 없음)벌이 없는 대상으로의 되돌아가기
Narrow · Narrow_alt컬럼이 적은 벌이 이름으로 맞춰지고, 없는 컬럼이 「값 없음」으로 읽히는 것

골든 트리가 지키는 것 중 가장 큰 것은 없는 것입니다 — 세 언어 어디에도 ColourAlt 타입이 없어야 합니다.

7. 실측 결과

recipe-all로 전량을 통과시킨 결과입니다.

무엇이전이후
접힌 벌78
생성된 *BCCN 타입730
데이터 파일 대 타입 파일509 / 509509 / 436
없는 행을 가리키는 참조1110

§3이 게이트로 적어 둔 93건은 전부 사라졌고, 나머지 18건도 같이 사라졌습니다.

접지 못한 넷 — 둘은 규칙이 되었고 둘은 시트의 문제입니다

무엇지금
TradeGoodsTownMatrix_BCCN매트릭스라 컬럼이 곧 다른 축의 마을 id입니다. 지역마다 마을 수가 다르니 컬럼 집합이 다릅니다접힙니다 — 4.2의 「격자는 컬럼 id로」
Market_BCCN벌에 demandModifier이 없는데 그 컬럼이 required입니다접힙니다 — 4.2의 「벌이 선언하지 않은 컬럼은 optional」
Profile_BCCN벌에만 있는 컬럼 defaultRegions[5]. 원본이 5개, 벌이 6개입니다시트의 문제. 생성 타입이 테이블에서 나오므로 해결할 수 없는 쪽입니다
AutoMatePassive_BCCN벌의 행이 시트의 :requiredInObject를 어깁니다 (6곳)시트의 문제

앞의 둘이 규칙이 된 이유가 같습니다. 둘 다 「벌마다 컬럼 집합이 다를 수 있다」는 한 가지 사실의 두 얼굴이고, 접기가 이미 그것을 전제로 「없는 컬럼은 값 없음」을 쓰고 있었습니다. 검사와 정렬만 그 전제를 따라오지 못하고 있었습니다.

뒤의 둘은 시트 오류 보고로 갑니다.