<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Backend 공부 기록</title>
        <link>https://velog.io/</link>
        <description>백엔드 개발자 지망생</description>
        <lastBuildDate>Sat, 02 Sep 2023 08:21:10 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Backend 공부 기록</title>
            <url>https://velog.velcdn.com/images/jam2_boyak/profile/df525b29-1ef4-4c3d-a1d7-1e408352d374/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Backend 공부 기록. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jam2_boyak" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SQLD] 함수적 종속성과 정규화]]></title>
            <link>https://velog.io/@jam2_boyak/SQLD-%EC%A0%95%EA%B7%9C%ED%99%94%EC%99%80-%EC%9D%B4%EC%83%81%ED%98%84%EC%83%81-%ED%95%A8%EC%88%98%EC%A0%81-%EC%A2%85%EC%86%8D%EC%84%B1</link>
            <guid>https://velog.io/@jam2_boyak/SQLD-%EC%A0%95%EA%B7%9C%ED%99%94%EC%99%80-%EC%9D%B4%EC%83%81%ED%98%84%EC%83%81-%ED%95%A8%EC%88%98%EC%A0%81-%EC%A2%85%EC%86%8D%EC%84%B1</guid>
            <pubDate>Sat, 02 Sep 2023 08:21:10 GMT</pubDate>
            <description><![CDATA[<h4 id="정규화와-이상현상-함수적-종속성">정규화와 이상현상, 함수적 종속성</h4>
<ol>
<li><p>정규화</p>
<ul>
<li>이상 현상을 제거하면서 데이터베이스를 올바르게 설계해나가는 과정</li>
<li>함수적 종속성을 판단하여 정규화를 수행함</li>
</ul>
</li>
<li><p>이상현상</p>
<ul>
<li>불필요한 데이터 중복으로 인해 릴레이션에 대한 데이터 삽입, 수정, 삭제 연산을 수행할 때 발생할 수 있는 부작용</li>
<li>삽입 이상: 새 데이터를 삽입하기 위해 불필요한 데이터도 함께 삽입해야 하는 문제</li>
<li>갱신 이상: 중복 튜플 중 일부만 변경하여 데이터가 불일치하게 되는 모순의 문제</li>
<li>튜플을 삭제하면 꼭 필요한 데이터까지 함께 삭제되는 데이터 손실의 문제</li>
</ul>
</li>
<li><p>함수적 종속성(FD: Functional Dependency)</p>
<ol>
<li>함수 종속: X가 Y를 함수적으로 결정한다<ul>
<li>릴레이션 내의 모든 튜플에서 하나의 X값에 항상 하나의 Y값이 대응</li>
<li>X, Y는 하나의 릴레이션을 구성하는 속성들의 부분 집합</li>
<li>X는 결정자, Y는 종속자</li>
<li>X → Y로 표현</li>
</ul>
</li>
<li>함수 종속 관계 판단 시 유의사항<ul>
<li>속성 자체의 특성과 의미를 기반으로 함수 종속성을 판단해야 함</li>
<li>일반적으로 기본 키와 후보 키는 릴레이션의 다른 모든 속성들을 함수적으로 결정함</li>
<li>기본 키나 후보 키가 아니어도 다른 속성 값을 유일하게 결정하는 속성은 함수 종속 관계에서 결정자가 될 수 있음</li>
</ul>
</li>
<li>함수 종속의 유형<ol>
<li>완전 함수 종속<ul>
<li>릴레이션에서 속성 집합 Y가 속성 집합 X에 함수적으로 종속되어 있지만, 속성 집합 X의 전체가 아닌 일부분에는 종속되지 않음을 의미.</li>
<li>일반적으로 함수 종속은 완전 함수 종속을 의미</li>
</ul>
</li>
<li>부분 함수 종속<ul>
<li>릴레이션에서 속성 집합 Y가 속성 집합 X의 전체가 아닌 일부분에도 함수적으로 종속됨을 의미</li>
</ul>
</li>
<li>이행적 함수 종속<ul>
<li>릴레이션을 구성하는 3개의 속성 집합 X, Y, Z에 대한 함수 종속 관계</li>
<li>X → Y, Y → Z가 존재하면 X → Z가 성립</li>
<li>이 때, Z가 X에 이행적으로 함수 종속되었다고 함</li>
</ul>
</li>
<li>고려할 필요가 없는 함수 종속 관계<ul>
<li>결정자와 종속자가 같거나, 결정자가 종속자를 포함하는 것처럼 당연한 함수 종속 관계는 고려하지 않음</li>
</ul>
</li>
</ol>
</li>
</ol>
</li>
<li><p>기본 정규형과 정규화 과정</p>
<ol>
<li>정규화의 목표<ul>
<li>함수 종속성을 이용해 릴레이션을 연관성이 있는 속성들로만 구성되도록 분해해서, 이상 현상이 발생하지 않는 올바른 릴레이션으로 만들어가는 과정</li>
<li>관련이 없는 함수 종속성은 별개의 릴레이션으로 표현</li>
</ul>
</li>
<li>주의사항<ul>
<li>정규화를 통해 릴레이션은 무손실 분해되어야 함</li>
<li>릴레이션이 의미상 동등한 릴레이션들로 분해되어야 하고, 분해로 인한 정보 손실이 발생하지 않아야 함</li>
<li>분해된 릴레이션들을 자연 조인하면 분해 전의 릴레이션으로 복원 가능해야 함</li>
</ul>
</li>
</ol>
</li>
<li><p>정규형</p>
<ul>
<li>릴레이션이 정규화된 정도</li>
<li>각 정규형마다 제약조건이 존재</li>
<li>정규형의 차수가 높아질수록 요구되는 제약조건이 많아지고 엄격해짐</li>
<li>높은 차수의 정규형은 보다 낮은 차수의 정규형이 갖는 특성을 모두 포함</li>
<li>릴레이션의 특성을 고려해서 적합한 정규형을 선택</li>
</ul>
<ol>
<li><p>제1정규형(1NF)</p>
<ul>
<li>릴레이션의 모든 속성이 더는 분해되지 않는 원자 값만 가지면 제1정규형을 만족</li>
<li>제1정규형을 만족하지 않는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/6fdfb516-18b6-4a35-8ca3-ba1a05051314/image.jpg" alt=""></li>
<li>제1정규형을 만족하는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/07bb33c9-2db8-4f49-8c7c-266081e06b8d/image.jpg" alt=""></li>
<li>제1정규형을 만족하지만 이상 현상이 발생하는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/0bc5f160-db69-4cf1-8cfc-6afb6d58c139/image.jpg" alt=""></li>
<li>이상 현상이 발생하는 이유: 기본키인 {고객아이디, 이벤트번호}에 완전 함수 종속되지 못하고 일부분인 고객아이디에 종속되는 등급과 할인율 속성이 존재하기 때문</li>
<li>문제 해결 방법: 부분 함수 종속이 제거되도록 이벤트참여 릴레이션을 분해</li>
</ul>
</li>
<li><p>제2정규형(2NF)</p>
<ul>
<li>릴레이션이 제1정규형에 속하고, 기본 키가 아닌 모든 속성이 기본 키에 완전 함수 종속되면 제2정규형을 만족함</li>
<li>제1정규형을 만족하는 릴레이션에 대해, 부분 함수 종속을 제거하고 모든 속성이 기본 키에 완전 함수 종속되도록 분해</li>
<li>제1정규형을 만족하지만, 제2정규형을 만족하지 않는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/b3275bf7-c40a-498e-8ef6-0eca8b78fb0f/image.jpg" alt=""></li>
<li>제2정규형을 만족하도록 분해한 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/50114b63-49dd-4a6d-83c9-3fdfaf8c763c/image.jpg" alt=""></li>
<li>제2정규형을 만족하지만 이상 현상이 발생하는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/56936283-abf6-4736-9fe5-837af51967c0/image.jpg" alt=""></li>
<li>이상 현상이 발생하는 이유: 이행적 함수 종속이 존재하기 때문        </li>
<li>문제 해결 방법: 이행적 함수 종속이 제거되도록 고객 릴레이션을 분해</li>
</ul>
</li>
<li><p>제3정규형(3NF)</p>
<ul>
<li>릴레이션이 제2정규형에 속하고, 기본 키가 아닌 모든 속성이 기본 키에 이행적 함수 종속이 되지 않으면 제3정규형을 만족함</li>
<li>제2정규형을 만족하는 릴레이션에 대해, 모든 속성이 기본 키에 이행적 함수 종속이 되지 않도록 분해</li>
<li>제2정규형을 만족하지만, 제3정규형을 만족하지 않는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/414ce485-5d58-4a78-a2c0-62c38a310b9d/image.jpg" alt=""></li>
<li>제3정규형을 만족하도록 분해한 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/e121f8b9-1026-46e7-a1b6-ce5071616972/image.jpg" alt=""></li>
</ul>
</li>
<li><p>보이스-코드 정규형(BCNF)</p>
<ul>
<li><p>필요성: 하나의 릴레이션에 여러 개의 후보 키가 존재하는 경우, 제3정규형까지 모두 만족해도 이상 현상이 발생할 수 있음</p>
</li>
<li><p>의미: 강한 제3정규형</p>
<ul>
<li>후보 키를 여러 개 가지고 있는 릴레이션에 발생할 수 있는 이상 현상을 해결하기 위해 제3정규형보다 더 엄격한 제약조건을 제시</li>
<li>보이스-코드 정규형에 속하는 모든 릴레이션은 제3정규형에 속하지만, 제3정규형에 속하는 모든 릴레이션이 보이스-코드 정규형에 속하는 것은 아님</li>
</ul>
</li>
<li><p>제3정규형을 만족하지만 이상 현상이 발생하는 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/8ad60c0d-24a9-4d6f-bcff-be7122b08859/image.jpg" alt=""></p>
</li>
<li><p>이상 현상이 발생하는 이유: 담당강사번호가 후보키가 아님에도 인터넷강좌 속성을 결정하기 때문</p>
</li>
<li><p>BCNF를 만족하도록 분해한 릴레이션
<img src="https://velog.velcdn.com/images/jam2_boyak/post/f127c753-89ac-4609-8216-9ce2e2e856ee/image.jpg" alt=""></p>
</li>
</ul>
</li>
</ol>
</li>
<li><p>유의 사항</p>
<ul>
<li>정규화 차수가 높을 수록 성능이 개선되는 것은 아님</li>
<li>일반적으로 제 3 정규형이나 보이스/코드 정규형에 속하도록 릴레이션을 분해하여 데이터 중복을 줄이고 이상 현상을 해결하는 경우가 많음</li>
<li>정규화로 인한 성능 저하 시, 반정규화를 고려</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2_데이터 모델과 성능(3)]]></title>
            <link>https://velog.io/@jam2_boyak/SQLD-2%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-%EC%84%B1%EB%8A%A53</link>
            <guid>https://velog.io/@jam2_boyak/SQLD-2%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-%EC%84%B1%EB%8A%A53</guid>
            <pubDate>Sat, 02 Sep 2023 06:36:08 GMT</pubDate>
            <description><![CDATA[<h3 id="2장-데이터-모델과-성능">2장. 데이터 모델과 성능</h3>
<h4 id="5-데이터베이스-구조와-성능">5. 데이터베이스 구조와 성능</h4>
<ol>
<li><p><strong>슈퍼/서브타입 데이터 모델의 성능 고려 방법</strong></p>
<ol>
<li>모델의 개요<ol>
<li>Extended ER 모델이라고도 불림</li>
<li>데이터의 공통점과 차이점을 효과적으로 표현할 수 있기 때문에 자주 쓰임</li>
<li>공통 부분 - 슈퍼타입 모델링, 차이점 - 다른 엔티티와 차이가 있는 속성에 대해서는 별도의 서브엔티티로 구분</li>
<li>논리적인 데이터 모델이서 이용/분석 단계에서 많이 쓰이는 모델</li>
</ol>
</li>
<li>슈퍼/서브타입 데이터 모델의 변환<ol>
<li>변환 오류로 성능이 저하되는 경우<ul>
<li>트랜잭션은 항상 일괄로 처리하는데, 테이블은 개별로 유지되어 Union 연산에 의해 성능 저하 발생</li>
<li>트랜잭션은 항상 서브타입 개별로 처리하는데, 테이블한 하나로 통합되어 있어 불필요하게 많은 양의 데이터가 집약된 경우</li>
<li>트랜잭션은 항상 슈퍼+서브타입을 공통으로 처리하는데, 개별로 유지되어 있거나 하나의 테이블로 집약된 경우</li>
</ul>
</li>
<li>데이터가 소량일 경우<ul>
<li>성능에 영향을 미치지 않으므로 데이터 처리의 유연성을 고려하거나, 1:1 관계 유지</li>
<li>용량이 커지면 다음 3가지 방법 고려</li>
</ul>
</li>
</ol>
</li>
<li>슈퍼/서브타입 모델의 변환 기술<ol>
<li>개별로 발생되는 트랜잭션: 개별 테이블로 구성(1:1 관계)</li>
<li>슈퍼타입+서브타입에 대해 발생되는 트랜잭션: 슈퍼타입+서브타입 테이블로 구성(Plus Type)</li>
<li>전체를 하나로 묶어 트랜잭션이 발생할 때: 하나의 테이블로 구성(Single, All in One)</li>
</ol>
</li>
<li>슈퍼/서브타입 데이터 모델의 변환타입 비교
<img src="https://velog.velcdn.com/images/jam2_boyak/post/6f3ef593-5b89-4fd1-ba9d-2032faeac75c/image.png" alt=""></li>
</ol>
</li>
<li><p><strong>인덱스 특성을 고려한 PK/FK 데이터베이스 성능 향상</strong></p>
<ol>
<li>PK/FK 컬럼 순서와 성능 개요<ul>
<li>데이터베이스 테이블에서는 균형 잡힌 트리 구조의 B-Tree 구조를 보편적으로 사용</li>
<li>성능 저하: PK가 여러 개의 속성으로 구성된 복합 식별자일 때, PK 순서에 대해 별로 고려하지 않고 데이터 모델링을 한 경우 발생</li>
<li>PK는 해당 테이블의 데이터를 접근할 때 가장 빈번하게 사용되는 유일한 인덱스를 모두 자동 생성</li>
<li>여러 개의 속성이 하나의 인덱스로 구성되어 있을 때, 앞쪽에 위치한 속성값이 비교자로 있어야 인덱스가 좋은 효율을 보임<ul>
<li>앞 쪽에 있는 속성 값이 가급적 &#39;=&#39; 혹은 범위 &#39;BETWEEN&#39;, &#39;&lt;&#39;, &#39;&gt;&#39;가 들어와야 인덱스를 이용할 수 있음</li>
</ul>
</li>
</ul>
</li>
<li>PK 컬럼의 순서 미조정에 따른 성능 저하<ul>
<li>인덱스 특징에 맞게 고려하지 않고 PK 컬럼 생성 시, 테이블에 접근하는 트랜잭션의 특징에 효율적이지 않은 인덱스가 생성됨</li>
<li>이로 인해, 인덱스의 범위를 넓게 이용하거나, 테이블 Full Scan을 유발하여 성능 저하 발생</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>물리적인 테이블에 FK 제약이 걸려있지 않을 시, 인덱스 미생성으로 성능 저하</strong></p>
<ol>
<li>물리적인 테이블에 FK를 사용하지 않아도, 데이터 모델 관계에 따라 상속받은 FK 속성들은 SQL WHERE 절에서 JOIN으로 이용되는 경우가 많음<ul>
<li>따라서, FK 인덱스를 생성해야 성능이 좋은 경우가 많음</li>
</ul>
</li>
<li>FK 인덱스를 적절하게 설계하여 구축하지 않았을 경우<ul>
<li>개발 초기에는 데이터 양이 적기 때문에 성능 저하가 발생하지 않음</li>
<li>하지만, 시스템을 오픈하고 데이터가 누적될수록 SQL 성능이 나빠져 데이터베이스 서버에 심각한 장애 현상을 초래하게 됨</li>
</ul>
</li>
</ol>
</li>
</ol>
<h4 id="6-분산-데이터베이스와-성능">6. 분산 데이터베이스와 성능</h4>
<ol>
<li>분산 데이터베이스의 개요<ol>
<li>분산 데이터베이스 정의<ul>
<li>분산된 데이터베이스를 하나의 가상 시스템으로 사용할 수 있도록 한 데이터베이스</li>
<li>논리적으로 동일한 시스템에 속하나, 컴퓨터 네트워크를 통해 물리적으로 분산되어 있는 데이터들의 모임. 물리적 Site 분산, 논리적으로 사용자 통합, 공유</li>
<li>데이터베이스를 연결하는 빠른 네트워크 환경을 이용하여 데이터베이스를 여러 지역 여러 노드로 위치시켜 사용성/성능을 극대화시킨 데이터베이스</li>
</ul>
</li>
<li>분산 데이터베이스의 투명성<ul>
<li>분할 투명성(단편화): 하나의 논리적 Relation이 여러 단편으로 분할되어 각 단편의 사본이 여러 Site에 저장</li>
<li>위치 투명성: 사용하려는 데이터의 저장 장소 명시 불필요. 위치 정보가 System Catalog에 유지되어야 함</li>
<li>지역 사상 투명성: 지역DBMS와 물리적 DB 사이의 Mapping 보장. 각 지역 시스템 이름과 무관한 이름 사용 가능</li>
<li>중복 투명성: DB 객체가 여러 Site에 중복되어 있는지 알 필요가 없는 특성</li>
<li>장애 투명성: 구성요소(DBMS, 컴퓨터)의 장애에 무관한 트랜잭션의 원자성 유지</li>
<li>병행 투명성: 다수 트랜잭션 동시 수행 시, 결과의 일관성 유지, Time Stamp, 분산 2단계 Locking을 이용 구현</li>
</ul>
</li>
<li>분산 데이터베이스의 적용 방법 및 장단점<ul>
<li>분산 데이터베이스 적용 방법: 업무의 흐름에 따라 업무 구성별 아키텍쳐 특징에 기반하여 데이터베이스를 구성</li>
<li>분산 데이터베이스의 장단점</li>
</ul>
</li>
<li>데이터베이스 분산 구성의 가치<ul>
<li>가장 핵심적인 가치는 통합된 데이터베이스에서 제공할 수 없는 빠른 성능을 제공한다는 것</li>
</ul>
</li>
<li>분산 데이터베이스의 적용 기법<ol>
<li>테이블 위치 분산<ul>
<li>설계된 테이블의 위치를 각각 다르게 하는 것. 도식화된 위치별 데이터베이스 문서가 요구됨</li>
</ul>
</li>
<li>테이블 분할 분산(Fragmentation)<ul>
<li>위치만 다른 곳에 두는 것이 아니라, 각각의 테이블을 쪼개어 분산</li>
<li>수평 분할: 노드(Node)에 따라 테이블을 특정 컬럼의 값을 기준으로 로우(Row)를 분리</li>
<li>수직 분할: 노드(Node)에 따라 테이블 컬럼을 기준으로 컬럼을 분리</li>
</ul>
</li>
<li>테이블 복제 분산(Replication)<ul>
<li>동일한 테이블을 다른 지역이나 서버에서 동시에 생성하여 관리하는 유형</li>
<li>부분 복제(Segment Replication): 통합된 테이블을 한 군데(본사)에 가지고 있으면서, 각 지사별로는 지사에 해당된 로우를 가지고 있는 형태. 여러 테이블에 조인이 발생하지 않는 빠른 작업 수행이 가능</li>
<li>광역 복제(Broadcast Replication): 통합된 테이블을 한 군데(본사)에 가지고 있으면서, 각 지사에도 본사와 동일한 데이터를 모두 가지고 있는 형태</li>
</ul>
</li>
<li>테이블 요약 분산(Summarization)<ul>
<li>지역 간, 서버 간에 데이터가 비슷하지만 서로 다른 유형으로 존재하는 경우</li>
<li>분석 요약(Rollup Replication): 각 지사별로 존재하는 동일 정보를 본사에서 통합하여, 다시 전체에 대해서 요약 정보를 산출하는 분산 방법</li>
<li>통합 요약(Consolidation Replication): 각 지사별로 존재하는 다른 내용의 정보를 본사에 통합하여, 다시 전체에 대해서 요약 정보를 산출하는 분산 방법</li>
<li>분석 요약은 지사에 있는 데이터를 이용하여 본사에서 통합하여 요약 데이터를 산정 vs 통합 요약은 지사에서 요약한 정보를 본사에서 취합하여 각 지사별로 데이터를 비교하기 위해 이용</li>
</ul>
</li>
</ol>
</li>
<li>분산 데이터베이스 적용<ol>
<li>성능이 중요한 사이트에 적용</li>
<li>공통 코드, 기준 정보, 마스터 데이터 등에 대해 분산 환경을 구성하면 성능이 좋아짐</li>
<li>실시간 동기화가 요구되지 않을 경우, 거의 실시간(Near Real Time)의 업무적인 특징을 가지고 있을 때도 분산 환경을 구성 가능</li>
<li>특정 서버에 부하가 집중이 될 때, 부하를 분산할 경우</li>
<li>백업 사이트(Disaster Recovery Site)를 구성할 때, 간단하게 분산 기능을 적용 가능</li>
</ol>
</li>
</ol>
</li>
</ol>
<p>참고:
<a href="https://fromitot.tistory.com/86">https://fromitot.tistory.com/86</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2_데이터 모델과 성능(2)]]></title>
            <link>https://velog.io/@jam2_boyak/SQLD-2%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-%EC%84%B1%EB%8A%A52-45l6ewy5</link>
            <guid>https://velog.io/@jam2_boyak/SQLD-2%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-%EC%84%B1%EB%8A%A52-45l6ewy5</guid>
            <pubDate>Sat, 02 Sep 2023 06:36:01 GMT</pubDate>
            <description><![CDATA[<h3 id="2장-데이터-모델과-성능">2장. 데이터 모델과 성능</h3>
<h4 id="3-반정규화와-성능">3. 반정규화와 성능</h4>
<ol>
<li>반정규화<ul>
<li>정의: 정규화된 엔티티, 속성, 관계에 대해 시스템의 성능 향상과 개발, 운영의 단순화를 위해 중복, 통합, 분리 등을 수행하는 데이터 모델링 기법</li>
<li>수행 예시:<ol>
<li>데이터를 조회할 때 디스크 I/O양이 많아서 성능이 저하될 때</li>
<li>경로가 너무 멀어 조인으로 인한 성능 저하가 예상될 때</li>
<li>컬럼을 계산하여 읽을 때 성능이 저하될 것이 예상될 때</li>
</ol>
</li>
<li>데이터 무결성이 침해될 가능성이 높음 -&gt; 성능상의 이점을 위해 포기</li>
</ul>
</li>
<li>적용 방법<ul>
<li>반정규화 적용 절차<ol>
<li>반정규화 대상 조사</li>
<li>다른 방법유도 검토</li>
<li>반정규화 적용</li>
</ol>
</li>
<li>반정규화 대상 조사<ol>
<li>자주 사용되는 테이블에 접근하는 프로세스의 수가 많고 항상 일정한 범위만을 조회하는 경우</li>
<li>테이블에 대량의 데이터가 있고, 대량의 데이터 범위를 자주 처리하는데 처리 범위를 일정하게 줄이지 않으면 성능을 보장할 수 없을 경우</li>
<li>통계성 프로세스에 의해 통계 정보를 필요로 할 때, 별도의 통계테이블(반정규화 테이블)을 생성</li>
<li>테이블에 지나치게 많은 조인이 걸려 데이터를 조회하는 작업이 기술적으로 어려울 경우</li>
</ol>
</li>
<li>다른 방법 검토<ol>
<li>지나치게 많은 조인이 걸려 데이터를 조회하는 작업이 기술적으로 어려울 경우: 뷰(View)를 사용</li>
<li>대량의 데이터처리나 부분처리에 의해 성능이 저하되는 경우: 클러스터링을 적용 or 인덱스를 조정</li>
<li>대량의 데이터는 PK성격에 따라 부분적인 테이블로 분리 가능: 파티셔닝 기법 적용</li>
<li>응용 애플리케이션에서 로직을 구사하는 방법을 변경함으로써 성능 향상 가능: 응용 메모리 영역에 데이터 처리를 위한 값을 캐쉬하거나, 중간 클래스 영역에 데이터를 캐쉬하여 공유</li>
</ol>
</li>
<li>반정규화 적용<ol>
<li>테이블 반정규화, 속성의 반정규화, 관계의 반정규화 수행</li>
</ol>
</li>
</ul>
</li>
<li>반정규화 기법<ul>
<li>테이블 반정규화</li>
<li>칼럼 반정규화</li>
<li>관계 반정규화</li>
</ul>
</li>
</ol>
<h4 id="4-대량-데이터에-따른-성능">4. 대량 데이터에 따른 성능</h4>
<ol>
<li>대량 데이터 발생에 따른 테이블 분할<ul>
<li>데이터가 특정 테이블에 몰리지 않도록 테이블 단위의 분할 시도</li>
<li>로우 체이닝(Row Chaining): 로우 길이가 너무 길어서 데이터 블록 하나에 데이터가 모두 저장되지 않고, 두 개 이상의 블록에 걸쳐 하나의 로우가 저장되어 있는 형태</li>
<li>로우 마이그레이션(Row Migration): 데이터 블록에서 수정이 발생하면 수정된 데이터를 해당 데이터 블록에서 저장하지 못하고 다른 블록의 빈 공간을 찾아 저장하는 방식</li>
<li>트랜잭션을 분석하여 적절하게 1:1 관계로 분리하여 성능 향상이 가능하도록 해야 함</li>
</ul>
</li>
<li>대량 데이터 저장 및 처리<ul>
<li>논리적으로는 하나의 테이블로 보이지만, 물리적으로 여러 개의 테이블스페이스에 쪼개어 저장될 수 있는 구조의 파티셔닝을 적용하거나, PK로 테이블을 분할하는 방법을 적용</li>
<li>Range Partition<ol>
<li>대상 테이블이 날짜 또는 숫자값으로 분리가 가능하고, 각 영역별로 트래잭션이 분리되어 있는 경우</li>
<li>예: 요금 테이블 -&gt; 요금_0901, 요금_0902 </li>
</ol>
</li>
<li>List Partition<ol>
<li>지점, 사업소, 사업장, 코드값 등으로 PK가 구성되어 있는 경우, 값 각각에 의해 파티셔닝</li>
<li>예: 회원 테이블 -&gt; 회원_서울, 회원_제주</li>
</ol>
</li>
<li>Hash Partition<ol>
<li>지정된 Hash 조건에 따라 hash 알고리즘이 적용되어 테이블 분리</li>
</ol>
</li>
</ul>
</li>
<li>테이블 수평/수직 분할 절차<ul>
<li>데이터 모델링 완성</li>
<li>데이터베이스 용량 산정</li>
<li>대량 데이터가 처리되는 테이블에 대해서 트랜잭션 처리 패턴을 분석</li>
<li>칼럼/로우 단위로 집중화된 처리가 발생하는지 분석하여 집중화된 단위로 테이블을 분리하는 것을 검토</li>
</ul>
</li>
</ol>
<p>참고:
<a href="https://yganalyst.github.io/sql/SQL_5/#google_vignette">https://yganalyst.github.io/sql/SQL_5/#google_vignette</a>
<a href="https://fromitot.tistory.com/86">https://fromitot.tistory.com/86</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 2_데이터 모델과 성능(1)]]></title>
            <link>https://velog.io/@jam2_boyak/SQLD-2%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-%EC%84%B1%EB%8A%A51</link>
            <guid>https://velog.io/@jam2_boyak/SQLD-2%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-%EC%84%B1%EB%8A%A51</guid>
            <pubDate>Sat, 02 Sep 2023 06:35:52 GMT</pubDate>
            <description><![CDATA[<h3 id="2장-데이터-모델과-성능">2장. 데이터 모델과 성능</h3>
<h4 id="1-성능-데이터-모델링의-개요">1. 성능 데이터 모델링의 개요</h4>
<ol>
<li>성능 데이터 모델의 정의<ul>
<li>정의<ol>
<li>데이터베이스 성능 향상을 목적으로 설계 단계의 데이터 모델링 때부터 성능 관련 사항이 데이터 모델링에 반영될 수 있도록 하는 것</li>
<li>성능 관련 사항: 정규화, 반정규화, 테이블 통합/분할, 조인 구조, PK, FK 등</li>
</ol>
</li>
<li>데이터 모델의 성능 저하 원인<ol>
<li>데이터 모델 구조</li>
<li>대용량 데이터</li>
<li>특성을 고려하지 않고 인덱스 생성</li>
</ol>
</li>
</ul>
</li>
<li>수행 시점<ul>
<li>일찍 수행할수록 비용이 저렴하고, 늦게 수행할수록 비용이 비싸진다.</li>
<li>분석/설계 단계에서 성능을 고려한 데이터 모델링을 수행할 경우, 성능 저하에 따른 재업무 비용을 최소화할 수 있다.</li>
</ul>
</li>
<li>고려 사항<ol>
<li>데이터 모델링 시, 정확한 정규화 수행.</li>
<li>데이터베이스 용량산정 실시</li>
<li>데이터베이스에 발생되는 트랜잭션의 유형 파악</li>
<li>용량과 트랜잭션 유형에 따른 반정규화 수행</li>
<li>이력모델의 조정, PK/FK조정, 슈퍼타입/서브타입 조정 등 수행</li>
<li>성능 관점에서 데이터 모델 검증</li>
</ol>
</li>
</ol>
<h4 id="2-정규화와-성능">2. 정규화와 성능</h4>
<ol>
<li>정규화<ul>
<li>정의<ol>
<li>데이터를 결정하는 결정자에 의해 함수적 종속을 가지고 있는 일반 속성을 의존자로 하여, 입력/수정/삭제 이상을 제거하는 것</li>
<li>데이터의 일관성, 최소한의 데이터 중복 및 데이터 유연성을 위한 방법이며, 데이터를 분해하는 과정</li>
<li>정규화된 모델은 테이블이 분해됨.</li>
<li>불필요한 데이터를 입력하지 않아도 되므로 중복 데이터가 제거됨</li>
</ol>
</li>
<li>절차<ol>
<li>제1정규화: 속성의 원자성 확보, 속성의 중복값 제거, 기본 키 설정</li>
<li>제2정규화: 기본 키가 복수인 속성에 대해 부분 함수 종속성 제거, 복합 인스턴스의 종속적 중복 제거</li>
<li>제3정규화: 기본 키 이외의 컬럼 간 종속성 제거, 이행 함수 종속성 제거, 일반속성 종속성 제거</li>
<li>BCNF: 후보 키가 기본 키를 종속시킬 경우 제거, 복수의 후보 키가 복합 속성이고 중첨되는 경우에만 해당</li>
<li>4정규화, 5정규화 등이 있지만, 실무에서는 보통 제3정규화 수준으로 수행 </li>
</ol>
</li>
<li>정규화를 통한 성능 향상 전략<ol>
<li>데이터에 대한 중복성을 제거하여 데이터가 관심사별로 처리되는 경우가 많아지므로, 성능이 향상되는 특징</li>
<li>데이터 처리 성능: 조회 vs 입력/수정/삭제 &gt; 한 파트의 성능 향상은 다른 파트의 성능 저하를 가져올 수 있다<ul>
<li>함수적 종속성에 근거한 데이터 정규화 수행 필요</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
</ol>
<p>참고:
<a href="https://yganalyst.github.io/sql/SQL_5/#google_vignette">https://yganalyst.github.io/sql/SQL_5/#google_vignette</a>
<a href="https://fromitot.tistory.com/86">https://fromitot.tistory.com/86</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[sourcetree를 이용해 소스코드 github에 백업하기 (2)]]></title>
            <link>https://velog.io/@jam2_boyak/sourcetree%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-github%EC%97%90-%EB%B0%B1%EC%97%85%ED%95%98%EA%B8%B0-2</link>
            <guid>https://velog.io/@jam2_boyak/sourcetree%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-github%EC%97%90-%EB%B0%B1%EC%97%85%ED%95%98%EA%B8%B0-2</guid>
            <pubDate>Sat, 02 Sep 2023 04:25:10 GMT</pubDate>
            <description><![CDATA[<h4 id="변경-내역을-저장소에-push하기">변경 내역을 저장소에 PUSH하기</h4>
<p>로컬 저장소에 변경 사항이 생긴다면, sourcetree에서 이를 확인할 수 있습니다.
F5(새로고침)을 통해 변경 사항을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/c5fef02f-5f9a-474a-9306-b33c7e5b9a53/image.JPG" alt=""></p>
<ol>
<li>변경사항이 생기면 &quot;커밋하지 않은 변경사항&quot; 및 &quot;스테이지에 올라가지 않은 파일&quot;을 확인할 수 있습니다. 왼쪽 상단에 &quot;커밋&quot; 아이콘을 눌러 파일을 저장소에 올리기 위한 준비를 합니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/a3a67ed8-6df3-4c50-bd83-f2b2398be716/image.JPG" alt=""></p>
<ol start="2">
<li>&quot;커밋&quot; 아이콘을 누른 후의 모습입니다. 스테이지에 올라가지 않은 파일을 &quot;모두 스테이지에 올리기&quot; 버튼을 눌러 백업할 파일을 모두 지정해줍니다. 파일명 우측의 &quot;+&quot; 혹은 &quot;-&quot; 아이콘을 눌러 개별적으로 파일을 업로드 할 수 있습니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/624437e4-0b66-45f7-a98a-fdc2176efbd1/image.JPG" alt=""></p>
<ol start="3">
<li>스테이지에 파일을 모두 올렸다면, 하단의 커밋 메시지를 작성합니다. 커밋 메시지는 수정 사항에 대한 주요 정보를 담아 작성하면 됩니다. 완료되었다면 우측 하단의 커밋 버튼을 누릅니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/f9c057d2-cb93-4025-848c-213c65c0e8ac/image.JPG" alt=""></p>
<ol start="4">
<li>커밋을 완료한 모습입니다. 메인에 커밋 메시지와 함께 변경 사항을 확인할 수 있습니다. 문제가 없다면 좌측 상단에 Push를 누릅니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/05ffa4f6-8e1e-4254-b7bd-e8c149129a91/image.JPG" alt=""></p>
<ol start="5">
<li>Push 전 최종 확인을 진행합니다. 문제가 없으면 Push합니다. 이후 git repository에서 업로드 된 파일들을 확인할 수 있습니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[sourcetree를 이용해 소스코드 github에 백업하기 (1)]]></title>
            <link>https://velog.io/@jam2_boyak/sourcetree%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-github%EC%97%90-%EB%B0%B1%EC%97%85%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jam2_boyak/sourcetree%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-github%EC%97%90-%EB%B0%B1%EC%97%85%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 29 Aug 2023 08:18:20 GMT</pubDate>
            <description><![CDATA[<p>매번 작업한 내용을 압축하고, 메일로 보내는 작업을 한번에 단축할 수 있도록,
sourcetree를 이용해서 로컬 저장소를 github에 백업하는 방법입니다.</p>
<ol>
<li>sourcetree 설치
sourcetree.com에서 운영체제에 맞는 설치 파일을 다운로드하고, 설치를 진행합니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/79ee933d-dfd7-482b-acba-08a997b4c9dd/image.JPG" alt=""></p>
<ol start="2">
<li>로컬 저장소 지정
백업하고자 하는 저장소를 생성하고, 폴더 경로를 복사합니다.
깃헙에 새로운 저장소를 만들기 위해서는 빈 폴더를 지정해야 합니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/e87f8a8b-8203-4257-b10a-1fd8b337206d/image.JPG" alt=""></p>
<ol start="3">
<li>깃헙 저장소 생성하기
복사한 폴더 경로를 목적지 경로에 입력합니다.
이름은 잘 지어주시면 됩니다.
계정에 저장소 생성하기 체크합니다.
계정은 github 계정을 선택하시면 됩니다.
소유자는 자동으로 설정됩니다.
저장소에 대한 적절한 설명을 달아주시면 됩니다.
만약, 저장소 비공개 설정을 원한다면, is Private을 체크해주시면 됩니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jam2_boyak/post/5048a5ca-cc5c-46dd-9cf1-d19f315f423a/image.JPG" alt=""></p>
<p>생성 버튼을 누르셨다면, github에 저장소가 생긴 것을 확인하실 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 1_데이터 모델링의 이해(3)]]></title>
            <link>https://velog.io/@jam2_boyak/SQLD-1%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B43</link>
            <guid>https://velog.io/@jam2_boyak/SQLD-1%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B43</guid>
            <pubDate>Sun, 27 Aug 2023 15:19:02 GMT</pubDate>
            <description><![CDATA[<h3 id="4-관계">4. 관계</h3>
<ol>
<li>정의: 엔티티 간의 논리적 관련성</li>
<li>유의점<ol>
<li>두 개의 엔티티 사이에 연관 규칙이 존재하는가?</li>
<li>업무기술서, 장표에 관계 연결을 가능하게 하는 동사가 있는가?</li>
<li>업무기술서, 장표에 관계 연결 규칙이 서술되어 있는가?</li>
<li>두 개의 엔티티 사이에서 정보의 조합이 발생하는가?</li>
</ol>
</li>
<li>분류<ol>
<li>존재에 의한 관계: 두 개의 엔티티가 존재 여부에 대한 관계가 이루어진 상태 (ex. 부서와 사원은 소속이라는 존재 관계를 이룸)</li>
<li>행위에 의한 관계: 두 개의 엔티티가 어떤 행위의 관련성에 대해 관계가 이루어진 상태 (ex. 회원과 도서는 대출을 통해 행위 관계를 이룸)</li>
</ol>
</li>
<li>표기법<ol>
<li>1대 1 관계: 하나의 A 엔티티와 다른 하나의 B 엔티티는 서로가 속성 하나씩만을 가지는 관계 (ex. 한 명의 회원은 하나의 회원 번호를 가짐. 하나의 회원 번호 또한 한 명의 회원만을 가짐)</li>
<li>1대 N 관계: 하나의 A 엔티티는 다른 하나의 B 엔티티의 여러 속성을 가질 수 있고, 하나의 B 엔티티는 A 엔티티의 속성을 오직 하나만 가질 수 있는 관계 (ex. 한 명의 회원은 여러 대출 기록을 가짐. 하나의 대출 기록은 한 명의 회원만을 가짐)</li>
<li>N대 N 관계: A 엔티티는 B 엔티티의 여러 속성을 가질 수 있으며, B 엔티티 또한 A 엔티티의 여러 속성을 가질 수 있는 관계 (ex. 한 명의 회원은 여러 권의 책을 대출할 수 있고, 하나의 책은 여러 회원에게 대출될 수 있음)</li>
</ol>
</li>
</ol>
<h3 id="5-식별자">5. 식별자</h3>
<ol>
<li>정의: 하나의 엔티티에 구성되어 있는 여러 속성 중, 엔티티를 대표할 수 있는 속성<ol>
<li>하나의 엔티티는 반드시 하나의 유일한 식별자가 존재해야 함</li>
<li>업무적으로 구분이 되는 정보이며, 논리 데이터 모델링 단계에서 사용됨</li>
</ol>
</li>
<li>특징<ol>
<li>유일성: 식별자에 의해 엔티티 내에 모든 인스턴스들은 유일하게 구분되어야 함</li>
<li>최소성: 식별자를 구성하는 속성의 수는 유일성을 만족하는 최소의 수가 되어야 함</li>
<li>불변성: 식별자가 한 번 지정되면 그 식별자의 값은 변하지 않아야 함</li>
<li>존재성: 식별자가 지정되면 반드시 식별자의 값이 존재해야 함</li>
</ol>
</li>
<li>분류<ol>
<li>대표성 여부에 따른 분류<ul>
<li>주 식별자: 유일성과 최소성을 만족하면서 엔티티를 대표하는 식별자이며, 타 엔티티와 참조관계 연결 가능</li>
<li>보조 식별자: 유일성과 최소성을 만족하지만, 엔티티를 대표하지 못해 타 엔티티와 참조관계 연결 불가능</li>
</ul>
</li>
<li>스스로 생성 여부에 따른 분류<ul>
<li>내부 식별자: 엔티티 내부에서 스스로 만들어지는 식별자</li>
<li>외부 식별자: 타 엔티티와의 관계를 통해 타 엔티티로부터 받아오는 식별자</li>
</ul>
</li>
<li>속성의 수에 따른 분류<ul>
<li>단일 식별자: 하나의 속성으로 구성된 식별자</li>
<li>복합 식별자: 둘 이상의 속성으로 구성된 식별자</li>
</ul>
</li>
<li>대체 여부에 따른 분류<ul>
<li>본질 식별자: 업무에 의해 자연스레 만들어지는 식별자</li>
<li>인조 식별자: 업무에 의해 자연스레 만들어지지는 않지만, 원조 식별자가 복잡한 구성을 가지고 있어 인위적으로 만든 식별자</li>
</ul>
</li>
</ol>
</li>
<li>키<ol>
<li>정의: DB 테이블에 접근을 위한 매개체로, 물리 데이터 모델링 단계에서 사용</li>
<li>종류<ul>
<li>후보키: 유일성과 최소성을 만족하는 키</li>
<li>슈퍼키: 유일성은 만족하지만, 최소성을 만족하지 못하는 키</li>
<li>대체키: 후보키 중 기본키를 제외하고 남은 나머지 키</li>
<li>외래키: 다른 테이블의 기본 키 필드를 가리키며, 참조 무결성이 특징인 키</li>
</ul>
</li>
</ol>
</li>
</ol>
<p>참고: <a href="https://mjn5027.tistory.com/100">https://mjn5027.tistory.com/100</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JDBC] 과제_0825 (5)]]></title>
            <link>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-5</link>
            <guid>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-5</guid>
            <pubDate>Sun, 27 Aug 2023 07:38:04 GMT</pubDate>
            <description><![CDATA[<p>abstract에서 override한 DELETE, INSERT, UPDATE를 수행하는 메서드를 구현한다.</p>
<pre><code class="language-java">    @Override
    public int deleteOneMemberByMemberId (String memberId) {

        Connection conn = cafeConnect.makeConnection();

        //쿼리 생성
        StringBuffer query = new StringBuffer();
        query.append(&quot; DELETE  &quot;);
        query.append(&quot;   FROM MEMBERS &quot;);
        query.append(&quot;  WHERE MEMBER_ID = ? &quot;);

        //쿼리 실행 준비
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(query.toString());
        } catch (SQLException e) {
            System.out.println(&quot;쿼리에 문제가 있습니다.&quot;);
            System.out.println(e.getMessage());
            cafeConnect.closeConnection(conn);
            return 0;
        }

        //바인딩
        try {
            pstmt.setString(1, memberId);
        } catch (SQLException e) {
            System.out.println(&quot;파라미터 바인딩 과정에서 예외가 발생했습니다.&quot;);
            System.out.println(&quot;사유: &quot; + e.getMessage());
            cafeConnect.closePreparedStatement(pstmt);
            cafeConnect.closeConnection(conn);
            return 0;
        }

        int deleteCount = 0;
        try {
            deleteCount = pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            return 0;
        } finally {
            cafeConnect.closePreparedStatement(pstmt);
            cafeConnect.closeConnection(conn);
        }

        return deleteCount;
    }

    @Override
    public int insertNewMember (MembersVO memberVO) {

        Connection conn = cafeConnect.makeConnection();

        //쿼리 생성
        StringBuffer query = new StringBuffer();
        query.append(&quot; INSERT INTO MEMBERS &quot;);
        query.append(&quot;       (MEMBER_ID &quot;);
        query.append(&quot;      , MEMBER_NAME &quot;);
        query.append(&quot;      , MEMBER_GRADE &quot;);
        query.append(&quot;      , PROFILE_IMG) &quot;);
        query.append(&quot; VALUES &quot;);
        query.append(&quot;       (SEQ_MEMBERS_PK &quot;);
        query.append(&quot;      , ? &quot;);
        query.append(&quot;      , ? &quot;);
        query.append(&quot;      , ?) &quot;);

        //쿼리 실행 준비
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(query.toString());
        } catch (SQLException e) {
            System.out.println(&quot;쿼리에 문제가 있습니다.&quot;);
            System.out.println(e.getMessage());
            cafeConnect.closeConnection(conn);
            return 0;
        }

        //바인딩
        try {
            pstmt.setString(1, memberVO.getMemberId());
            pstmt.setString(2, memberVO.getMemberName());
            pstmt.setString(3, memberVO.getMemberGrade());
            pstmt.setString(4, memberVO.getProfileImg());
        } catch (SQLException e) {
            System.out.println(&quot;파라미터 바인딩 과정에서 예외가 발생했습니다.&quot;);
            System.out.println(&quot;사유: &quot; + e.getMessage());
            cafeConnect.closePreparedStatement(pstmt);
            cafeConnect.closeConnection(conn);
            return 0;
        }

        int insertCount = 0;
        try {
            insertCount = pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            return 0;
        } finally {
            cafeConnect.closePreparedStatement(pstmt);
            cafeConnect.closeConnection(conn);
        }

        return insertCount;
    }

    @Override
    public int updateMemberGradeByMemberId(String newGrade, String memberId) {

        Connection conn = cafeConnect.makeConnection();

        //쿼리 생성
        StringBuffer query = new StringBuffer();
        query.append(&quot; UPDATE MEMBERS  &quot;);
        query.append(&quot;    SET MEMBER_GRADE = ? &quot;);
        query.append(&quot;  WHERE MEMBER_ID = ? &quot;);

        //쿼리 실행 준비
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(query.toString());
        } catch (SQLException e) {
            System.out.println(&quot;쿼리에 문제가 있습니다.&quot;);
            System.out.println(e.getMessage());
            cafeConnect.closeConnection(conn);
            return 0;
        }

        //바인딩
        try {
            pstmt.setString(1, newGrade);
            pstmt.setString(2, memberId);
        } catch (SQLException e) {
            System.out.println(&quot;파라미터 바인딩 과정에서 예외가 발생했습니다.&quot;);
            System.out.println(&quot;사유: &quot; + e.getMessage());
            cafeConnect.closePreparedStatement(pstmt);
            cafeConnect.closeConnection(conn);
            return 0;
        }

        int updateCount = 0;
        try {
            updateCount = pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            return 0;
        } finally {
            cafeConnect.closePreparedStatement(pstmt);
            cafeConnect.closeConnection(conn);
        }

        return updateCount;

    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JDBC] 과제_0825 (4)]]></title>
            <link>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-4</link>
            <guid>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-4</guid>
            <pubDate>Sun, 27 Aug 2023 07:37:52 GMT</pubDate>
            <description><![CDATA[<p>앞선 내용을 바탕으로 전체 조회 및 단건 조회, 조인 조회 메소드를 생성한다.</p>
<pre><code class="language-java">    public List&lt;MembersVO&gt; selectAllMembers (){

        Connection conn = makeConnection();

        //쿼리 생성
        StringBuffer query = new StringBuffer();
        query.append(&quot; SELECT MEMBER_ID &quot;);
        query.append(&quot;      , MEMBER_NAME &quot;);
        query.append(&quot;      , MEMBER_GRADE &quot;);
        query.append(&quot;      , PROFILE_IMG &quot;);
        query.append(&quot;   FROM MEMBERS &quot;);

        //쿼리 실행 준비
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(query.toString());
        } catch (SQLException e) {
            System.out.println(&quot;쿼리에 문제가 있습니다.&quot;);
            System.out.println(e.getMessage());
            closeConnection(conn);
            return null;
        }

        //쿼리 실행 결과 받아오기
        ResultSet rs = null;
        try {
            rs = pstmt.executeQuery();
        } catch (SQLException e) {
            System.out.println(&quot;쿼리 실행 결과를 받아오는 중에 문제가 생겼습니다.&quot;); 
            System.out.println(&quot;사유: &quot; + e.getMessage());
            closePreparedStatement(pstmt);
            closeConnection(conn);
            return null;
        }

        List&lt;MembersVO&gt; members = new ArrayList&lt;&gt;();
        MembersVO memberVO = null;

        try {
            while (rs.next()) {
                memberVO = new MembersVO();
                memberVO.setMemberId( rs.getString(&quot;MEMBER_ID&quot;) );
                memberVO.setMemberName( rs.getString(&quot;MEMBER_NAME&quot;) );
                memberVO.setMemberGrade( rs.getString(&quot;MEMBER_GRADE&quot;) );
                memberVO.setProfileImg( rs.getString(&quot;PROFILE_IMG&quot;) );

                members.add(memberVO);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        } finally {
            closeResultSet(rs);
            closePreparedStatement(pstmt);
            closeConnection(conn);
        }

        return members;
    }

    public MembersVO selectOneMemberByMemberId (String memberId) {

        Connection conn = makeConnection();

        //쿼리 생성
        StringBuffer query = new StringBuffer();
        query.append(&quot; SELECT MEMBER_ID &quot;);
        query.append(&quot;      , MEMBER_NAME &quot;);
        query.append(&quot;      , MEMBER_GRADE &quot;);
        query.append(&quot;      , PROFILE_IMG &quot;);
        query.append(&quot;   FROM MEMBERS &quot;);
        query.append(&quot;  WHERE MEMBER_ID = ? &quot;);

        //쿼리 실행 준비
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(query.toString());
        } catch (SQLException e) {
            System.out.println(&quot;쿼리에 문제가 있습니다.&quot;);
            System.out.println(e.getMessage());
            closeConnection(conn);
            return null;
        }

        //바인딩
        try {
            pstmt.setString(1, memberId);
        } catch (SQLException e) {
            System.out.println(&quot;파라미터 바인딩 과정에서 예외가 발생했습니다.&quot;);
            System.out.println(&quot;사유: &quot; + e.getMessage());
            closePreparedStatement(pstmt);
            closeConnection(conn);
            return null;
        }

        //쿼리 실행 결과 받아오기
        ResultSet rs = null;
        try {
            rs = pstmt.executeQuery();
        } catch (SQLException e) {
            System.out.println(&quot;쿼리 실행 결과를 받아오는 중에 문제가 생겼습니다.&quot;); 
            System.out.println(&quot;사유: &quot; + e.getMessage());
            closePreparedStatement(pstmt);
            closeConnection(conn);
            return null;
        }

        MembersVO memberVO = null;

        try {
            if (rs.next()) {
                memberVO = new MembersVO();
                memberVO.setMemberId( rs.getString(&quot;MEMBER_ID&quot;) );
                memberVO.setMemberName( rs.getString(&quot;MEMBER_NAME&quot;) );
                memberVO.setMemberGrade( rs.getString(&quot;MEMBER_GRADE&quot;) );
                memberVO.setProfileImg( rs.getString(&quot;PROFILE_IMG&quot;) );
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        } finally {
            closeResultSet(rs);
            closePreparedStatement(pstmt);
            closeConnection(conn);
        }

        return memberVO;
    }

    public MembersVO selectOneMemberAndArticleByMemberId (String memberId) {

        Connection conn = makeConnection();

        //쿼리 생성
        StringBuffer query = new StringBuffer();
        query.append(&quot; SELECT M.MEMBER_ID &quot;);
        query.append(&quot;      , M.MEMBER_NAME &quot;);
        query.append(&quot;      , M.MEMBER_GRADE &quot;);
        query.append(&quot;      , M.PROFILE_IMG &quot;);
        query.append(&quot;      , A.ARTICLE_ID &quot;);
        query.append(&quot;      , A.BOARD_ID &quot;);
        query.append(&quot;      , A.ARTICLE_TITLE &quot;);
        query.append(&quot;      , TO_CHAR(A.UPLOAD_DATE, &#39;YYYY-MM-DD&#39;) UPLOAD_DATE &quot;);
        query.append(&quot;      , A.ARTICLE_MAIN &quot;);
        query.append(&quot;      , A.LIKE_COUNT &quot;);
        query.append(&quot;      , A.VIEW_COUNT &quot;);
        query.append(&quot;   FROM MEMBERS M &quot;);
        query.append(&quot;   JOIN ARTICLES A &quot;);
        query.append(&quot;     ON M.MEMBER_ID = A.MEMBER_ID &quot;);
        query.append(&quot;  WHERE M.MEMBER_ID = ? &quot;);

        //쿼리 실행 준비
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(query.toString());
        } catch (SQLException e) {
            System.out.println(&quot;쿼리에 문제가 있습니다.&quot;);
            System.out.println(e.getMessage());
            closeConnection(conn);
            return null;
        }

        //바인딩
        try {
            pstmt.setString(1, memberId);
        } catch (SQLException e) {
            System.out.println(&quot;파라미터 바인딩 과정에서 예외가 발생했습니다.&quot;);
            System.out.println(&quot;사유: &quot; + e.getMessage());
            closePreparedStatement(pstmt);
            closeConnection(conn);
            return null;
        }

        //쿼리 실행 결과 받아오기
        ResultSet rs = null;
        try {
            rs = pstmt.executeQuery();
        } catch (SQLException e) {
            System.out.println(&quot;쿼리 실행 결과를 받아오는 중에 문제가 생겼습니다.&quot;); 
            System.out.println(&quot;사유: &quot; + e.getMessage());
            closePreparedStatement(pstmt);
            closeConnection(conn);
            return null;
        }

        MembersVO memberVO = null;
        ArticlesVO articleVO = null;

        try {
            if (rs.next()) {
                memberVO = new MembersVO();
                memberVO.setMemberId( rs.getString(&quot;MEMBER_ID&quot;) );
                memberVO.setMemberName( rs.getString(&quot;MEMBER_NAME&quot;) );
                memberVO.setMemberGrade( rs.getString(&quot;MEMBER_GRADE&quot;) );
                memberVO.setProfileImg( rs.getString(&quot;PROFILE_IMG&quot;) );

                articleVO = new ArticlesVO();
                articleVO.setArticleId( rs.getString(&quot;ARTICLE_ID&quot;) );
                articleVO.setMemberId( rs.getString(&quot;MEMBER_ID&quot;) );
                articleVO.setBoardId( rs.getString(&quot;BOARD_ID&quot;) );
                articleVO.setArticleTitle( rs.getString(&quot;ARTICLE_TITLE&quot;) );
                articleVO.setUploadDate( rs.getString(&quot;UPLOAD_DATE&quot;) );
                articleVO.setArticleMain( rs.getString(&quot;ARTICLE_MAIN&quot;) );
                articleVO.setLikeCount( rs.getInt(&quot;LIKE_COUNT&quot;) );
                articleVO.setViewCount( rs.getInt(&quot;VIEW_COUNT&quot;) );

                memberVO.setArticles(null);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        } finally {
            closeResultSet(rs);
            closePreparedStatement(pstmt);
            closeConnection(conn);
        }

        return memberVO;

    }
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JDBC] 과제_0825 (3)]]></title>
            <link>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-3</link>
            <guid>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-3</guid>
            <pubDate>Sun, 27 Aug 2023 07:37:40 GMT</pubDate>
            <description><![CDATA[<p>앞선 내용을 바탕으로 Delete, Insert, Update 메서드에 대한 추상 클래스를 구현한다.</p>
<pre><code class="language-java">public abstract class DeleteInsertUpdate {

    public abstract int deleteOneMemberByMemberId(String Id);
    public abstract int insertNewMember(MembersVO memberVO);
    public abstract int updateMemberGradeByMemberId(String newGrade, String memberId);

}</code></pre>
<p>이를 상속받아 MembersDAO를 구현한다. 부모 클래스의 메서드를 모두 implemente한다.
처음 구현하고자 했던 SELECT 메서드들도 틀을 잡는다.
또한, DB와 통신을 위해, 처음에 구현했던 CafeConnection 클래스도 인스턴스로 생성한다.</p>
<pre><code class="language-java">public class MembersDAO extends DeleteInsertUpdate {

      CafeConnection cafeConnect = new CafeConnection();

      public List&lt;MembersVO&gt; selectAllMembers () {
      }

      public MembersVO selectOneMemberByMemberId (String memberId) {
              return null;
      }

      public MembersVO selectOneMemberAndArticleByMemberId (String memberId) {
              return null;
      }

      @Override
      public int deleteOneMemberByMemberId (String memberId) {
              return 0;
      }

      @Override
      public int insertNewMember (MembersVO memberVO {
              return 0;
      }

      @Override
      public int updateMemberGradeByMemberId (String newGrade, String memberId) {
              return 0;
      }

}</code></pre>
<p>틀은 모두 갖추었으니, 개별 함수를 구현한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JDBC] 과제_0825 (2)]]></title>
            <link>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-2</link>
            <guid>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-2</guid>
            <pubDate>Sun, 27 Aug 2023 07:37:30 GMT</pubDate>
            <description><![CDATA[<p>DAO 클래스에 구현할 메서드 중, 추상 클래스를 상속해서 구현할 방법이 있을까 고민해본다.
DAO에서 추상 클래스를 상속받아 활용하기 위해서는 다음의 조건을 만족해야 한다.
    1. 추상 클래스에서 정의한 메서드가 모두 사용되어야 한다.
    2. 추상 클래스에서 정의한 메서드의 이름, 리턴 타입, parameter의 개수, 자료형, 순서를 동일하게 구현해야 한다.</p>
<p>DAO에서 구현하고자 하는 메서드는 다음과 같다.</p>
<ul>
<li>public List&lt;MembersVO&gt; selectAllMembers () <pre><code class="language-SQL">SELECT * 
 FROM MEMBERS;</code></pre>
</li>
<li>public MembersVO selectOneMemberByMemberId (String memberId) <pre><code class="language-SQL">SELECT * 
FROM MEMBERS
WHERE MEMBER_ID = &#39;memberId&#39;;</code></pre>
</li>
<li>public MembersVO selectOneMemberAndArticleByMemberId (String memberId)<pre><code class="language-SQL">SELECT * 
FROM MEMBERS M 
JOIN ARTICLES A
  ON M.MEMBER_ID = A.MEMBER_ID;</code></pre>
</li>
<li>public int deleteOneMemberByMemberId (String memberId)<pre><code class="language-SQL">DELETE  
FROM MEMBERS M 
WHERE MEMBER_ID = &#39;memberId&#39;;</code></pre>
</li>
<li>public int insertNewMember (MembersVO memberVO)<pre><code class="language-SQL">SELECT * 
  FROM MEMBERS M 
  JOIN ARTICLES A
    ON M.MEMBER_ID = A.MEMBER_ID;</code></pre>
</li>
<li>public int updateMemberGradeByMemberId(String newGrade, String memberId)<pre><code class="language-SQL">UPDATE MEMBERS 
  SET MEMBER_GRADE = &#39;newGrade&#39;
WHERE MEMBER_ID = &#39;memberId&#39;;</code></pre>
<br>
모든 메서드의 리턴 혹은 파라미터가 MemberVO에 종속되어 있다. 추상 클래스 사용이 비효율적인 것 같다.
<br>하지만 DELTE, INSERT, UPDATE에 대해서는 추상 클래스를 생성하여 DAO에서 상속받아 구현해본다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JDBC] 과제_0825 (1)]]></title>
            <link>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-1</link>
            <guid>https://velog.io/@jam2_boyak/JDBC-%EA%B3%BC%EC%A0%9C0825-1</guid>
            <pubDate>Sun, 27 Aug 2023 07:37:15 GMT</pubDate>
            <description><![CDATA[<p>JDBC를 이용해 DB와 통신하는 과제.</p>
<ol>
<li>코드의 중복을 제거하기 위해 Connection을 위한 클래스를 분리하고, Connection을 여는 메서드와 닫는 메서드를 구현한다.</li>
</ol>
<pre><code class="language-java">public class CafeConnection {

        public Connection makeConnection() {
            //1. 드라이버 로딩
            try {
                Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
            } catch (ClassNotFoundException e) {
                System.out.println(&quot;드라이버 로딩에 실패하였습니다.&quot;);
                return null;
            }

            //2. DB 연결
            Connection conn = null;
            String dbURL = &quot;jdbc:oracle:thin:@localhost:1522:XE&quot;;
            String userName = &quot;CAFE&quot;;
            String password = &quot;admin1234&quot;;

            try {
                conn = DriverManager.getConnection(dbURL, userName, password);
            } catch (SQLException e) {
                System.out.println(&quot;연결에 실패하였습니다.&quot;);
                System.out.println(&quot;사유: &quot; + e.getMessage());
            }

            return conn;
        }

        public void closeResultSet(ResultSet rs) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {}
            }
        }

        public void closePreparedStatement(PreparedStatement pstmt) {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {}
            }
        }

        public void closeConnection(Connection conn) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {}
            }
        }


}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 1_데이터 모델링의 이해(2)]]></title>
            <link>https://velog.io/@jam2_boyak/1%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B42</link>
            <guid>https://velog.io/@jam2_boyak/1%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B42</guid>
            <pubDate>Sat, 26 Aug 2023 12:37:16 GMT</pubDate>
            <description><![CDATA[<h3 id="2-엔티티">2. 엔티티</h3>
<ol>
<li>정의: 업무에서 관리해야하는 데이터 집합<ol>
<li>개념, 사건, 장소 등의 명사형, 인스턴스의 집합</li>
</ol>
</li>
<li>특징<ol>
<li>식별자: 유일한 식별자가 있어야 한다 (ex. 도서관 회원번호)</li>
<li>인스턴스 집합: 2개 이상의 인스턴스가 있어야 한다</li>
<li>속성: 반드시 속성을 가지고 있어야 한다 (ex. 회원 이름, 회원 주소 등)</li>
<li>관계: 다른 엔티티와 최소 한 개 이상의 관계를 가져야 한다 (ex. 회원은 도서를 대출한다)</li>
<li>업무: 반드시 업무에서 관리되어야 할 집합이어야 한다 (ex. 회원, 도서)</li>
</ol>
</li>
<li>엔티티 분류<ol>
<li>형태에 따른 분류<ol>
<li>유형 엔티티: 업무에서 도출되는 지속적으로 사용되며 물리적 형태를 갖는 엔티티 (ex. 회원, 도서)</li>
<li>사건 엔티티: 업무를 수행함에 따라 생성되는 업무 관련 행위의 엔티티. 각종 통계에 이용 가능 (ex. 대출, 반납)</li>
<li>개념 엔티티: 오직 개념적으로만 사용되며 물리적 형태가 없는 엔티티 (ex. 조직, 보험 상품)</li>
</ol>
</li>
<li>발생 시점에 따른 분류<ol>
<li>기본 엔티티(Key Entity): 독립적으로 생성되는 엔티티 (ex. 회원, 도서)</li>
<li>중심 엔티티(Main Entity): 기본 엔티티로부터 발생되며, 업무에서 중심 역할을 수행해 행위 엔티티를 생성 (ex. 대출, 반납)</li>
<li>행위 엔티티(Active Entity): 비즈니스 프로세스를 통하여 두 개 이상의 엔티티로부터 발생하는 엔티티 (ex. 대출 회원 목록, 반납 도서 목록) → 지속적으로 정보가 추가되고 변경되어 데이터 양이 가장 많음</li>
</ol>
</li>
</ol>
</li>
<li>엔티티 명명 규칙<ol>
<li>실제 업무에서 사용하는 용어</li>
<li>약어 지양</li>
<li>단수 명사</li>
<li>유일성 보장</li>
<li>명확성</li>
</ol>
</li>
</ol>
<h3 id="3-속성">3. 속성</h3>
<ol>
<li>정의<ol>
<li>엔티티가 가지는 항목이며 더 이상 분리되지 않는 데이터 단위</li>
<li>엔티티 가지는 최소 의미 단위</li>
<li>인스턴스의 구성 요소</li>
</ol>
</li>
<li>분류<ol>
<li>엔티티 구성에 따른 분류<ol>
<li>PK 속성: 엔티티를 식별할 수 있는 속성</li>
<li>FK 속성: 다른 엔티티와의 관계에서 포함된 속성</li>
<li>일반 속성: 엔티티에 포함되고 PK, FK가 아닌 속성</li>
</ol>
</li>
<li>분해 여부에 따른 분류<ol>
<li>복합 속성: 여러 개의 의미를 지닌 속성</li>
<li>단일 속성: 오직 하나의 의미를 지닌 속성. 하나의 속성은 한 개의 값만을 갖게 됨</li>
<li>다중 값 속성: 하나의 속성이 여러 값을 갖는 경우. 정규화 과정을 거쳐 별도의 엔티티를 생성하여 관계로 연결해야 함.</li>
</ol>
</li>
<li>특성에 따른 분류<ol>
<li>기본 속성: 업무로부터 추출한 모든 속성. 엔티티 중 가장 많은 비율 차지.</li>
<li>설계 속성: 업무상 필요하지는 않지만, 데이터 모델링을 위해 생성하거나 변형하여 정의하는 속성. 일련번호와 같은 유일 값을 갖게 됨 (ex. 도서 번호 PK)</li>
<li>파생 속성: 다른 속성의 영향을 받아 발생하는 속성. 주로 집계 등의 속성이 해당됨 (ex. 평균, 합계)</li>
</ol>
</li>
</ol>
</li>
</ol>
<p>참고: <a href="https://mjn5027.tistory.com/100">https://mjn5027.tistory.com/100</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLD] 1_데이터 모델링의 이해(1)]]></title>
            <link>https://velog.io/@jam2_boyak/SQLD-%EC%A4%80%EB%B9%84-1%EC%9E%A5.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@jam2_boyak/SQLD-%EC%A4%80%EB%B9%84-1%EC%9E%A5.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Sat, 26 Aug 2023 12:13:11 GMT</pubDate>
            <description><![CDATA[<h2 id="1장-데이터-모델링의-이해">1장. 데이터 모델링의 이해</h2>
<h3 id="1-데이터-모델의-이해">1. 데이터 모델의 이해</h3>
<ol>
<li>데이터 모델링: 현실 세계를 단순화하여 표현하는 것.<ol>
<li>현실 세계의 정보와 업무를 데이터와 기능의 관점으로  분석하는 것</li>
<li>데이터베이스를 구축하기 위한 분석 및 설계의 과정</li>
</ol>
</li>
<li>데이터 모델링의 특징<ol>
<li>추상화: 현실을 일정한 양식(표기법)에 맞추어 표현</li>
<li>단순화: 누구나 이해하기 쉽도록 약속된 규약에 의한 제한된 표기법 또는 언어를 이용하여 표현</li>
<li>명확화: 명확하게 한 가지 해석될 수 있도록 애매모호함을 제거하고 정확하게 현상을 기술</li>
</ol>
</li>
<li>데이터 모델링의 관점<ol>
<li>데이터 관점: 데이터와 업무 간의 관계, 데이터와 데이터 간의 관계가 무엇인지에 따라 모델링. 비즈니스 프로세스에서 사용되는 데이터를 의미.<ol>
<li>구조 분석, 정적 분석</li>
</ol>
</li>
<li>프로세스 관점: 실제 하는 업무에 따라 무엇을 어떻게 하는지 모델링. 비즈니스 프로세스에서 수행하는 작업을 의미.<ol>
<li>시나리오 분석, 동적 분석</li>
</ol>
</li>
<li>데이터와 프로세스의 상관 관점: 업무의 처리(프로세스)와 데이터 간에 서로 어떤 영향을 주고받는지 모델링. 프로세스와 데이터 간의 관계를 의미. 실무에서 가장 많이 쓰임.<ol>
<li>CRUD(Create, Read, Update, Delete)</li>
</ol>
</li>
</ol>
</li>
<li>데이터 모델링의 단계<ol>
<li>개념적 모델링: 추상화 수준이 높고, 업무 중심적인 포괄적인 수준의 모델링<ol>
<li>엔티티와 속성을 도출하며, 개념적 ERD를 작성하는 단계</li>
</ol>
</li>
<li>논리적 모델링: 식별자를 도출하고 속성과 관계 등을 정의<ol>
<li>정규화를 수행하여 데이터 모델의 독립성과 재사용성을 확보</li>
<li>데이터 모델링이 완료된 상태</li>
</ol>
</li>
<li>물리적 모델링: 실제 DB에 적용할 수 있도록 물리적인 성능과 데이터  저장을 고려한 설계 단계<ol>
<li>가장 구체적인 수준의 데이터 모델링으로, 추상화 수준이 가장 낮은 단계</li>
<li>성능, 보안, 가용성 등을 고려한 DB 모델링 진행</li>
</ol>
</li>
</ol>
</li>
<li>3단계 구조 스키마(3-Level Schema)<ol>
<li>DB의 독립성을 위해 3단계 구조 스키마가 존재</li>
<li>사용자(외부 스키마), 설계자(내부 스키마), 개발자(개념 스키마)의 각 관점에 따라 DB를 기술하고, 이들 간의 관계를 ANSI 표준으로 지정</li>
<li>데이터의 독립성 확보를 통해 얻는 장점<ol>
<li>데이터 복잡도 감소</li>
<li>데이터 중복 제거</li>
<li>사용자 요구 사항 변경에 따른 대응력 향상</li>
<li>관리 및 유지보수 비용 절감</li>
</ol>
</li>
<li>각 계층을 뷰(VIEW)라고 부르며, 3단계 계층으로 분리되어 서로 독립성을 확보</li>
</ol>
</li>
<li>3단계 구조 스키마의 특징<ol>
<li>외부 스키마: DB의 개별 사용자 관점의 이해와 표현<ol>
<li>응용 프로그램이 데이터에 접근하는 View를 표현</li>
</ol>
</li>
<li>개념 스키마: DB 관리자의 관점으로 규칙과 구조 표현<ol>
<li>DB의 전체적인 논리 구조</li>
</ol>
</li>
<li>내부 스키마: DB 시스템 설계자의 관점으로 저장 장치 관점의 이해 및 표현<ol>
<li>데이터가 실제로 DB에 물리적으로 어떻게 저장되는지 확인</li>
</ol>
</li>
</ol>
</li>
<li>데이터 모델링을 위한 ERD(Entity Relationship Diagram)<ol>
<li>대표적인 표기법: 바커 표기법 (Baker Notation), I/E 표기법 (Information Engineering Notation)</li>
<li>ERD 작성 순서<ol>
<li>엔티티 도출</li>
<li>엔티티 배치</li>
<li>엔티티 관계 설정</li>
<li>관계명 기술</li>
<li>관계 참여도 기술 → 1:1, 1:N, N:N</li>
<li>관계 필수 여부 기술</li>
</ol>
</li>
</ol>
</li>
</ol>
<p>참고: <a href="https://mjn5027.tistory.com/100">https://mjn5027.tistory.com/100</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫글]]></title>
            <link>https://velog.io/@jam2_boyak/%EC%B2%AB%EA%B8%80</link>
            <guid>https://velog.io/@jam2_boyak/%EC%B2%AB%EA%B8%80</guid>
            <pubDate>Sun, 16 Jul 2023 13:22:17 GMT</pubDate>
            <description><![CDATA[<p>백엔드 개발자가 되기 위해 공부 중입니다</p>
]]></description>
        </item>
    </channel>
</rss>