데이터베이스 정규화 그리고 조인

안희수·2021년 6월 16일
1

TIL

목록 보기
17/26

데이터베이스 관련 블로그를 적다가 내용이 길어져서 추가로 더 작성하는데 개발을 하면서도 딜레마가 아닐 수 없다.

요즈음에는 데이터베이스 분야 프로그램 분야가 세분화 되어서 필수 교양으로써 데이터베이스를 알고 있을 수는 있어도
프로그래머가 데이터베이스를 깊이 다루는가 하면 그렇지도 않아보여서 하는 말이다.
그런데 적어도 지금까지 겪어온 업곈는 프론트엔드 백엔드 그런 구분 없이 혼자서 다 개발을 진행할 수 있어야 했어서
어디까지 깊게 들어가야 하는가 하는 부분에 대해서는 고민이 많은데
프로그램은 그저 거들뿐 이라는 말이 생각날 정도로 데이터베이스로 더 많은 업무가 처리되었고
프로그램은 입력 데이터의 정합성 체크를 위한 보조 도구이자 결과를 보여주는 화면 그렇게 개발을 해왔다.
다만 백엔드 개발을 하기 위해서는 데이터베이스를 프론트엔드 개발자보다 더 잘 알아야 할 필요성이 있다는 점에 대해서는
동의하면서 글을 써내려 간다.

정규화 란 ?

정규화를 하는 목적을 한마디로 설명하자면 중복된 데이터를 최대한 줄이는 것이라 볼 수 있다.

보통 최적화라고 하는데 중복된 데이터는 관리도 어려울뿐더러 불필요한 저장공간을 가지고 있고 연산결과에도 영향을 주기 때문이다.

사물을 객체로 구현하기 위해서는 먼저 사물을 최상위 부터 하나씩 원자단위로 분해하는 과정을 거치는데 그 구현 사항이 2차원 테이블 상으로 구현되다보면 상위 항목이 공통적으로 포함되므로 테이블 구조의 특성 상 중복된 데이터들이 각 세부 데이터들과 함께 존재하면서 불필요한 중복 데이터가 필연적으로 발생하게 되는데
테이블은 굳이 말하자면 메모리 블록에 가깝기 때문에 융통성 있게 가변적으로 형태를 바꿀 수 없다.

따라서 중복된 데이터를 줄이려면 공통 사항을 한곳으로 모아놓고 필요에 따라서 연결시켜서 하나의 완전한 객체를 생성하게 되는데 그러기 위한 과정이 바로 정규화이다.

정규화 하는 과정

앞서 설명한 과정은 보통 1차 정규화에 가깝다.

1차 정규화라고 하는 것은 현실의 실무에 비유하자면 엑셀의 셀병합 과정을 1차 졍규화로 비유할 수 있다.

엑셀을 사무에서 다루다 보면 공통된 내용이 가시성이 좋지 않아서 공통 항목은 셀 병합으로 하나로 묶는 것을 종종 볼 수 있을텐데 데이터베이스는 이 병합된 행 자체를 분리해서 테이블로 만든 것이라고 볼 수 있겠다.

2차 정규화는 1차 졍규화 된 테이블에서 또 다시 공통된 항목들이 있을 것이다. 그것이 전혀 관계성이 없을 수도 있지만 경우에 따라서는 하나의 공통분모를 가지고 있을수도 있다.

정규화 예시도를 가져온 URL

해당 사진이 아주 좋은 예시인데 아마도 어느 학부의 학생들을 테이블로 표현한 것 같다.
학생번호는 학생 개개인을 나타내고 학생들은 같은 수업을 들을 수도 서로 다른 수업을 들을 수 있다.
그리고 강의의 경우 강의실과 연관되므로 학생과 학생이 듣는 강좌 그리고 성정을 하나로 묶고
그 학생들이 듣고있는 강좌와 강좌가 진행되고 있는 강의실 이렇게 두가지로 분류를 할 수 있을 것이다.
1차 정규화가 생략된 이유는 이미 학생이라고 하는 데이터가 최소단위로 더 이상 중복의 대상이 없으므로
1차 정규화는 이미 진행되었다고 판단하고 있다.

