[MySQL] X코리아를 보며 설계 연습중 질문 0 1 843

by 내몸매GROUPBY [MySQL] [2019.06.21 20:09:06]


Maria 데이터베이스로 잡X리아를 보며 설계 연습을 하고 있습니다.

일단 회사 구인 공고 리스트 페이지를 보고 이런식으로 가져와야 겠다라고 생각해서 만들어보았는데요..

(완전 똑같게하진 않았습니다)

 

TB_COMPANY (회사)

SEQ | NAME | TEL | ADDRESS | REG_TIME

1 | 한국상사 | 0212341234 | 서울특별시 마포구 .... | 2013-03-11 12:11:11

 

TB_RECRUIT (모집)

SEQ | COMPANY_SEQ | TITLE | CONTENT | RECRUIT_DEADLINE (마감 일시) | REG_TIME 

1 | 1 | 디자이너 구해요~ | (*)$#@*&(@# | 2019-07-03 23:59:59 | 2019-06-26 12:23:11

...

 

TB_CAREER_CD (경력)

CD | NAME | POSITION

FR | 신입 | 1

1Y | 1년 | 2

..

TB_JOB_TYPE_CD (고용 형태)

CD | NAME | POSITION

PT | 아르바이트 | 1

CW | 계약직 | 2

...

 

TB_RECRUIT_CAREER (모집 - 경력 매핑 테이블, 한 모집 당 여러 경력을 원할 수 있다고 생각)

RECRUIT_SEQ | CAREER_CD

1 | FR

1 | 1Y

...

 

TB_RECRUIT_JOB_TYPE (모집 - 고용 형태 매핑 테이블, 한 모집 당 여러 고용 형태를 제시할 수 있다고 생각)

RECRUIT_SEQ | JOB_TYPE_CD

1 | CW

 

이제 구인 공고 리스트에서는 회사명, 회사 주소, 고용 형태, 경력을 보여주면 되겠다고 생각했습니다.

먼저 모집과 회사를 조인했습니다.

 

SELECT
    R.TITLE,
    R.CONTENT,
    R.REG_TIME,
    C.NAME,
    C.ADDRESS
FROM TB_RECRUIT R INNER JOIN TB_COMPANY C
ON R.COMPANY_SEQ = C.SEQ
ORDER BY R.SEQ DESC
LIMIT 20;

 

이제 해당 모집에서 원하는 경력을 보여주려 합니다.

만일 경력을 신입 또는 2년이라고 표시하려면 GROUP_CONCAT을 써야한다고 생각했습니다.

SELECT
    R.TITLE,
    R.CONTENT,
    R.REG_TIME,
    C.NAME,
    C.ADDRESS,
    RC.CAREERS
FROM TB_RECRUIT R INNER JOIN TB_COMPANY C
ON R.COMPANY_SEQ = C.SEQ
INNER JOIN (
    SELECT
        RC.RECRUIT_SEQ,
        GROUP_CONCAT(C.NAME) AS CAREERS
    FROM TB_RECRUIT_CAREER RC INNER JOIN TB_CAREER_CD C
   ON RC.CAREER_CD = C.CD
   GROUP BY RC.RECRUIT_SEQ
) RC
ON RC.RECRUIT_SEQ = R.SEQ
ORDER BY R.SEQ DESC
LIMIT 20;

 

이제 고용 형태가 아르바이트 또는 계약직 이런식으로 표시하려면 방금 경력을 추가한 것처럼 조인을 한번 더 하게 됩니다.

만일 공고 관련하여 다른 옵션이 추가된다면 (복지같은) 조인하는 테이블은 계속 늘어나겠죠..

 

그래서 다른 한편으로는 그냥 TB_RECRUIT 테이블에 CAREERS, JOB_TYPES 컬럼을 추가하여

코드 값을 저장하지 않고 해당 코드의 NAME 값을 GROUOP_CONCAT으로 묶어 저장할까 했습니다.

 

TB_RECRUIT (모집)

SEQ | COMPANY_SEQ | TITLE | CONTENT | RECRUIT_DEADLINE (마감 일시) | REG_TIME | CAREERS | JOB_TYPES

1 | 1 | 디자이너 구해요~ | (*)$#@*&(@# | 2019-07-03 23:59:59 | 2019-06-26 12:23:11 | 신입, 1년, 2년 | 계약직, 정규직

 

하지만 이렇게되면 코드 값을 참조하지 않기 때문에 코드 자체가 없어지거나 변경되면 반영이 되지 않으므로 관계형 데이터베이스에서는 맞지 않다고 생각합니다..ㅠ

하지만 불필요한 조인을 줄일 수 있겟죠..

결론은 제 설계가 잘못된거 같은데..어떻게 하면 좀 더 개선시킬 수 있을까요?

 

by 르매 [2019.06.22 10:20:56]

당연히 원칙도 정답도 아닌 개인적으로 드리는 가이드입니다.

적절히 취사선택하시기 바랍니다.

1. 코드의 key, valule 쌍을 테이블로 정의해 두는 것은 필요할 수 있지만, 이런 테이블을 서비스에서 직접 JOIN 하여 value를 가져오는 것은 성능면에서 별로 권하고 싶지 않습니다. DB에는 key만 저장하고 key와 쌍을 이루는 value는 웹 서버가 별도의 데이터 구조체 - json 파일이라던가 - 를 가지고 있게해서 그 곳으로부터 value를 추출하게 하면 됩니다.

2. 1:n의 성격을 가지는 속성의 설계는.. TB_RECRUIT_CAREER 같은 매핑 테이블을 사용할 수도 있고, TB_RECRUIT 테이블에서 컬럼으로 관리할 수도 있습니다.

어느 쪽을 선택할 지 판단하는 기준 한 가지는 "검색 필터로 사용될 일이 있는가?" 입니다.

본문에 나오는 경력이나 고용형태는 채용사이트에서 검색할 때 사용하는 기본 필터 중 하나이기 때문에 WHERE 절에서 사용되는 성격이니 정규화해야겠네요.

그럼 목록을 SELECT 할 때마다 GROUP_CONCAT() 해야 하는 상황은 어떻게 해결해야 할까요?

채용 공고는 한 번 올라가면 수정 자체가 빈번한 작업은 아닙니다. 이런 경우에는 정규화와 역정규화를 함께 해 줍니다.

즉, 검색과 무결성 보장을 위한 별도의 매핑 테이블도 만들고 목록을 SELECT할 때 발생하는 그룹핑과 조인을 피하기 위해 그 결과를 미리 컬럼으로도 가지고 있는거죠. 개인적으로 이런 컬럼은 JSON 으로 저장합니다. 이때 주의할 점은 당연히 트랜잭션 처리겠죠. 매핑 테이블의 데이터와  JSON으로 저장한 데이터가 일치하도록 신경 써 줘야 합니다.

 

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입