Skip to content
isdnetworks
Go back

배열을 문자열에 넣어 뒀다

슬롯 게임 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 가 못 지키니 문서에 적어 둔 것이다.

정리


Share this post on:

Previous Post
포기한 것과 지운 것을 같이 다뤘다
Next Post
저장할 때마다 무거운 계산이 돌았다