3차 졍규화는 2차 정규화를 진행한 테이블에 대해 이행적 종속을 없애도록 테이블을 분해하는 것으로
이렇게 분해된 데이터들도 잘 찾아보면 다시 하나로 묶을 수 있다. 물론 이것은 할 수도 있고 안할 수도 있는데
과도한 분해 역시 꼭 좋은 것은 아니고 데이터의 성격에 따라서 진행해야 한다.

3차 정규화를 상단 이미지에서 표현해본다면 학생에게 수강료가 종속될 필요는 없다.
학생이 강좌를 듣는거지 학생에게 수강료는 종속의 대상이 아니고 오히려 수강료는 강좌에 종속되어야 더 의미가 있을 것이다.
그래서 원문의 작성자는 3자 정규화를 다음과 같이 표현하였다.

조인이란 ?

그렇다면 조인이라는 것은 무엇인가 ?
조인은 그렇게 파편화한 조각들을 특성에 따라 끼워 맞추는 것이다.

현업에는 이러한 말이 있는데
잘짜여진 쿼리 한줄은 잘못 짠 쿼리 백줄보다 더 높은 성능을 발휘한다.

일단 본인은 그러한 점에서 현업에 있으면서 그리 좋은 평가를 받지 못했다.
쿼리는 얼마나 다양한 고급 기술을 사용하는 것이 아니라 얼마나 데이터의 효율과 관걔를 이해하고 작성하는가가 관건이기 때문이었다.

오라클이건 Mysql MS-Sql PostgreSQL이건 상관없이 SQL이라고 하는 언어는 약간의 차이나 호환성이 있을뿐 거의 동일하다.
그리고 조인은 쿼리의 꽃이라고 많이들 표현하는데 본인이 가장 많이 약했던 부분이다.

흩어진 데이터를 한땀 한땀 이어서 하나의 완제품으로 만드는 것이 쿼리의 조인 개념이라고 한다면 잘 짜여진 조인이라는 것은
비유하자면 옷을 입을 때 첫 단추부터 끝 단추 까지 잘 잠구는 것을 예시로 들 수 있다.
단추를 하나라도 잘못 잠구면 아무리 나머지 단추가 잘 잠겨있어도 옷 맵시가 나지 않듯이 조인 하나를 잘못 짜게되면
결과는 바뀐게 없어 보일지는 몰라도 조회 속도와 데이터베이스 엔진의 부하도에 엄청난 차이를 주게 된다.

조인이라고 하는 것을 잘 하기 위해서는 보통 몇 가지 원칙이 있는데 인덱스를 잘 사용하는 것
그리고 조인의 대상이되는 컬럼이 가급적 해당 테이블의 키가 되는 컬럼을 사용하고
조건절을 사용함에 있어서도 과도한 연산수식을 자제하는 것
이것은 쉽게 말하면 조건절에 특정 값을 비교하되 조건절 안에서 무언가 연산을 해서 비교하는 것을 자제하라는 것이다.
그리고 데이터형을 가급적 동일한 컬럼을 사용할 것 이렇게 들 수 있다.

깊게 설명을 하게 되면 한도끝도 없는 것이 데이터베이스인데
위에 3가지를 하나 하나 간략하게 설명하자면
먼저 인덱스를 적절하게 사용해야 하는 이유로는 데이터베이스 엔진은 인덱스를 최우선적으로 검색하기 때문이다.
인덱스는 보통 테이블의 기본키를 의미하는데 경우에 따라서는
사용자가 인덱스를 정의해서 기본키외 다른 컬럼을 추가해서 사용할 수도 있다.

이를 인덱스스캔과 풀스캔이라고 표현하는데
인덱스스캔은 보통 레인지스캔과 많이 엮여서 설명이 되어지는데
인덱스스캔도 레인지 스캔의 일종이기 때문이다.

자료구조에서 보게 되면 배열과 그 반대적 성격을 가진 연결 리스트를 설명하는데 있어서
배열은 일정한 블록을 사용하기 때문에 검색이라던가 순처적인 데이터 입력에 대해서는 연결리스트보다 월등히 효율적이라고 이야기한다.

