슬롯 게임 DB 설계서를 읽다가 정규화가 안 된 자리가 두 곳 눈에 띄었다.
Table of contents
Open Table of contents
릴이 문자열이었다
슬롯 정보 테이블에 릴 컬럼이 다섯 개 있다.
reel1 varchar
reel2 varchar
reel3 varchar
reel4 varchar
reel5 varchar
값이 이렇다.
1,2,3,4,5,6,7,8,9,10,11,1,2,3,4,5,6,7,8,9,10,11,5,2,11,3,4,6,11,2,1,10,10,9,9
심볼 번호를 콤마로 이어 놓은 것이다. VARCHAR 한 칸에 배열이 들어가 있다.
설명에 이렇게 적혀 있었다.
콤마를 구분자로 심볼 번호를 연결한다
심볼 배치 칸 수는 변동될 수 있고
마지막 번호 뒤에는 콤마를 붙이지 않는다
비교 — 정규화하면 어떤 모양인가
배운 대로라면 이렇게 나눠야 한다.
reel_symbol
slot_num
reel_num 1~5
position 1~35
symbol_num
릴 하나에 35행이고 슬롯 하나에 175행이 되는데 나눴을 때 무엇이 좋아지는지 따져 봤다.
조회 특정 심볼이 어느 위치에 있나 — SQL로 찾을 수 있다
검증 심볼 번호가 유효한지 외래키로 걸 수 있다
변경 한 칸만 고칠 수 있다
왜 안 나눴나 생각해 봤다
실제로 이 데이터를 어떻게 쓰는지를 보니 달랐다. 릴 정보 API 는 슬롯 하나의 릴 다섯 개를 통째로 내려주고 클라이언트가 받아서 explode 로 잘라 쓴다.
통째로 쓰면 한 행 읽어서 그대로 전달
나누면 175행 읽어서 다시 조립
나누면 매번 ORDER BY position 으로 여러 행을 읽어 다시 조립해야 한다. 쓰는 방식이 통째다.
변경 쪽도 생각해 봤다. 릴 배치를 바꾼다는 것은 게임 밸런스를 바꾸는 것이라 한 칸만 바꾸는 일보다 전체를 다시 짜는 일에 가깝고 그러면 통째로 덮는 것이 자연스럽다.
설명의 칸 수가 변동될 수 있다는 문장도 걸렸다. 정규화했으면 행 수가 달라지는 것이라 문제가 없고 문자열이면 길이가 달라지는 것이라 이것도 문제가 없다. 둘 다 되긴 되는데 문자열 쪽은 길이 제한이 걸려서 35칸이면 100자쯤이고 칸 수가 크게 늘면 컬럼 길이를 봐야 한다.
페이라인은 더 특이했다
두 번째 자리는 페이라인 테이블의 패턴 컬럼이었다.
x,x,x,x,x,o,o,o,o,o,x,x,x,x,x
설명이 이랬다.
페이라인은 다음과 같은 위치 번호를 갖는다
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
각 위치별로 상태값을 가지며
비선택은 'x', 선택은 'o'
3행 5열 격자를 15칸 문자열로 펴 놓은 것이고 위 예제는 가운데 행이 전부 선택된 일직선이다.
1~5 첫 행
6~10 둘째 행
11~15 셋째 행
행 우선으로 편 것이다. 이 형식의 장점이 하나 보였다.
x,x,x,x,x,o,o,o,o,o,x,x,x,x,x 가운데 가로줄
o,o,o,o,o,x,x,x,x,x,x,x,x,x,x 윗 가로줄
o,x,x,x,o,x,o,x,o,x,x,x,o,x,x V자
값만 봐도 모양이 짐작된다. 정규화해서 (payline, position, selected) 15행으로 두면 한 행씩 봐서는 모양이 안 보이고 조립해 봐야 안다. 사람이 확인할 일이 있는 자료에서는 이 점이 꽤 크다.
판단 기준과 대가
두 자리를 보고 나니 공통점이 있었다. 릴도 페이라인도 통째로 읽고 통째로 쓰며 부분을 따로 다루지 않는다.
그리고 개수가 고정에 가깝다. 35칸과 15칸이고 게임 종류에 따라 정해지면 잘 안 바뀐다. 이런 경우에는 나누는 이득이 크지 않아 보였다. 판단 기준이 정규화 규칙 자체가 아니라 이 자료를 어떻게 쓰는지에 있었다.
다만 문자열로 두면서 잃는 것도 분명히 있었다.
심볼 번호가 유효한지 DB가 검사 못 한다
구분자가 빠지거나 하나 더 들어가도 저장은 된다
길이가 컬럼 한계를 넘으면 잘린다
그 판의 MySQL 은 CHECK 를 파싱만 하고 무시하니 나눠 뒀어도 범위까지는 못 막았겠지만 개수와 타입은 컬럼 정의가 지켜 준다. 조건으로 쓰려 해도 FIND_IN_SET 은 인덱스를 못 타서 전수 스캔이 된다.
형식이 맞는지는 애플리케이션이 책임지는 셈이고 설명에 마지막 번호 뒤에는 콤마를 붙이지 않는다가 적혀 있는 이유도 그것으로 보인다. 규칙을 DB 가 못 지키니 문서에 적어 둔 것이다.
정리
- 릴 배치와 페이라인이
VARCHAR한 칸에 들어가 있다 - 쓰는 방식이 통째로 읽고 통째로 쓰는 형태라 나누는 이득이 작다
- 나누면 175행을
ORDER BY position으로 읽어 조립해야 한다 - 격자를 행 우선으로 편 문자열은 값만 봐도 모양이 짐작된다
- 개수가 고정에 가까우면
explode하는 쪽이 다루기 쉽다 - 대신 DB 가 개수와 타입과 범위를 검사하지 못한다
FIND_IN_SET으로 조건을 걸면 인덱스를 못 타 전수 스캔이 된다- 그래서 구분자 규칙 같은 것이 설계서에 적혀 있다
- 부분을 조회하거나 부분만 바꾸는 자료라면 나누는 쪽이 맞다