26.물리적 데이터 모델링
- 논리적 데이터 모델링이 관계형 데이터베이스에 맞는 이상적인 표를 만드는것이라면 물리적 데이터 모델링은 이상적인 표를 구체적인 제품에 맞는 현실적인 표를 만드는것. 특히 이단계에서 중요한 것은 성능이다. 지금부터 어떻게성능을 향상시킬수있는지에 대한 이야기를 해볼것임.
- 운영을 조금이라도 해보는것. 데이터가 쌓이고 처리량이 많아져야 분별력이 생기고 적당한 시점에서 각 쿼리의 성능을 평가해보고 병목이 발생하는 지점을 집중적으로 해결하는 거이 바람직하다고 생각한다. 이때 사용해볼 방법은 슬로우 커리라고해서 여러가지 쿼리가 동작할때 특히 느려지는 쿼리가 있을텐데 이걸 찾을수있는게 제품마다 다르다. 우리가 사용하는 데이터 베이스 제품에 이름을 붙여서 검색하면 어디서 병목이 발생하는지 찾을수있다.
- 이런방식을 통해 느려지는 지점을 찾았다면 성능을 향상시키기위한 여러가지 방법들을 적용해봐야한다. 최후에는 이상적으로 정교화된 표에 구조를 손해되는것이다.(?❓)
- 이러한 행위를 역정규화 혹은 반정규화라고 한다. 근데 역정규화는 혹독한 대가를 치뤄야되니 따라서 역정규화를 시도하기 이전에 다른 방법을 찾아보는게 바람직하다.
1) 인덱스
:행에 대한 읽기 성능을 비약적으로 향상시킨다. 대신 쓰기 성능을 비관적으로 희생시킨다. 쓰기가 이루어질 때마다 행이 인덱스가 걸려있다면 입력된 정보를 잘 정리 정돈하기 위한 복잡한 전상과정이 필요하다. 이과정에서 시간이 많이 걸릴 뿐만 아니라 저장 공간을 더욱 많이 찾게된다. 그럼에도 불구하고 인덱스를 사용하는 이유는 이렇게 잘 정리정돈하면 엄청난 빠른속도로 읽을수있기 때문에2)캐시 —> 애플리케이션 영역에서 쓰는 방법
: 저장하다라는 뜻의 캐시 cach 입력에 따른 실행결과를 저장해 뒀다가 나중에 동일한 입력이 들어왔을 때 저장해둔 결과를 사용하는 것을 통해서 데이터베이스의 부하를 주지않는 것. 이렇게 하면 db가 겪게되는 부하를 획기적으로 줄일수있다.3) 표의 구조를 바꾸는 외과적인 수술.. -> 역정교화 시도..(최후의 방법)
27.역정규화 소개
- 역정규화라는 것은 정규화를 통해 만든이상적 표를 성능이나. 개발의 편의성을 위해 조작하는 것이 역정규화라고 할수있다. 기본적으로 정규화라는 것은 정의하는것이 뭐 한마디로 어렵지만 대체로 쓰기에 편리함을 위해 읽기의 성능을 희생한것. 왜냐면 정교화하게 되면 표들이 여러개로 쪼개지고 그 표들을 다시 사용할때는 조인을 통해서 할때해야되는데 조인은 굉장히 비싼 작업이다. 그래서 읽기의 성능이 희생되게 되는데 이때 앱을 운영하다보면은 읽기가 굉장히 자주 일어나는데 이때에 정규화로 인해서 성능이 느려지는 케이스가 종종 생긴다.
- 그럴땐 여러가지 방법들을 먼저해보고 최후의 수단으로 역정교화 즉 표의 구조를 다시 바꾸는 작업을 하게 되는 것. 기억하실 것은 일단 정규화를 한 다음에 역 정교화를 하는거지 아예 정규화를 하지 않는 표가 좋은거라고 할수없다. 그리고 정규화를 한다고해서 반드시 성능이 떨어지는게 아니기 때문에 정규화는 성능을 떨어뜨린다라는 너무 단순한 일반화도 좋지않다!!!!!!
- 구글 스프레드 시트에다가 denormalization 문서를 만듬 (denormalization 문서)
- orgin이라는 부분이 현재 우리가 가지고 있는 표들임. 데이터 해석을 지금할 필요는 없음.
- 실험용 데이터가 우측에 있는데 마우스 올려보면 표를 만들기 위한 sql문이 있음 (mysql 기반) 다른 디비 제품에서는 수정필요
- 이 orgin 테이블을 이렇게 저렇게 역정규화 해볼것이다.
1) 컬럼의 역정규화
- 하나의 표 안에서 컬럼을 바꿔볼것임
2) 테이블의 역정규화
- 하나의 표를 여러개의 표로 쪼개는 것
3) 관계의 역정규화
- 테이블과 테이블 사이의 관계성을 조작해서 일종의 지름길을 만들것임
우리가 말하는 정규화는 엄격한 규칙에 따라 공정을 거쳐가듯이 순차적으로 진행하는 것이 정규화인데 역정규화라는것은 어떤 규칙이 있는 것이 아님. 그냥 상황판단해서 진행하는 것임. 엄밀한 공정이 아니라 이런 기법들이 있을 수있다라는 일종의 샘플이다. —> 법칙처럼 받아들이지는 말아라..
28.역정규화 - 컬럼을 조작해서 join을 줄이기
- 하나의 테이블 안에서 컬럼을 조작하는 것을 통해 성능을 향상시키는 방법을 살펴보자 성능을 향상시키는데 있어서 가장 중요한 대상 중 하나는 조인을 줄이는 것.. 이건 굉장히 비싼 작업임
- 여기에 topic 태그 릴레이션이라는 표가 있고 태그라는 표가 있다. 그중에서 topic_title값이 mysql이라는 행의 이름을 알고싶다. 근데 문제는 이 테이블에는 태그 id값이 있고 실제 이름은 그 id 값과 연결된 태그라고하는 표에 존재한다. 그렇기 때문에 우리는 지금 조인이 필요한 상태이다. 그럼 쿼리를 한번 때려보자.
- Mysql workbench 도구 이용
- topic_tag_realation의 topic_title의 값이 mysql이라는 것을 찾아내야되기 때문에
SELECT
FROM topic_tag_relation
LEFT JOIN tag
ON TTR.tag_id=tag.id # 테그 릴레이션을 ttr이라고 줄여줌 . Ttr이라는 별명을 가지고 있는 테이블에 tag_id 와 tag id 값이 같다라고 해서 이렇게하면 조인이 되어서 나옴.
WHERE topic_title = ‘MySQL’;
이런 서비스를 운영하다보면 이런 조회가 굉장히 많이 일어날수도 있다. 어떤 서비스이냐에 따라서 그걸로 인해서 굉장히 시스템의 부하가 일어나고 사용자의 경험이 급격히 나빠지고 있다면 방법이 필요한 것임.
우리가 선택할수있는 방법은 여러가지가 있지만 그 중 가장 쉬운방법은 topic_tag_relation 을 조회할때 아예 표 안에 tag_id 값에 해당되는 tag 의 이름이 뭔지를 넣어라 —> 중복허용
그럼 우리가 싫어하는 중복이 발생하긴 하나 우리는 조인을 하지않고 표를 다를 수 있게 되었다.
SELECT tag_name FROM topic_tag_relation WHERE topic_title = ‘MySQL’;
결과는 동일하나 join을 하지 않기 때문에 훨씬 더 빠르게 데이터를 가져올 수 있게 된다. 이런걸 역정규화라고 한다.—> 역정규화를 하면 우리가 정규화 하기 전에 있었던 문제를 고스란히 받게됨. (중복이 있으니 수정하려면 다 수정해야되고 & 기존의 태그 테이블은 그대로 있기 때문에 안좋은 상황) 따라서 역정규화를 하게 되면 시스템의 복잡도가 엄청 높아져 프로그램이 고장나기가 훨씬 시워진다. 그럼에도 하는 이유는 성능을 향샹시키기 위해서임… 을 명심해라
📌처음부터 역정규화를 하겠다고해서 정규화를 소홀히 하면 안된다!!!
29.역정규화 : 컬럼을 조작해서 계산을 줄이기
- 이전시간에는 조인을 줄이는 것에 초점이 맞춰져있다면 이번 시간에 살펴볼 역정규화는 어떤 데이터를 우리가 처리하는 비용을 줄이기 위한 역정규화를 살펴 볼 것임.
- 목표: 각각의 저자별로 몇개의 토픽을 생성했는가를 알고싶은것. 그러기 위해서는 topic 테이블에 있는 author id 값들이 각각의 author id 별로 author id 가 같은 행이 몇개가 있는지 카운팅 하면 된다.
- Topic 테이블에서 author id 별로 몇개의 행들을 가지고 있는가를 볼 것임
SELECT*FROM topic GROUP BY author_id
—>이렇게 하면 author_id 별로 그룹핑을 해주게 됨 근데 이걸로만은 실행이 안되고 하단처럼 바꿔줘야된다.
SELECT author_id COUNT(author_id)
FROM
topic
GROUP BY author_id;
이게 매우 빈번한 작업이라면 Group by는 사용하기 아주 비싼 작업이 될수도 있다. 그래서 머리를써보니 이런식의 역정교화를 생각할수있다. 그러면 author라고 하는 테이블에 컬럼을 추가해서 몇개의 글을 가지고 있는지를 topic 테이블의 행을 추가할때마다 추가 하면서 동시에 그 추가한 그 행에 os 아이디에 count값을 1씩 증가 시키면 어떨까라는 생각을 하시게 된다면 여러분은 이제 직감적으로 역정규화를 생각하고 있는 것.
author라고 생긴 테이블의 칼럼을 복사해서 역정규화 된 표 라고 할 것임. 그다음 옆에 topic_count . 현재 상태에서 김은 2개 이는 1개라고 유지되려고하는 . 이를 위해서 author 테이블에 토픽 카운트를 추가하는 ALTER 문을 추가했고 내용도 살짝 수정을 함.
이제 실행을 해보자 author 테이블의 topic_count라고 하는 컬럼이 이미있기 때문 앞으로 GROUP BY를 할것이 아니라 author 테이블의 id와 topic_count /author 라고 하면 보시는 것 처럼 이전과 똑같은 결과를 얻지만 그냥 계산된 결과인 topic_count를 출력하기 때문에 훨씬더 빠르게 처리할 수 있다. 다만 이렇게 했을때 우리가 잃게 되는것은 topic_count라고 하는 값을 항상 유지시켜줘야되는 어려움이 생긴다. 그렇기 때문에 역정규화를 했을 때 얻는것과 잃는것이 분명히 트레이드 오프가 있기 때문에 현명하게 선택해라.
30.역정규화:표를 쪼개기
-토픽테이블을 쪼개는 방법은 컬럼/행 기준으로 쪼갤수도 있다.
1) column기준으로 쪼개는것 : topic 테이블에있는 description이라고하는 텍스트의 값이 용량히 굉장히 크고 topic 테이블의 description을 제외한 나머지 컬럼들을 조회하는 오퍼레이션과 description을 포함해서 조회하는 오퍼레이션이 양쪽다 굉장히 많을 때 처리를 할 수 있다.
- Topic 테이블에서 description만 제외한 테이블을 만든다.
- Topic 테이블에서 primary key 와 description만 가지고 있는 topic_description이라는 테이블은 만든다. 이렇게하면 용량이 큰 description이라고하는 컬럼은 topic에 없기 때문에 여러가지 장점들을 가지게됨.
- 이렇게 쪼개개 되면 토픽도 조회가 많고 topic_description도 사용량이 엄청나게 많다면 각각의 표들을 각자 다른 컴퓨터에 저장해서 그 컴퓨터에서 쓰기 읽기와 같은 방법을 시키면 컴퓨터 1대로 처리하던 일을 분산시킬수있어 성능 향상 가능 —> Sharding
- Sharding: 데이터베이스 운영할때 성능에 한계가 느껴졌을 때 여러 대의 컴퓨터로 Scale out 하는 기법 (최후의 수단)
2) 행의 기준으로 쪼개기 : 이전시간에 살펴봤던 컬럼의 기준으로 해서 분리하는 방법은 지금 보는것처럼 컬럼의숫자가 많아봐야 얼마나 많아봤자 이니 한계가 있는데 행의 기준으로 분리하는 것은 이론적으로는 한계가 없으나 관리하는게 굉장히 어렵다.
- topic table에 보면 author id가 1.2 이렇게 있다. 만약 사용자가 1억명이 넘는 어마어마 하게 많은 조회가 일어나는 서비스라면 author id가 1번부터 1000번까지는 topic_1000이라는 표를 쓰고 1000번부터 2000번까지는 topic_2000이라는 테이블을 쓰게 하는 방식으로
- 사용자 author id 가 1번이라고 하면 앱이 topic_1000이라고 하는 표가 있는 서버쪽으로 쿼리를 보내 데이터를 추가함. 읽을때도 마찬가지 즉) 사용자가 누구냐에 따라 그 사람이 데이터를 저장해야되는 표를 구분하게 됨. 그렇게 되면 각각의 물리적인 서버마다 서로 다른 표를 저장하고 서로다른 조회를 처리하는 것을 통해서 무한히 많은 처리량을 소화할수있게 되는것….( 이런 처리는 노하우도 필요하고 사고 위험도도 높아 어렵다..이건 코너에 몰렸을 때하는 것..)
테이블의 역정규화는 대체로 여러대의 서버로 분산시킬때 사용할수있는 방법!!
31.역정규화:관계의 역정규화
- 조인을 줄여서 지름길을 만드는 테! 크 !닉 ! 컬럼의 역정규화와도 사실 비슷한 내용인데 다만 이제 foreignkey를 추가해서 join을 줄이기는 점에 약간의 차이가 있다.
- 특정한 저자의 태그 id와 태그 명을 제외하고 싶다. 이때 우리가 topic_tag_relation 테이블과 테그 테이블을 조인시키면 되는데 이제 두개의 표에는 author_id값이 없어서 토픽 테이블까지도 조인에 참여를 시켜야한다. 이문제를 우리가 낮추는 역정규화하는 방법을 살펴볼것임
- topic_tag_relation을 먼저 셀렉트 할것임. #SELECT*FROM topic_tag_relation
- 너무 기니까 ttr이라는 별명 줄것. SELECT*FROM topic_tag_relation AS TTR;
- 원하는 값은 name값인데 이건 테이블이 안가지고 있어서 left join으로 붙일것임. LEFT JOIN tag ON TTR_tag_id = tag.id;
- Author id 가 1과같은 사람의 태그 정보만 가져오고 싶다. 여기 author_id가 없어서 where을 쓸수가없어서 topic tag를 조인할수밖에 없다 LEFT JOIN topic ON TTR_topic_title = topic.title
- 그 안에는 author_id가 있기 때문에 where문을 통해서 id가 1인 사용자의 정보만 가져온다. 태그의 id와 태그의 name만 출력할수있다.
WHERE author_id = 1;
```sql
SELECT
tag.id, tag.name - FROM
topic_tag_relation AS TTR
LEFT JOIN tag ON TTR_tag_id = tag.id
LEFT JOIN topic ON TTR_topic_title = topic.title
WHERE author_id = 1;
``` - 그런데 이런 오퍼레이션이 자주일어나면 조인이 너무 많아 시스템 성능을 저하시킬 위험이 있다. 그래서 topic_tag_relation이라고 하는 테이블에 author_id라고 하는 컬럼을 추가해서 저 테이블에 있는 author_id값만 가지고 조회를 할수있도록 하면 조인을 줄일수있을거같다. 그래서 표를 바꿔보겠다.
- author_id 값을 줘서 어떤 저자의 태그인가를 이렇게 표시할것임. 표를 이런 구조로 바꾸고 데이터를 바꾸는 쿼리를 적을 것이담/-> 역정규화 쿼리
- 이렇게 만들어진 표에서 이렇게 조인을 3번했는데 이제는 조인을 2번만 하면 된다!!
WHERE TTR.author_id =1; #하단 결과물
- tag.id, tag.name
쿼리를 작성해보자
SELECT
*
tag.id, tag.name
FROM topic_relation AS TTR
LEFT JOIN tag ON TTR.tag_id = tag.id #author_id라고 하는 컬럼이 추가된걸 볼수있다. 그렇기 때문에 추가적인 조인작업을 안해도 된다.
WHERE TTR.author_id =1;
32.수업을 마치며
강사님 머릿속에 떠오른 단어는 중용..
순수하게 이상적인 것을 향해가다가 물리적인 모델링단계에서 현실에 맞게 수정하는게 인상적이었다.
마치 인간세계에서 사상가들에 의해 고안된 순수한 이념들이 현실을 반영하기 위해 수정되는 것과 비슷하지 않나요.. 이상적인 것들이 없다면 현실은 너무나 혼란스러울것이고 이상이 현실을 외면한다면 이상은 더 이상 이상적이지 않을것입니다. 데이터 모델링은 하나의 공식이라기 보다는. 제 느낌상으로는 문학의 고전에 가깝다. 고전이란 좋은 작품을 모아놓은것 그말은 2가지 의미를 내포한다. 1)고전에 속한 작품은 괜찮은 작품이다. 2) 고전에 속하지 못했다고 괜찮지 못한것은 아니다
즉 데이터 모델링에서 소개하지않은 괜찮은 방법이 있을수도 있다. 우리가 배운 지식을 엄격하게 자신의 삶에 적용하는 것은 중요하지만 동시에 이런 지식을 만든사람들은 엄격함과는 거리가 먼 자유로운 사람들이었을 것이다. 그런점에서 엄격하면서도 자유롭게 자유로우면서도 엄격하게 지식을 대해야겠다라는 걸 다짐해보자.
어떻게 하면 최소한으로 배워서 내가 알게된 것을 최대한 사용할 것인가를 이제 궁리해보자
끝났다ㅠㅠ아쉽네
'STUDY > SQL' 카테고리의 다른 글
SQL 입문하기 - 1주차 (0) | 2021.05.09 |
---|---|
MySQL 데이터베이스 한번에 끝내기 (0) | 2021.05.09 |
[생활코딩] 관계형 데이터 모델링 (22-25강의 : 정규화) (0) | 2021.05.09 |
[생활코딩] 관계형 데이터 모델링 (15-21강의 : 논리적 데이터 모델링) (0) | 2021.05.09 |
[생활코딩] 관계형 데이터 모델링 (8-14강의 : 개념적 모델링) (0) | 2021.05.09 |