풀스캔은 테이블을 통째로 메모리로 끌어와서 검색을 하겠다는 의미이기 때문에
데이터가 많아지면 많아질수록 조회속도도 오래 걸리고 부하도 엄청나다.
하지만 인덱스스캔의 경우 1차적으로 조회할 대상을 추려내기때문에 보다 적은 검색횟수로 동일한 데이터를 저리할 수 있다.
또한 데이터베이스엔진 자체가 인덱스에 최적화 되어있는 구조이기 때문에 엔진의 도움 역시 크다고 볼 수 있다.
문제는 조인을 하는 자식 테이블의 인덱스 컬럼을 사용하지 않는다면 자식테이블의 경우는 풀스캔이 일어나기 때문에
IO 횟수는 조건절이 없는 검색과 차이가 없다.
단일 테이블만을 조회할 때도 검색조건이 인덱스의 대상이 아닐 경우 풀스캔이 발생하게 된다.

두번째로 조인 테이블의 인덱스 컬럼을 조인으로 사용해야 하는 이유 역시 이와 동일한데
일반 컬럼을 사용하게 될 경우 부모 테이블의 검출 행의 갯수 * 자식 테이블 전체의 행 갯수 만큼의 조회가 발생하게 되서 금기 대상이고
부득이한 경우애 한해서만 하도록 되어 있다.

마지막으로 조인을 할 부모 와 자식의 컬럼의 데이터형이 동일한 경우를 사용해야 하는 주된 이유는
데이터형이 다른 경우 부모 테이블의 컬럼을 기준으로
자식 테이블의 조인 컬럼 전부를 데이터베이스가 형변환 해버린 후 조인하기 때문이다.
데이터를 1차적으로 모두 형변환하는 과정에서 꽤 많은 과부화가 발생하기도 하지만
또 다른 문제는 비교연산자의 데이터가 형변환해도 비교할 수 없는 문자와 숫자의 비교가 일어나게 될 경우에는
검색 도중 오류가 발생하게되는데
퀴리문만 돌아가는 상태라면 에러메시지 하나로 끝나겠지만 이것이 실제 프로그램과 연동되어 있는 상황이라면
십중팔구 프로그램이 죽거나 중대한 에러가 발생하게 될 것이다.

대부분의 경우에는 예외처리가 되어 있어 당장 시각적으로 큰 문제가 발생하지는 않겠지만
전에 있었던 업계는 자동화 시스템으로 매 시간마다 데이터베이스의 값을 요청하고
대용량 데이터를 일괄적으로 처리하는 업무가 주된 일이었기 때문에
잘못 짠 쿼리 하나로 인해 고객사의 시스템을 망가뜨려본 경험도 있었다.

그래서 데이터베이스는 가장 많이 다뤄보았지만 가장 어렵고 대하기 힘든 분야이다.

맺는 말

본인은 누구보다 많이 에러를 발생시켜왔고
누구보다 많이 시행착오를 겪어왔음에도
여전히 프로그램 특히 데이터베이스 분야는 아직까지도 많이 생소하게 느껴진다.

백엔드 개발자를 지향하면서 데이터베이스는 어쩌면 뗄레야 뗄 수 없는 애증의 관계이고
가장 많이 봐았던 분야이기 때문에 어쩌면 가장 자신있으면서도 자신이 없는 분야이다.

이전까지 써왔던 다른 기술블로그 기고문에 비해서도 엄청나게 길게 쓰고 있는데
그만큼 프로그래밍 언어보다도 더 많이 겪어왔기 때문이 아닐까 싶다.
새롭게 배워나가고 초심으로 돌아간다는 기분으로 매일 매일 공부를 해 나가고 있는데
이번에 백엔드 개발자로써 다시 시작하게 된다고 한다면
부디 프로그래머로써 또 한번 좌절하지 않았으면 좋겠다.

profile
9년차 소프트웨어 개발자 (2024년 재 개편 예정입니다)

0개의 댓글