<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>readyoun's devlog</title>
    <link>https://readyoun.tistory.com/</link>
    <description>&amp;quot;Computer science is an art of problem-solving.&amp;quot;

github.com/ready-oun</description>
    <language>ko</language>
    <pubDate>Wed, 8 Apr 2026 23:28:32 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>readyoun</managingEditor>
    <image>
      <title>readyoun's devlog</title>
      <url>https://tistory1.daumcdn.net/tistory/7574567/attach/dae138a4524f44bf82b219d39e2fc8f3</url>
      <link>https://readyoun.tistory.com</link>
    </image>
    <item>
      <title>복잡도와 핵심 자료구조 (C++, Java, Python 예시)</title>
      <link>https://readyoun.tistory.com/49</link>
      <description>&lt;h1&gt;  [5.1 복잡도] 이해 완전 정복&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접을 위한 CS 전공지식노트 p.231 - 262 기반으로 작성.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 복잡도가 뭐지?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘의 성능을 수치화한 기준입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡도는 코드가 얼마나 빠르고 효율적으로 동작하는지를 판단하는 &lt;b&gt;&amp;lsquo;시간과 공간 자원의 소비량&amp;rsquo;&lt;/b&gt;을 나타내는 척도예요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간 복잡도(Time Complexity)&lt;/b&gt;: 코드가 실행되는데 걸리는 시간 (≒ 반복 횟수)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 복잡도(Space Complexity)&lt;/b&gt;: 코드가 실행될 때 사용하는 메모리 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 5.1.1 시간 복잡도&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  시간 복잡도란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력의 크기(n)가 커질수록, &lt;b&gt;코드가 얼마나 더 느려지는지&lt;/b&gt;를 보는 것.&lt;br /&gt;실제 걸리는 &amp;lsquo;초&amp;rsquo; 단위 시간은 아니고, &lt;b&gt;입력 크기에 비례하는 &amp;lsquo;연산 횟수&amp;rsquo;를 수학적으로 나타낸 것&lt;/b&gt;이에요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  왜 중요할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;O(n&amp;sup2;)&lt;/code&gt; 알고리즘은 n이 10 &amp;rarr; 100이 되면 연산 횟수가 &lt;b&gt;100배 &amp;rarr; 10,000배&lt;/b&gt;로 늘어나요!&lt;/li&gt;
&lt;li&gt;반면 &lt;code&gt;O(n log n)&lt;/code&gt;은 훨씬 완만하게 증가해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  대표적인 시간 복잡도&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;빅오&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;입력 크기와 무관하게 항상 일정한 시간&lt;/td&gt;
&lt;td&gt;해시 테이블 조회&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O(log n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;절반씩 나눠서 탐색&lt;/td&gt;
&lt;td&gt;이진 탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;모든 요소를 순회&lt;/td&gt;
&lt;td&gt;선형 검색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O(n log n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정렬 알고리즘의 평균 성능&lt;/td&gt;
&lt;td&gt;병합 정렬, 힙 정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O(n&amp;sup2;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이중 반복문&lt;/td&gt;
&lt;td&gt;버블 정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O(2ⁿ)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;모든 경우의 수 탐색&lt;/td&gt;
&lt;td&gt;부분 집합 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  핵심: 빠른 코드를 짜고 싶다면 O(1) &amp;rarr; O(log n) &amp;rarr; O(n) 순으로 지향해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  빅오 표기법 (Big-O Notation)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 영향력 있는 항만 남기고 나머진 버리는 방식&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; n; i++) { 
    for (int j = 0; j &amp;lt; n; j++) { 
        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; j &amp;lt;&amp;lt; '\n'; 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 루프 &amp;rarr; 반복 횟수: &lt;code&gt;n * n = n&amp;sup2;&lt;/code&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; 시간 복잡도: &lt;code&gt;O(n&amp;sup2;)&lt;/code&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⛔ 왜 상수는 무시할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: &lt;code&gt;10n&amp;sup2; + 5n + 20&lt;/code&gt; &amp;rarr; &lt;code&gt;O(n&amp;sup2;)&lt;/code&gt;&lt;br /&gt;입력 크기 n이 커지면 10, 5, 20은 전혀 중요하지 않게 되니까요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⌛ 5.1.2 공간 복잡도&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;알고리즘이 얼마만큼의 메모리를 쓰는가?&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 배열: &lt;code&gt;int a[1000]&lt;/code&gt; &amp;rarr; 약 4KB 사용&lt;/li&gt;
&lt;li&gt;재귀 호출: 함수 스택 계속 쌓이므로 공간 복잡도 커짐&lt;/li&gt;
&lt;li&gt;반복문 vs 재귀함수: 반복문은 공간 낭비 거의 없음, 재귀는 &lt;b&gt;함수 호출마다 스택이 쌓임&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  5.1.3 자료 구조별 시간 복잡도&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 평균 시간 복잡도 (일반적인 상황)&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료구조&lt;/th&gt;
&lt;th&gt;접근&lt;/th&gt;
&lt;th&gt;탐색&lt;/th&gt;
&lt;th&gt;삽입&lt;/th&gt;
&lt;th&gt;삭제&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;배열&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스택/큐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;연결 리스트&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해시 테이블&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이진 탐색 트리&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(log n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(log n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(log n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(log n)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AVL, 레드-블랙 트리&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(log n)&lt;/code&gt; 전부&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❗ 최악의 시간 복잡도 (엣지 케이스)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해시 테이블: 모든 key가 같은 해시값 &amp;rarr; 연결 리스트처럼 되어 &lt;code&gt;O(n)&lt;/code&gt;됨&lt;/li&gt;
&lt;li&gt;이진 탐색 트리: 정렬된 값이 삽입되면 선형 구조가 되어 &lt;code&gt;O(n)&lt;/code&gt;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  평균 vs 최악 복잡도 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;비교&lt;/th&gt;
&lt;th&gt;평균&lt;/th&gt;
&lt;th&gt;최악&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;해시 테이블&lt;/td&gt;
&lt;td&gt;빠름 (&lt;code&gt;O(1)&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;느림 (&lt;code&gt;O(n)&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AVL 트리&lt;/td&gt;
&lt;td&gt;안정적 (&lt;code&gt;O(log n)&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;안정적 (&lt;code&gt;O(log n)&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;연결 리스트&lt;/td&gt;
&lt;td&gt;삽입은 빠름 (&lt;code&gt;O(1)&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;탐색은 느림 (&lt;code&gt;O(n)&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  언제 어떤 걸 선택할까?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;빠른 검색이 중요&lt;/code&gt;하다 &amp;rarr; 해시 테이블 (단, 충돌 대비 필요)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;항상 일정 성능 보장&lt;/code&gt; &amp;rarr; AVL, Red-Black Tree&lt;/li&gt;
&lt;li&gt;&lt;code&gt;삽입/삭제 자주&lt;/code&gt; &amp;rarr; 연결 리스트&lt;/li&gt;
&lt;li&gt;&lt;code&gt;배열처럼 빠른 접근&lt;/code&gt; + &lt;code&gt;크기 유동적&lt;/code&gt; &amp;rarr; 벡터&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  한 문장 요약&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간과 공간 복잡도를 분석하면 성능 좋고 버그 없는 코드 설계가 가능해진다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  [5.2 복잡도] 선형 자료 구조&lt;/h1&gt;
&lt;h1&gt;  5.2.1 연결 리스트 (Linked List)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 연결 리스트란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 저장하는 노드들을 포인터로 연결해서 구성한 선형 자료구조입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열은 메모리에 &lt;b&gt;연속적으로 저장&lt;/b&gt;되지만,&lt;br /&gt;연결 리스트는 &lt;b&gt;각 노드가 흩어져&lt;/b&gt; 있으며,&lt;br /&gt;노드 간 연결만 포인터로 이어져 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  구성 요소&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;노드(Node)&lt;/b&gt;: 하나의 데이터 + 다음 노드를 가리키는 포인터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포인터(Pointer)&lt;/b&gt;: 다음(혹은 이전) 노드의 주소를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, 연결 리스트는 &amp;lsquo;노드들의 체인&amp;rsquo;이다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  연결 리스트의 종류&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;방향&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;단일 연결 리스트&lt;/td&gt;
&lt;td&gt;각 노드가 다음 노드만 가리킴&lt;/td&gt;
&lt;td&gt;한 방향&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이중 연결 리스트&lt;/td&gt;
&lt;td&gt;각 노드가 이전/다음 노드 모두 가리킴&lt;/td&gt;
&lt;td&gt;양 방향&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;원형 연결 리스트&lt;/td&gt;
&lt;td&gt;마지막 노드가 처음 노드를 가리킴&lt;/td&gt;
&lt;td&gt;순환 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 5-3: 세 가지 구조 비교&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  특징 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리는 &lt;b&gt;연속적이지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입/삭제가 빠름&lt;/b&gt; (중간 삽입도 링크만 바꾸면 됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임의 접근이 불가능&lt;/b&gt; (배열처럼 인덱스로 바로 접근 못함)&lt;/li&gt;
&lt;li&gt;동적 크기 조절 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;접근&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;원하는 위치까지 순회 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;탐색&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;조건 만족하는 값 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;포인터만 조작하면 됨 (위치 알고 있다면)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;포인터만 끊으면 됨 (위치 알고 있다면)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의&lt;br /&gt;&lt;/b&gt;삽입/삭제가 빠르다는 것은 &quot;노드 위치를 알고 있는 경우&quot; 에 한정됨.&lt;br /&gt;위치를 모른다면 역시 O(n)만큼 순회해야 함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C++ 코드 예시 (STL &lt;code&gt;list&lt;/code&gt; 활용)&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std; 

int main() {
    list&amp;lt;int&amp;gt; a; 
    for (int i = 0; i &amp;lt; 10; i++) a.push_back(i); 
    for (int i = 0; i &amp;lt; 10; i++) a.push_front(i); 

    auto it = a.begin(); 
    ++it; 
    a.insert(it, 1000); 

    for (auto x : a) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; &quot;; 
    cout &amp;lt;&amp;lt; '\n';

    a.pop_front(); 
    a.pop_back(); 

    for (auto x : a) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; &quot;;
    cout &amp;lt;&amp;lt; '\n'; 
    return 0; 
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;push_front(): 앞에 삽입&lt;br /&gt;push_back(): 뒤에 삽입&lt;br /&gt;insert(): 특정 위치 삽입&lt;br /&gt;pop_front(), pop_back(): 앞/뒤 삭제&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java와 Python 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Java: &lt;code&gt;LinkedList&lt;/code&gt; 클래스&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;LinkedList&amp;lt;String&amp;gt; list = new LinkedList&amp;lt;&amp;gt;();
list.add(&quot;사과&quot;);
list.addFirst(&quot;바나나&quot;);
list.addLast(&quot;오렌지&quot;);
list.add(1, &quot;포도&quot;);

System.out.println(list.getFirst()); // 바나나
list.remove(&quot;포도&quot;);
for (String item : list) System.out.println(item);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python: &lt;code&gt;collections.deque&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from collections import deque

linked_list = deque()
linked_list.append(&quot;사과&quot;)
linked_list.appendleft(&quot;바나나&quot;)
linked_list.append(&quot;오렌지&quot;)
linked_list.insert(1, &quot;포도&quot;)

print(linked_list[0])  # 바나나
linked_list.remove(&quot;포도&quot;)
for item in linked_list: print(item)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python의 deque는 이중 연결 리스트 기반으로 되어 있어 삽입/삭제가 효율적입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 리스트는 메모리 효율적이고, 삽입/삭제가 빠름&lt;/li&gt;
&lt;li&gt;단점은 임의 접근이 느리다는 점 (순차 접근만 가능)&lt;/li&gt;
&lt;li&gt;다양한 언어에서 기본 라이브러리로 제공되며, 구조 이해가 중요&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.2.2 배열 (Array)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 배열이란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 타입의 데이터를 &lt;b&gt;연속된 메모리 공간&lt;/b&gt;에 저장한 자료 구조입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어에서 가장 기본이 되는 자료구조이며, &lt;b&gt;고정 크기&lt;/b&gt;, &lt;b&gt;빠른 접근 속도&lt;/b&gt;가 특징입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  배열의 특징&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;동일한 타입&lt;/b&gt;의 요소들을 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고정된 크기&lt;/b&gt; (생성 시 크기 결정, 이후 변경 불가)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 연속 배치&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인덱스를 통한 직접 접근 가능 (랜덤 접근)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복 허용&lt;/b&gt;, &lt;b&gt;순서 존재&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  접근 방식&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 5-4 참고: 랜덤 접근 vs 순차 접근&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;접근 방식&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;대표 자료구조&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;랜덤 접근&lt;/td&gt;
&lt;td&gt;인덱스를 통해 즉시 접근 (주소 계산)&lt;/td&gt;
&lt;td&gt;배열, 벡터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;순차 접근&lt;/td&gt;
&lt;td&gt;앞에서부터 차례로 접근해야 함&lt;/td&gt;
&lt;td&gt;연결 리스트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⚔️ 배열 vs 연결 리스트&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기준&lt;/th&gt;
&lt;th&gt;배열&lt;/th&gt;
&lt;th&gt;연결 리스트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;메모리 배치&lt;/td&gt;
&lt;td&gt;연속적&lt;/td&gt;
&lt;td&gt;비연속적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;접근 속도&lt;/td&gt;
&lt;td&gt;빠름 &lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;느림 &lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입/삭제&lt;/td&gt;
&lt;td&gt;느림 &lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;빠름 &lt;code&gt;O(1)&lt;/code&gt; (위치 알고 있을 경우)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;크기 조절&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;캐시 적중률&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열은 메모리 캐시에 잘 맞아서 CPU 접근 속도도 빠름&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 배열의 시간 복잡도&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;접근&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;인덱스만 알면 주소 계산으로 즉시 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;선형 검색 필요 (정렬된 경우 이진 탐색은 &lt;code&gt;O(log n)&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;중간 삽입 시 요소 이동 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;중간 삭제 시 요소 이동 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 끝에 삽입/삭제는 O(1)이 될 수 있음 (배열의 크기만 충분하다면)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C/C++ 배열 예시&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int arr[5] = {10, 20, 30, 40, 50};
cout &amp;lt;&amp;lt; arr[2];  // 30 출력&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;arr[2]&lt;/code&gt;는 시작 주소 + 2칸 만큼 이동해서 값을 바로 가져옴&lt;br /&gt;&amp;rarr; O(1) 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java 배열 예시&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr = {10, 20, 30, 40, 50};
System.out.println(arr[2]); // 30&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열은 생성 후 크기를 변경할 수 없음&lt;/li&gt;
&lt;li&gt;대신 Java에서는 &lt;code&gt;ArrayList&lt;/code&gt;로 동적 배열 기능을 확장함 (다음 섹션)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 배열 (&lt;code&gt;list&lt;/code&gt;) 예시&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;arr = [10, 20, 30, 40, 50]
print(arr[2])  # 30&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Python의 &lt;code&gt;list&lt;/code&gt;는 내부적으로 동적 배열&lt;/li&gt;
&lt;li&gt;&lt;code&gt;append()&lt;/code&gt;, &lt;code&gt;insert()&lt;/code&gt;, &lt;code&gt;pop()&lt;/code&gt; 등의 메서드 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열은 &lt;b&gt;빠른 접근&lt;/b&gt;과 &lt;b&gt;고정 크기&lt;/b&gt;라는 명확한 장점이 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입/삭제&lt;/b&gt;에는 부적합 (특히 중간에)&lt;/li&gt;
&lt;li&gt;알고리즘에서 &lt;b&gt;빠른 참조&lt;/b&gt;가 필요한 경우 유리&lt;/li&gt;
&lt;li&gt;연결 리스트와 비교해 장단점을 이해하고 상황에 맞게 선택해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.2.3 벡터 (Vector)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 벡터란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기를 동적으로 조절할 수 있는 &lt;b&gt;동적 배열(Dynamic Array)&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 배열처럼 동작하지만, &lt;b&gt;필요에 따라 자동으로 메모리를 재할당&lt;/b&gt;하면서 크기를 늘릴 수 있습니다.&lt;br /&gt;C++에서는 &lt;code&gt;std::vector&lt;/code&gt;, Java에서는 &lt;code&gt;ArrayList&lt;/code&gt;, Python에서는 &lt;code&gt;list&lt;/code&gt;가 이에 해당합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  벡터의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;연속된 메모리 공간&lt;/b&gt;을 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복 허용&lt;/b&gt;, &lt;b&gt;순서 보장&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;요소가 가득 차면 &lt;b&gt;더 큰 공간을 새로 할당하고 기존 데이터를 복사&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;크기 증가 시 보통 &lt;b&gt;2배&lt;/b&gt;로 늘려 재할당 &amp;rarr; 효율적 성장&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  배열과의 차이점&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기준&lt;/th&gt;
&lt;th&gt;배열 (Array)&lt;/th&gt;
&lt;th&gt;벡터 (Vector)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;크기&lt;/td&gt;
&lt;td&gt;고정&lt;/td&gt;
&lt;td&gt;동적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메모리&lt;/td&gt;
&lt;td&gt;사용자 지정&lt;/td&gt;
&lt;td&gt;자동 할당/재할당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입/삭제&lt;/td&gt;
&lt;td&gt;비효율적&lt;/td&gt;
&lt;td&gt;상대적으로 유연&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;접근 방식&lt;/td&gt;
&lt;td&gt;인덱스 기반&lt;/td&gt;
&lt;td&gt;인덱스 기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;성능&lt;/td&gt;
&lt;td&gt;더 빠름&lt;/td&gt;
&lt;td&gt;약간 오버헤드 있음 (성장 시 복사)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 벡터의 시간 복잡도&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;접근&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;배열처럼 인덱스로 직접 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;선형 탐색 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입 (끝)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;평균&lt;/b&gt; O(1)&lt;/td&gt;
&lt;td&gt;공간이 남아있으면 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입 (중간)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;요소 이동 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제 (끝)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;마지막 요소 제거는 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제 (중간)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;요소 이동 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입/삭제는 &lt;b&gt;끝&lt;/b&gt;에서 하면 빠르지만, &lt;b&gt;중간&lt;/b&gt;에서는 느림&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  amortized time (분할 상환 시간 복잡도)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;push_back()&lt;/code&gt;은 보통 O(1)이지만, &lt;b&gt;가끔 O(n)이 발생&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;i&gt;예: 벡터가 가득 찬 경우 &amp;rarr; &lt;b&gt;더 큰 배열 생성 + 전체 복사&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이런 일이 매번 일어나는 게 아니라, 전체적으로 보면 &lt;b&gt;평균 O(1)&lt;/b&gt; 로 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이것을 &lt;code&gt;분할 상환 분석(amortized analysis)&lt;/code&gt;라고 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C++ 벡터 예시&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;vector&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;

int main() {
    vector&amp;lt;int&amp;gt; v;

    for (int i = 0; i &amp;lt; 5; i++) v.push_back(i);  // 끝에 삽입

    v.insert(v.begin() + 2, 100);  // 중간 삽입
    v.pop_back();                  // 마지막 요소 제거

    for (int i : v) cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; &quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java ArrayList 예시&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.*;

public class Main {
    public static void main(String[] args) {
        ArrayList&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

        list.add(10);              // 끝에 추가
        list.add(1, 20);           // 특정 위치 삽입
        list.remove(0);            // 인덱스로 삭제

        for (int i : list) System.out.println(i);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python list 예시&lt;/h2&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;lst = []
lst.append(10)       # 끝에 추가
lst.insert(1, 20)     # 인덱스 1에 삽입
lst.pop()            # 끝에서 제거
print(lst)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python의 &lt;code&gt;list&lt;/code&gt;는 내부적으로 C 배열 기반의 &lt;b&gt;동적 배열 구조&lt;/b&gt;입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;벡터는 배열처럼 빠른 접근(O(1)) + 동적 크기 조절이 가능한 자료구조&lt;/li&gt;
&lt;li&gt;끝에 삽입/삭제는 빠르지만, 중간 삽입/삭제는 성능 저하&lt;/li&gt;
&lt;li&gt;대부분의 현대 언어에서 &lt;b&gt;표준 동적 배열 타입&lt;/b&gt;으로 제공&lt;/li&gt;
&lt;li&gt;알고리즘 문제 풀 때 &lt;code&gt;배열 vs 벡터&lt;/code&gt;는 크기 조절이 필요한지를 기준으로 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.2.5 큐 (Queue)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 큐란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 넣은 데이터가 먼저 나오는 자료구조&lt;br /&gt;&lt;b&gt;&amp;rarr; FIFO (First-In, First-Out) 구조&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;일상 예시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;줄 서서 기다리는 은행 창구&lt;/li&gt;
&lt;li&gt;대기열이 있는 프린터&lt;/li&gt;
&lt;li&gt;음식점 번호표 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  주요 연산&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enqueue()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;큐 &lt;b&gt;뒤에 삽입&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dequeue()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;큐 &lt;b&gt;앞에서 제거&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;front()&lt;/code&gt; 또는 &lt;code&gt;peek()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;맨 앞의 요소 확인 (삭제 X)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEmpty()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;큐가 비었는지 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;뒤에 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;앞에서 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;조회&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;맨 앞만 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;특정 값 탐색 시 전체 순회 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C++ STL 큐 예시&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;queue&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;

int main() {
    queue&amp;lt;int&amp;gt; q;

    q.push(10);       // enqueue
    q.push(20);
    q.push(30);

    cout &amp;lt;&amp;lt; q.front(); // 10
    q.pop();           // dequeue

    cout &amp;lt;&amp;lt; q.front(); // 20
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java Queue 예시&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.*;

public class Main {
    public static void main(String[] args) {
        Queue&amp;lt;Integer&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();

        q.add(10);             // enqueue
        q.add(20);
        q.add(30);

        System.out.println(q.peek()); // 10
        q.remove();                   // dequeue
        System.out.println(q.peek()); // 20
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 큐 예시 (&lt;code&gt;collections.deque&lt;/code&gt; 추천)&lt;/h2&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;from collections import deque

q = deque()
q.append(10)      # enqueue
q.append(20)
q.append(30)

print(q[0])       # front: 10
q.popleft()       # dequeue
print(q[0])       # front: 20&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list로 큐를 구현하면 pop(0)이 느려서 &lt;b&gt;deque 사용을 권장&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  큐는 언제 사용할까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터를 순차적으로 처리할 때&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기 처리 / 버퍼링 / BFS 탐색 등&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 프로그래밍에서 프로세스 대기열 구현 시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.3.1 그래프 (Graph)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 그래프란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 봤던 배열&amp;middot;리스트&amp;middot;큐 등은 &quot;일렬로 나열된 구조&quot;였지만, &lt;br /&gt;&lt;br /&gt;그래프는 &lt;b&gt;노드들 간의 관계가 복잡하게 얽힌 구조&lt;/b&gt;.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정점(Vertex) 과 간선(Edge) 으로 이루어진 비선형 자료구조 &lt;br /&gt;&lt;br /&gt;&amp;rarr; 사물 간의 &lt;b&gt;복잡한 관계&lt;/b&gt;를 표현할 수 있음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지도(도시와 도로)&lt;/li&gt;
&lt;li&gt;SNS 관계(사람과 친구 관계)&lt;/li&gt;
&lt;li&gt;웹사이트 연결(페이지와 링크)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  구성 요소&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;요소&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정점 (Vertex)&lt;/td&gt;
&lt;td&gt;데이터를 담는 단위, 즉 &lt;b&gt;노드&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;간선 (Edge)&lt;/td&gt;
&lt;td&gt;정점 간의 연결 (양방향/단방향 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;진입 차수 (In-degree)&lt;/td&gt;
&lt;td&gt;특정 정점으로 &lt;b&gt;들어오는 간선 수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;진출 차수 (Out-degree)&lt;/td&gt;
&lt;td&gt;특정 정점에서 &lt;b&gt;나가는 간선 수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  그래프의 종류&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;무방향 그래프&lt;/td&gt;
&lt;td&gt;간선에 방향 없음&lt;/td&gt;
&lt;td&gt;A&amp;mdash;B: A&amp;rarr;B, B&amp;rarr;A 모두 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;방향 그래프&lt;/td&gt;
&lt;td&gt;간선에 방향 있음&lt;/td&gt;
&lt;td&gt;A&amp;rarr;B는 B&amp;rarr;A와는 다름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가중치 그래프&lt;/td&gt;
&lt;td&gt;간선에 &lt;b&gt;비용/거리&lt;/b&gt; 등의 숫자가 있음&lt;/td&gt;
&lt;td&gt;길이, 시간, 비용 표현 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⛓️ 그래프의 표현 방식&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;공간 복잡도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;인접 행렬 (Adjacency Matrix)&lt;/td&gt;
&lt;td&gt;2차원 배열로 간선 표현&lt;/td&gt;
&lt;td&gt;O(V&amp;sup2;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;인접 리스트 (Adjacency List)&lt;/td&gt;
&lt;td&gt;각 정점이 연결된 정점 리스트 보유&lt;/td&gt;
&lt;td&gt;O(V + E)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;V: 정점 수, E: 간선 수&lt;/b&gt;&lt;br /&gt;일반적으로 &lt;b&gt;인접 리스트&lt;/b&gt;가 메모리 효율이 좋음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도 참고&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;인접 리스트&lt;/th&gt;
&lt;th&gt;인접 행렬&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;간선 존재 확인&lt;/td&gt;
&lt;td&gt;O(정점 개수)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;모든 간선 순회&lt;/td&gt;
&lt;td&gt;O(V + E)&lt;/td&gt;
&lt;td&gt;O(V&amp;sup2;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 그래프 인접 리스트 예시&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;graph = {
    0: [1, 2],
    1: [0, 3],
    2: [0],
    3: [1]
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 인접 행렬 예시&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;graph = [
    [0, 1, 1, 0],
    [1, 0, 0, 1],
    [1, 0, 0, 0],
    [0, 1, 0, 0]
]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C++ 그래프 표현 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 인접 리스트 (vector of vector)&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;

int main() {
    int V = 4;
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; graph(V);

    graph[0].push_back(1);
    graph[0].push_back(2);
    graph[1].push_back(0);
    graph[1].push_back(3);
    graph[2].push_back(0);
    graph[3].push_back(1);

    // 출력
    for (int i = 0; i &amp;lt; V; i++) {
        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; : &quot;;
        for (int j : graph[i]) cout &amp;lt;&amp;lt; j &amp;lt;&amp;lt; &quot; &quot;;
        cout &amp;lt;&amp;lt; '\n';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 인접 행렬&lt;/h3&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int main() {
    int graph[4][4] = {
        {0, 1, 1, 0},
        {1, 0, 0, 1},
        {1, 0, 0, 0},
        {0, 1, 0, 0}
    };

    for (int i = 0; i &amp;lt; 4; i++) {
        for (int j = 0; j &amp;lt; 4; j++) {
            cout &amp;lt;&amp;lt; graph[i][j] &amp;lt;&amp;lt; &quot; &quot;;
        }
        cout &amp;lt;&amp;lt; '\n';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java 그래프 표현 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 인접 리스트 (ArrayList)&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;import java.util.*;

public class Main {
    public static void main(String[] args) {
        int V = 4;
        ArrayList&amp;lt;ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph = new ArrayList&amp;lt;&amp;gt;();

        for (int i = 0; i &amp;lt; V; i++)
            graph.add(new ArrayList&amp;lt;&amp;gt;());

        graph.get(0).add(1);
        graph.get(0).add(2);
        graph.get(1).add(0);
        graph.get(1).add(3);
        graph.get(2).add(0);
        graph.get(3).add(1);

        for (int i = 0; i &amp;lt; V; i++) {
            System.out.print(i + &quot; : &quot;);
            for (int j : graph.get(i)) {
                System.out.print(j + &quot; &quot;);
            }
            System.out.println();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 인접 행렬&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        int[][] graph = {
            {0, 1, 1, 0},
            {1, 0, 0, 1},
            {1, 0, 0, 0},
            {0, 1, 0, 0}
        };

        for (int i = 0; i &amp;lt; graph.length; i++) {
            for (int j = 0; j &amp;lt; graph[i].length; j++) {
                System.out.print(graph[i][j] + &quot; &quot;);
            }
            System.out.println();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요약하자면:&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;언어&lt;/th&gt;
&lt;th&gt;인접 리스트&lt;/th&gt;
&lt;th&gt;인접 행렬&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2차원 배열 &lt;code&gt;int graph[100][100]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ArrayList&amp;lt;ArrayList&amp;lt;Integer&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int[][]&lt;/code&gt; 배열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;list of lists&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2차원 리스트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  그래프는 언제 쓰일까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;탐색 알고리즘 (BFS, DFS)&lt;/b&gt; 에 자주 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;경로 탐색 / 최단 거리 / 사이클 검출&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;예: 네비게이션, 추천 시스템, 의존성 그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 단독으로 잘 안 나오고, 대부분 &lt;b&gt;탐색 문제 (BFS/DFS)&lt;/b&gt;와 함께 등장&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.3.2 트리 (Tree)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 트리란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이클이 없는 연결 그래프이자, 하나의 루트에서 시작되는&lt;b&gt; 계층적 자료 구조&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 다음을 모두 만족해야 합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 정점이 하나의 루트로 연결&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사이클 없음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정점 수 = 간선 수 + 1&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  기본 용어 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;용어&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;루트 노드 (root)&lt;/td&gt;
&lt;td&gt;트리의 시작점, 최상위 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;부모 노드&lt;/td&gt;
&lt;td&gt;다른 노드를 직접 가리키는 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;자식 노드&lt;/td&gt;
&lt;td&gt;부모에게 연결된 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;리프 노드&lt;/td&gt;
&lt;td&gt;자식이 없는 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 노드&lt;/td&gt;
&lt;td&gt;자식이 있는 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서브트리&lt;/td&gt;
&lt;td&gt;특정 노드를 루트로 하는 부분 트리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  깊이, 높이, 레벨&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;깊이 (depth)&lt;/td&gt;
&lt;td&gt;루트에서 해당 노드까지의 거리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;높이 (height)&lt;/td&gt;
&lt;td&gt;해당 노드에서 가장 깊은 리프까지의 거리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;레벨&lt;/td&gt;
&lt;td&gt;같은 깊이의 노드 묶음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 5-15에서 레벨/깊이/높이를 시각적으로 정리하면 이해 쉬움&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  트리의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정점 V개 &amp;rarr; 간선 E = V - 1개&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 정점 간의 경로가 유일함&lt;/b&gt;&lt;br /&gt;(루트에서 어떤 노드로 가는 길은 단 하나)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순환 없음&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  이진 트리 (Binary Tree)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 노드가 최대 2개인 트리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이진 트리의 종류&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정 이진 트리 (full)&lt;/td&gt;
&lt;td&gt;모든 노드가 자식 0개 또는 2개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;완전 이진 트리 (complete)&lt;/td&gt;
&lt;td&gt;마지막 레벨을 제외하고 꽉 채움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포화 이진 트리 (perfect)&lt;/td&gt;
&lt;td&gt;모든 레벨이 완전히 채워짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;변질 이진 트리 (degenerate)&lt;/td&gt;
&lt;td&gt;한쪽 자식만 있는 선형 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;균형 이진 트리 (balanced)&lt;/td&gt;
&lt;td&gt;좌우 서브트리 높이 차이가 1 이하&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  이진 탐색 트리 (BST: Binary Search Tree)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정렬된 데이터&lt;/b&gt;를 효율적으로 &lt;b&gt;저장/탐색&lt;/b&gt;하기 위한 이진 트리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왼쪽 서브트리: 현재 노드보다 작은 값&lt;/li&gt;
&lt;li&gt;오른쪽 서브트리: 현재 노드보다 큰 값&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;BST 시간 복잡도&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;평균&lt;/th&gt;
&lt;th&gt;최악&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(n) &amp;larr; 선형 트리 될 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최악의 경우는 정렬된 순서로 노드가 삽입될 때 (&amp;rarr; Linked List처럼 됨)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⚖️ 균형 이진 탐색 트리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬된 데이터를 넣었을 때 &lt;b&gt;한쪽으로 치우치지 않도록 자동으로 균형을 맞춰줌&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ AVL 트리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 노드의 좌우 서브트리 높이 차이가 &lt;b&gt;1 이하&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;삽입/삭제 시 &lt;b&gt;회전 연산으로 균형 조정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 레드-블랙 트리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 노드에 &lt;b&gt;색상(빨강/검정)&lt;/b&gt; 부여&lt;/li&gt;
&lt;li&gt;5가지 규칙으로 트리의 균형을 유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;균형 조건은 느슨하지만, 수행 속도가 빠름&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;비교&lt;/th&gt;
&lt;th&gt;AVL&lt;/th&gt;
&lt;th&gt;레드-블랙&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;회전 횟수&lt;/td&gt;
&lt;td&gt;더 많음&lt;/td&gt;
&lt;td&gt;더 적음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;균형 정도&lt;/td&gt;
&lt;td&gt;더 엄격&lt;/td&gt;
&lt;td&gt;덜 엄격&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;성능&lt;/td&gt;
&lt;td&gt;탐색 빠름&lt;/td&gt;
&lt;td&gt;삽입/삭제 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[더보기]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;노드에 색상(빨강/검정) 부여&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레드-블랙 트리에서 빨강/검정 색상은 추상적인 규칙을 시각적으로 표현한 메커니즘으로, &lt;br /&gt;트리의 구조적 균형을 강제하는 알고리즘의 핵심
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;빨강 노드: &quot;이 노드가 삽입/삭제로 인해 균형이 깨질 수 있음&quot;을 표시&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검정 노드: &quot;이 노드 주변의 균형이 안정적임&quot;을 표시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;색상 조합이 규칙을 위반하면(예: 빨강 노드 연속 발생), 회전(rebalancing) 또는 재색상(recoloring) 연산이 자동으로 트리거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;5가지 규칙으로 균형 유지&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;u&gt;모든 노드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;빨간색 또는 검은색이다.&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레드-블랙 트리에서 노드에 빨강/검정 색을 부여하는 가장 큰 목적은 트리의 균형을 자동으로 유지하기 위함&lt;/li&gt;
&lt;li&gt;빨강/검정 규칙 덕분에 트리의 한쪽으로 치우침(최악의 경우 linked list화)을 막아, 트리 높이가 항상 O(log n)에 머물게&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;루트&lt;span&gt;&amp;nbsp;&lt;/span&gt;노드는 항상&lt;span&gt;&amp;nbsp;&lt;/span&gt;검은색이다.&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;모든&lt;span&gt;&amp;nbsp;&lt;/span&gt;NIL&lt;span&gt;&amp;nbsp;&lt;/span&gt;리프 노드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;검은색이다.&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NIL = 아무 값도 없는(비어있는) 검정색 노드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;빨간색&lt;span&gt;&amp;nbsp;&lt;/span&gt;노드의&lt;span&gt;&amp;nbsp;&lt;/span&gt;자식은 모두&lt;span&gt;&amp;nbsp;&lt;/span&gt;검은색이다. (빨간색 노드는 연속될 수 없다)&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;루트 노드에서 모든 리프 노드까지의 경로에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;검은색&lt;span&gt;&amp;nbsp;&lt;/span&gt;노드의 개수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;같다&lt;/u&gt;.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 규칙은 &lt;b&gt;검정 높이(black height)&lt;/b&gt; 개념으로 표현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검정 높이 = 특정 노드에서 리프까지 경로의 검정색 노드 수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;모든 서브트리에서 &lt;b&gt;검정 높이가 일정하게 유지&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: 루트 노드에서 리프까지 경로에 검정 노드가 3개라면, 다른 모든 경로에서도 검정 노드는 3개여야&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  트리는 언제 사용할까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;계층적 데이터 표현&lt;/b&gt;: 파일 시스템, 조직도&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐색 최적화&lt;/b&gt;: 이진 탐색 트리, 맵/셋 구현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문법 분석&lt;/b&gt;: 파싱 트리, 표현식 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 정말 중요하고 자주 쓰이니, 이진 탐색 트리(BST), AVL, 레드블랙트리는 특히 시간 복잡도와 구조 꼭 숙지하자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;⛰️ 5.3.3 힙 (Heap)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 힙이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 다뤘던 트리의 연장선상에 있지만, 힙은 &lt;b&gt;우선순위에 따라 정렬된 특수한 완전 이진 트리&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전 이진 트리 형태를 가지면서,&lt;br /&gt;부모 노드가 자식 노드보다 항상 크거나 작아야 하는 자료 구조&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 구조는 트리지만, 동작은 &lt;b&gt;우선순위 큐(Priority Queue)&lt;/b&gt; 를 위한 용도에 최적화돼 있음.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  힙의 종류&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;루트 노드 특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;최대 힙 (Max Heap)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;부모 &amp;ge; 자식&lt;/td&gt;
&lt;td&gt;루트 = 가장 큰 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;최소 힙 (Min Heap)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;부모 &amp;le; 자식&lt;/td&gt;
&lt;td&gt;루트 = 가장 작은 값&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  힙의 특징&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;완전 이진 트리&lt;/b&gt;&lt;br /&gt;&amp;rarr; 마지막 레벨을 제외하고 왼쪽부터 빈틈없이 채워짐&lt;br /&gt;(배열로 구현하기 딱 좋음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정렬된 트리가 아님&lt;/b&gt;&lt;br /&gt;&amp;rarr; 왼쪽/오른쪽 간 대소관계는 중요하지 않음&lt;br /&gt;&amp;rarr; &lt;b&gt;항상 부모와 자식 간의 우선순위만 보장&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;삽입 (&lt;code&gt;push&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;마지막에 추가 후 위로 정렬 (heapify-up)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제 (&lt;code&gt;pop&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;루트 제거 후 마지막 노드를 루트로, 아래로 정렬 (heapify-down)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최대/최소 확인&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;루트만 보면 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 예시 (기본은 &lt;b&gt;최소 힙&lt;/b&gt;)&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import heapq

heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 3)
heapq.heappush(heap, 8)

print(heapq.heappop(heap))  # 3 (가장 작은 값)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❗ 최대 힙 사용하려면?&lt;/h3&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;heapq.heappush(heap, -5)  # 음수로 변환
max_val = -heapq.heappop(heap)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C++ 예시 (&lt;code&gt;priority_queue&lt;/code&gt;)&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;

int main() {
    priority_queue&amp;lt;int&amp;gt; maxHeap; // 최대 힙

    maxHeap.push(3);
    maxHeap.push(5);
    maxHeap.push(1);

    cout &amp;lt;&amp;lt; maxHeap.top(); // 5
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최소 힙 만들기&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;priority_queue&amp;lt;int, vector&amp;lt;int&amp;gt;, greater&amp;lt;int&amp;gt;&amp;gt; minHeap;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java 예시 (&lt;code&gt;PriorityQueue&lt;/code&gt;)&lt;/h2&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;import java.util.*;

public class Main {
    public static void main(String[] args) {
        PriorityQueue&amp;lt;Integer&amp;gt; minHeap = new PriorityQueue&amp;lt;&amp;gt;();

        minHeap.add(5);
        minHeap.add(3);
        minHeap.add(8);

        System.out.println(minHeap.poll());  // 3
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최대 힙 만들기&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;Integer&amp;gt; maxHeap = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  언제 쓰나?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;우선순위가 있는 작업 관리&lt;/b&gt;: CPU 스케줄러, 작업 큐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최소/최대 값 빠르게 꺼내기&lt;/b&gt;: Top-K 문제, 다익스트라 알고리즘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정렬 알고리즘&lt;/b&gt;: 힙 정렬 (Heap Sort)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬이 필요한 상황에서 항상 전체를 정렬할 필요는 &lt;b&gt;없음&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;&lt;i&gt;예: 가장 큰 값 3개만 꺼낼 때 &amp;rarr; 정렬보다 힙이 훨씬 빠름&lt;/i&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.3.4 우선순위 큐 (Priority Queue)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 우선순위 큐란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙이랑 거의 세트로 다뤄지는 자료구조&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 큐(FIFO)와 달리,&lt;br /&gt;&lt;b&gt;우선순위가 높은 요소가 먼저 나가는 큐&lt;/b&gt;입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삽입된 순서가 아니라 &lt;b&gt;우선순위 값(priority)&lt;/b&gt; 기준으로 처리&lt;/li&gt;
&lt;li&gt;내부적으로는 보통 &lt;b&gt;힙(Heap)&lt;/b&gt; 자료구조로 구현됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  일반 큐 vs 우선순위 큐&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;일반 큐&lt;/th&gt;
&lt;th&gt;우선순위 큐&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;처리 순서&lt;/td&gt;
&lt;td&gt;들어온 순서대로&lt;/td&gt;
&lt;td&gt;우선순위 높은 것부터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;구현 구조&lt;/td&gt;
&lt;td&gt;배열, 리스트&lt;/td&gt;
&lt;td&gt;힙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용 목적&lt;/td&gt;
&lt;td&gt;순차 처리&lt;/td&gt;
&lt;td&gt;긴급도/중요도 반영&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도 (힙 기반일 경우)&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;힙에 추가 후 정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제 (최고 우선순위)&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;루트 제거 후 재정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최고 우선순위 조회&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;루트 노드 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 우선순위 큐 예시&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;import heapq

# 빈 힙(우선순위 큐) 생성 - 최소 힙이 기본
pq = []

# (우선순위, 작업 내용) 튜플을 push
heapq.heappush(pq, (2, '코딩'))   # 우선순위 2
heapq.heappush(pq, (1, '점심'))   # 우선순위 1 (더 먼저 처리됨)
heapq.heappush(pq, (3, '운동'))   # 우선순위 3

# 우선순위가 낮은 숫자부터 pop됨
while pq:
    priority, task = heapq.heappop(pq)  # 가장 낮은 우선순위 튜플 꺼냄
    print(f&quot;[우선순위 {priority}] {task}&quot;)

&quot;&quot;&quot;
[우선순위 1] 점심
[우선순위 2] 코딩
[우선순위 3] 운동
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(우선순위, 값) 형태로 넣어야 함&lt;br /&gt;기본은 최소 힙, 낮은 숫자가 우선&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  C++ &lt;code&gt;priority_queue&lt;/code&gt; 예시&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;queue&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;

int main() {
    // 기본 priority_queue는 최대 힙: 큰 값부터 먼저 나옴
    priority_queue&amp;lt;pair&amp;lt;int, string&amp;gt;&amp;gt; pq;

    // (우선순위, 작업 내용) 삽입
    pq.push({2, &quot;코딩&quot;});
    pq.push({1, &quot;점심&quot;});
    pq.push({3, &quot;운동&quot;});

    // 우선순위가 높은 값(숫자 큰 값)부터 나옴
    while (!pq.empty()) {
        cout &amp;lt;&amp;lt; &quot;[우선순위 &quot; &amp;lt;&amp;lt; pq.top().first &amp;lt;&amp;lt; &quot;] &quot; &amp;lt;&amp;lt; pq.top().second &amp;lt;&amp;lt; '\n';
        pq.pop();  // 하나 꺼냄
    }
}
/*
[우선순위 3] 운동
[우선순위 2] 코딩
[우선순위 1] 점심
*/&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본은 최대 힙 &amp;rarr; 우선순위 높은 숫자부터 나감&lt;br /&gt;greater&amp;lt;&amp;gt;를 써서 최소 힙으로도 만들 수 있음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Java &lt;code&gt;PriorityQueue&lt;/code&gt; 예시&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.*;

public class Main {
    public static void main(String[] args) {
        // PriorityQueue는 기본적으로 낮은 숫자가 높은 우선순위 (최소 힙)
        PriorityQueue&amp;lt;Task&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();

        pq.add(new Task(2, &quot;코딩&quot;));   // 우선순위 2
        pq.add(new Task(1, &quot;점심&quot;));   // 우선순위 1
        pq.add(new Task(3, &quot;운동&quot;));   // 우선순위 3

        while (!pq.isEmpty()) {
            System.out.println(pq.poll().name); // 우선순위 낮은 숫자부터 poll()
        }
    }
}

// 우선순위 비교를 위한 Comparable 구현
class Task implements Comparable&amp;lt;Task&amp;gt; {
    int priority;
    String name;

    Task(int p, String n) {
        priority = p;
        name = n;
    }

    // 우선순위 기준: 숫자가 작을수록 높은 우선순위
    public int compareTo(Task o) {
        return this.priority - o.priority;
    }
}
/*
점심
코딩
운동
*/&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Comparable&lt;/i&gt;: 어떤 클래스의 객체들끼리 서로 비교할 수 있도록 만들어주는 Java의 인터페이스&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PriorityQueue나 Collections.sort() 같은 정렬 관련 기능들은 &amp;ldquo;어떤 기준으로 비교해서 정렬할지&amp;rdquo; 알아야 함.&lt;/li&gt;
&lt;li&gt;int, String 등은 이미 정해진 기준이 있지만, 사용자 정의 클래스에서는 직접 비교 기준을 정해줘야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  언제 사용할까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시스템 작업 스케줄링&lt;/b&gt; (OS의 Job Queue)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다익스트라 알고리즘&lt;/b&gt; (최단 경로)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;A* 탐색 알고리즘(A-star Search)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 패킷 처리 / 인터럽트 처리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 요약: 우선순위 큐는 힙을 추상화한 개념. &lt;br /&gt;&lt;br /&gt;&lt;i&gt;그냥 &quot;우선순위 있는 대기열&quot;이 필요하다? &amp;rarr; 바로 Priority Queue 사용&lt;/i&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.3.5 맵 (Map)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 맵이란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키-값 쌍 (Key-Value Pair)&lt;/b&gt; 형태로 데이터를 저장하는 자료구조&lt;br /&gt;&amp;rarr; &lt;b&gt;특정 키를 통해 값을 빠르게 찾아낼 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
    &quot;이름&quot;: &quot;리쿠&quot;,
    &quot;나이&quot;: 21
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  맵의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;키는 유일(unique)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;값은 중복 가능&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;검색, 삽입, 삭제 모두 빠름 (Hash 기반일 경우 O(1), 트리 기반일 경우 O(log n))&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  구현 방식별 특징&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료구조&lt;/th&gt;
&lt;th&gt;기반 구조&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;th&gt;정렬 여부&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;map&lt;/code&gt; (C++/Java)&lt;/td&gt;
&lt;td&gt;이진 탐색 트리&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;키 기준 정렬됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unordered_map&lt;/code&gt; / &lt;code&gt;HashMap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;해시 테이블&lt;/td&gt;
&lt;td&gt;O(1) 평균 / O(n) 최악&lt;/td&gt;
&lt;td&gt;정렬되지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;&lt;code&gt;map&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;unordered_map&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(1) 평균&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(1) 평균&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;O(1) 평균&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  언어별 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python &lt;code&gt;dict&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;info = {&quot;name&quot;: &quot;Riku&quot;, &quot;age&quot;: 22}
print(info[&quot;name&quot;])  # &quot;Riku&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;C++ &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;unordered_map&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;map&amp;lt;string, int&amp;gt; m;
m[&quot;apple&quot;] = 3;
cout &amp;lt;&amp;lt; m[&quot;apple&quot;];  // 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;unordered_map&amp;lt;string, int&amp;gt; um;
um[&quot;apple&quot;] = 3;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Java &lt;code&gt;HashMap&lt;/code&gt;, &lt;code&gt;TreeMap&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;Map&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
map.put(&quot;apple&quot;, 3);
System.out.println(map.get(&quot;apple&quot;));  // 3&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.3.6 셋 (Set)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 셋이란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복을 허용하지 &lt;b&gt;않는&lt;/b&gt; 데이터의 집합&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 값만 저장 (&lt;b&gt;key만 있음&lt;/b&gt;, value는 없음)&lt;/li&gt;
&lt;li&gt;주로 &lt;b&gt;빠른 존재 여부 확인&lt;/b&gt;(membership test)에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Set의 종류&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료구조&lt;/th&gt;
&lt;th&gt;기반 구조&lt;/th&gt;
&lt;th&gt;정렬&lt;/th&gt;
&lt;th&gt;시간 복잡도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set&lt;/code&gt; (C++/Java)&lt;/td&gt;
&lt;td&gt;이진 탐색 트리&lt;/td&gt;
&lt;td&gt;O(log n)&lt;/td&gt;
&lt;td&gt;정렬 O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unordered_set&lt;/code&gt; / &lt;code&gt;HashSet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;해시 테이블&lt;/td&gt;
&lt;td&gt;O(1) 평균&lt;/td&gt;
&lt;td&gt;정렬 X&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python &lt;code&gt;set&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;s = {&quot;apple&quot;, &quot;banana&quot;}
s.add(&quot;cherry&quot;)
print(&quot;banana&quot; in s)  # True&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;C++ &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;unordered_set&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;set&amp;lt;int&amp;gt; s;
s.insert(10);
s.insert(20);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Java &lt;code&gt;HashSet&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Set&amp;lt;String&amp;gt; s = new HashSet&amp;lt;&amp;gt;();
s.add(&quot;apple&quot;);
s.contains(&quot;apple&quot;); // true&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  5.3.7 해시 테이블 (Hash Table)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 해시 테이블이란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 &lt;b&gt;해시 함수&lt;/b&gt;를 통해 &lt;b&gt;고정된 인덱스 공간&lt;/b&gt;에 저장하는 구조&lt;br /&gt;&amp;rarr; &lt;b&gt;평균 O(1)의 빠른 검색/삽입/삭제 가능&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구성 요소&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;해시 함수&lt;/b&gt;: 키 &amp;rarr; 해시값(정수) 변환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버킷(bucket)&lt;/b&gt;: 데이터를 저장할 인덱스 공간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;충돌 해결 로직&lt;/b&gt;: 같은 해시값에 여러 데이터가 맵핑될 경우를 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  충돌 해결 방법&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;체이닝 (Chaining)&lt;/td&gt;
&lt;td&gt;같은 해시값에 연결 리스트로 저장&lt;/td&gt;
&lt;td&gt;구현 쉬움, 공간 추가 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;개방 주소법 (Open Addressing)&lt;/td&gt;
&lt;td&gt;비어 있는 다음 슬롯 찾음&lt;/td&gt;
&lt;td&gt;메모리 효율적, 클러스터링 문제 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  해시 함수 충돌 예시 (비둘기집 원리)&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;hash(&quot;hello&quot;) &amp;rarr; 42
hash(&quot;world&quot;) &amp;rarr; 42&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 서로 다른 입력이 동일한 인덱스로 매핑되는 현상 = 충돌&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱️ 시간 복잡도&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;평균&lt;/th&gt;
&lt;th&gt;최악&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최악의 경우는 모든 키가 같은 해시값을 가질 때&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  핵심 비교 요약&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료구조&lt;/th&gt;
&lt;th&gt;기반&lt;/th&gt;
&lt;th&gt;키-값 쌍&lt;/th&gt;
&lt;th&gt;중복&lt;/th&gt;
&lt;th&gt;정렬&lt;/th&gt;
&lt;th&gt;대표 연산&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Map&lt;/td&gt;
&lt;td&gt;트리 / 해시&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;키 중복 X&lt;/td&gt;
&lt;td&gt;트리: O, 해시: X&lt;/td&gt;
&lt;td&gt;get(key), put(key, value)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;트리 / 해시&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;값 중복 X&lt;/td&gt;
&lt;td&gt;트리: O, 해시: X&lt;/td&gt;
&lt;td&gt;contains(value), add(value)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash Table&lt;/td&gt;
&lt;td&gt;해시&lt;/td&gt;
&lt;td&gt;일반 구조&lt;/td&gt;
&lt;td&gt;충돌 관리&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;빠른 검색&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 단순히 외워야 하는 목록이 아니라, &lt;br /&gt;&lt;br /&gt;&lt;b&gt;어떤 문제에 어떤 구조를 써야 할지 판단하는 사고 방식&lt;/b&gt;입니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 정리를 통해 각 자료구조의 목적과 특징, 시간 복잡도까지 흐름을 잡는다면 &lt;br /&gt;&lt;br /&gt;실제 프로젝트나 알고리즘 문제를 만났을 때&lt;br /&gt;&lt;b&gt;&amp;ldquo;왜 이 구조를 써야 하는가&amp;rdquo;&lt;/b&gt; 라는 질문에&lt;br /&gt;스스로 답할 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로는 문제를 풀기 전에 이렇게 생각해봅시다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이 데이터, 어떻게 저장하고 꺼내는 게 가장 효율적일까?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  함께 보면 좋은 참고자료&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  시각화 도구&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://visualgo.net/ko&quot;&gt;VisuAlgo &amp;ndash; 자료구조 시각화&lt;/a&gt;&lt;br /&gt;자료구조와 알고리즘의 동작 과정을 단계별로 시각화해서 보여주는 사이트 (한글 지원)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cs.usfca.edu/~galles/visualization/Algorithms.html&quot;&gt;Data Structure Visualization - Computer Science&lt;/a&gt;&lt;br /&gt;스택/큐/힙/트리 등 동작 시각화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  읽을거리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://book.naver.com/bookdb/book_detail.nhn?bid=16367753&quot;&gt;『이것이 취업을 위한 코딩 테스트다』 &amp;ndash; 나동빈 저&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[『면접을 위한 CS 전공지식 노트』 &amp;ndash; 주홍철 저]&lt;br /&gt;이 블로그 정리의 기반이 된 책. 기초 CS 개념과 면접 대비용 정리로 유용함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>DSA</category>
      <category>datastructure</category>
      <category>DSA</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/49</guid>
      <comments>https://readyoun.tistory.com/49#entry49comment</comments>
      <pubDate>Mon, 19 May 2025 21:27:29 +0900</pubDate>
    </item>
    <item>
      <title>샤딩 vs 파티셔닝, 무엇을 언제 선택해야 할까? &amp;ndash; 데이터 분산 전략</title>
      <link>https://readyoun.tistory.com/48</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝과 샤딩은 단순한 성능 향상을 위한 기술이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 두 전략의 개념과 차이를 명확히 구분하고,&lt;br /&gt;Airbyte, LINE 등 실무 사례를 통해 실제 기업들이 왜 각각의 전략을 선택했는지를 살펴봅니다.&lt;br /&gt;마지막엔 분산 전략을 선택할 때 고려해야 할 판단 기준도 함께 정리했습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 분산 저장이 필요한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스가 성장하면서 점점 더 많은 사용자 요청과 데이터가 쌓이게 됩니다. 이때 &lt;b&gt;단일 DB 인스턴스&lt;/b&gt;에 모든 데이터를 저장하고 조회하려고 하면 시스템이 감당하지 못하고 &lt;b&gt;병목이 발생하게 됩니다&lt;/b&gt;. 그 병목은 성능 저하뿐 아니라, 운영 이슈, 데이터 정합성 문제로 이어질 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 섹션에서는 &lt;u&gt;왜 데이터를 분산시켜야 하는지&lt;/u&gt; 근본적인 이유부터 살펴봅니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  문제 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 이용자가 늘어나면, 데이터도 기하급수적으로 증가합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lrK3m/btsNex9TbWI/qsUDBWKBvTmu9sBt4G4cyK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lrK3m/btsNex9TbWI/qsUDBWKBvTmu9sBt4G4cyK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lrK3m/btsNex9TbWI/qsUDBWKBvTmu9sBt4G4cyK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlrK3m%2FbtsNex9TbWI%2FqsUDBWKBvTmu9sBt4G4cyK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;521&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;(출처:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: center;&quot; href=&quot;https://www.simform.com/blog/database-devops&quot;&gt;simform&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;단일 테이블(또는 DB 인스턴스)에서 모든 데이터를 처리하면 다음과 같은 병목이 발생합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;I/O 병목&lt;/li&gt;
&lt;li&gt;인덱스 비대화&lt;/li&gt;
&lt;li&gt;데이터 락 충돌&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  [더보기] I/O 병목, 인덱스 비대화, 데이터 락 충돌이란?&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;I/O 병목&lt;/b&gt;: 데이터가 많아지면 디스크에서 읽고 쓰는 속도가 느려짐 &amp;rarr; 처리 속도 급격히 하락함&lt;br /&gt;&lt;b&gt;인덱스 비대화&lt;/b&gt;: 인덱스가 커지면 B-Tree 탐색 비용 증가, CPU 캐시 미스 증가 &amp;rarr; 오히려 성능 저하&lt;br /&gt;&lt;b&gt;데이터 락 충돌&lt;/b&gt;: 동시성 트랜잭션이 많아질수록 row-level, table-level 락 충돌이 발생 &amp;rarr; 대기/충돌 증가&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  [더보기] 데이터 분산 외 성능 최적화 전략은 뭐가 있을까?&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;읽기/쓰기 분리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Master-Slave 구조에서 쓰기는 Master, 읽기는 Read Replica로 분산 &amp;rarr; 읽기 부하 분산&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시 계층 도입&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redis, Memcached 등으로 자주 쓰는 데이터는 메모리에서 빠르게 응답 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CQRS 패턴&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰기 연산과 읽기 연산을 분리해 각각 다른 저장소나 처리 흐름 사용 &amp;rarr; 동시성 분리 효과&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 파티셔닝이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 데이터를 다루는 테이블에서는 단순한 인덱스 추가나 쿼리 튜닝만으로는 성능 개선이 한계에 부딪힙니다. 이때 활용할 수 있는 전략이 바로 &lt;b&gt;파티셔닝(Partitioning)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝은 &lt;u&gt;하나의 큰 테이블을 여러 개의 작은 단위로 나누어, 마치 독립적인 테이블처럼 관리할 수 있도록 해주는 기술&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 쿼리 성능 향상, 관리 효율성 증대, 아카이빙 자동화 등 다양한 측면에서 효과를 발휘합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  개념부터 짚고 가기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;논리적으로는 하나의 테이블이지만&lt;/b&gt;, 내부적으로는 여러 개의 파티션(partition)으로 구성되어 있음&lt;/li&gt;
&lt;li&gt;각 파티션은 물리적으로는 별도의 저장 단위로 취급될 수 있으며, 조건에 따라 개별 접근 가능&lt;/li&gt;
&lt;li&gt;DBMS가 파티션을 인식하고, 특정 조건에 따라 일부 파티션만 조회하는 &lt;b&gt;최적화(Partition Pruning, 쿼리&amp;nbsp;시&amp;nbsp;필요한&amp;nbsp;파티션만&amp;nbsp;선택해서&amp;nbsp;읽는&amp;nbsp;동작)&lt;/b&gt;를 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;파티셔닝을 &lt;b&gt;왜&lt;/b&gt; 사용하는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝은 단순한 성능 개선이 목적이 아닙니다.&lt;br /&gt;데이터가 많아질수록 관리 측면에서의 이점이 훨씬 커집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 향상&lt;/b&gt;: 조건 검색 시 불필요한 데이터 스캔 방지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보관/삭제 용이&lt;/b&gt;: 오래된 파티션만 DROP 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관리 단순화&lt;/b&gt;: 파티션 단위 백업/복구, 통계 수집 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 분리 처리&lt;/b&gt;: 파티션별 병렬처리, 스케줄 관리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  수평 vs 수직 파티셔닝&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce48nE/btsNcqY4kIN/FZKFQnkxpDyANaaw5PbSik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce48nE/btsNcqY4kIN/FZKFQnkxpDyANaaw5PbSik/img.png&quot; data-alt=&quot;horizontal&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce48nE/btsNcqY4kIN/FZKFQnkxpDyANaaw5PbSik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce48nE%2FbtsNcqY4kIN%2FFZKFQnkxpDyANaaw5PbSik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;469&quot; height=&quot;188&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;horizontal&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAVR1O/btsNdIR5pUH/kpl2rluu0OccnfFjx9o480/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAVR1O/btsNdIR5pUH/kpl2rluu0OccnfFjx9o480/img.png&quot; data-alt=&quot;vertical&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAVR1O/btsNdIR5pUH/kpl2rluu0OccnfFjx9o480/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAVR1O%2FbtsNdIR5pUH%2Fkpl2rluu0OccnfFjx9o480%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;230&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vertical&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;(출처: &lt;a href=&quot;https://www.sqlshack.com/sql-server-partitioning-types/&quot;&gt;SQLShack&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝은 크게 &lt;b&gt;행 기준 수평 분할&lt;/b&gt;과 &lt;b&gt;열 기준 수직 분할&lt;/b&gt;로 나뉩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;하지만 실무에서는 대부분 &lt;b&gt;수평 파티셔닝&lt;/b&gt;이 사용됩니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;수평 파티셔닝&lt;/th&gt;
&lt;th&gt;수직 파티셔닝&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;기준&lt;/td&gt;
&lt;td&gt;Row 기준&lt;/td&gt;
&lt;td&gt;Column 기준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;td&gt;가입 연도별 회원 나누기&lt;/td&gt;
&lt;td&gt;개인정보 / 활동 로그 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;쿼리 범위 축소&lt;/td&gt;
&lt;td&gt;보안, 분리 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;td&gt;파티션 수 증가 시 관리 부담&lt;/td&gt;
&lt;td&gt;JOIN 필요성 증가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  [더보기] 수직 파티셔닝은 왜 잘 안 쓰이는가?&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수직 파티셔닝은 &lt;b&gt;JOIN 비용&lt;/b&gt; 증가와 &lt;b&gt;컬럼 선택성 저하&lt;/b&gt; 등으로 인해 잘 쓰이지 않습니다.&lt;br /&gt;대부분의 쿼리가 &lt;code&gt;SELECT *&lt;/code&gt; 구조를 가질 경우, 분리된 테이블을 다시 조인해야 하며,&lt;br /&gt;이로 인해 오히려 성능이 악화되는 경우도 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  파티션 방식: 어떤 기준으로 나눌까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝은 데이터를 나누는 방식에 따라 아래와 같이 구분됩니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;기준 예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;특징 및 장단점&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;범위(RANGE)&lt;/td&gt;
&lt;td&gt;가입일 기준&lt;/td&gt;
&lt;td&gt;시간순 데이터 분할에 적합, 직관적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목록(LIST)&lt;/td&gt;
&lt;td&gt;지역 코드&lt;/td&gt;
&lt;td&gt;정해진 카테고리 그룹화에 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해시(HASH)&lt;/td&gt;
&lt;td&gt;해시 함수&lt;/td&gt;
&lt;td&gt;균등 분산에 유리, 범위 쿼리에 부적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;키(KEY)&lt;/td&gt;
&lt;td&gt;PK 또는 유니크 키&lt;/td&gt;
&lt;td&gt;DBMS가 내부적으로 HASH와 유사 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  [더보기] 파티션과 인덱스는 어떻게 작동할까?&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝이 적용된 테이블에서 인덱스를 사용하려면 &lt;b&gt;조건절이 파티션 키를 포함해야 합니다.&lt;/b&gt;&lt;br /&gt;그렇지 않으면 파티션을 모두 스캔하는 Full Scan이 발생할 수 있습니다.&lt;/p&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;-- 파티션 키인 created_at이 조건에 포함된 경우
SELECT * FROM orders WHERE created_at &amp;gt;= '2024-01-01';

-- 파티션 키가 아닌 경우
SELECT * FROM orders WHERE user_id = 1001;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 Partition Pruning이 작동하려면 파티션 키와 쿼리 조건이 일치해야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 샤딩이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 사용자 트래픽과 급증하는 데이터 볼륨을 감당하기 위해, 단일 데이터베이스로는 더 이상 충분하지 않은 상황이 많아졌습니다. 이럴 때 사용하는 대표적인 분산 저장 방식이 바로 &lt;b&gt;샤딩(Sharding)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩은 하나의 데이터베이스 테이블이 아니라, &lt;b&gt;전체 DB를 여러 개로 나누어&lt;/b&gt; 데이터 부하를 분산시키는 구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 샤딩은 하나의 논리적 데이터셋을 여러 DB 인스턴스에 분산 저장해 &lt;b&gt;병렬성(Parallelism)&lt;/b&gt; 과 &lt;b&gt;확장성(Scalability)&lt;/b&gt; 을 확보하려는 목적을 갖습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 성능 개선뿐 아니라, 장애 격리, 글로벌 리전 운영 등의 장점을 가져올 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; ️ 샤딩의 기본 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩은 단순히 데이터를 나누는 것을 넘어, &lt;b&gt;어떻게 나눌지(Shard Key)&lt;/b&gt;, &lt;b&gt;어디에 저장할지(Shard)&lt;/b&gt;, &lt;b&gt;어떻게 보내고 조회할지(Router)&lt;/b&gt; 가 함께 설계되어야 합니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;구성 요소&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Shard&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터를 실제로 저장하는 DB 인스턴스 (물리적 분산 단위)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Shard Key&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터를 어떤 샤드로 보낼지 결정하는 기준 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Router&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;클라이언트의 쿼리를 알맞은 샤드로 라우팅해주는 계층 (앱/미들웨어/DB 자체)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: user_id를 기준으로 샤딩한다면, user_id % 3의 결과에 따라 3개의 샤드로 나뉘어 저장됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr1PM3/btsNeyAWjXf/GkDY8SMXAmcvLPKAagpnG0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr1PM3/btsNeyAWjXf/GkDY8SMXAmcvLPKAagpnG0/img.webp&quot; data-alt=&quot;routing via mongos&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr1PM3/btsNeyAWjXf/GkDY8SMXAmcvLPKAagpnG0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr1PM3%2FbtsNeyAWjXf%2FGkDY8SMXAmcvLPKAagpnG0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;540&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;routing via mongos&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;br /&gt;(출처: &lt;a href=&quot;https://www.mongodb.com/docs/manual/core/sharded-cluster-components/&quot;&gt;MongoDB Docs&lt;/a&gt;)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  샤딩 전략 &amp;ndash; 데이터를 어떤 기준으로 나눌 것인가?&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6cRT1/btsNcuUHd1P/P8xjq76j2CR5Z2oAkmZL6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6cRT1/btsNcuUHd1P/P8xjq76j2CR5Z2oAkmZL6k/img.png&quot; data-alt=&quot;range-based ex&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6cRT1/btsNcuUHd1P/P8xjq76j2CR5Z2oAkmZL6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6cRT1%2FbtsNcuUHd1P%2FP8xjq76j2CR5Z2oAkmZL6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;range-based ex&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;(출처: &lt;a href=&quot;https://www.pingcap.com/blog/database-sharding-defined/&quot;&gt;TiDB Sharding Guide&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩은 &amp;ldquo;샤드 키를 기준으로 어떤 방식으로 데이터를 나눌지&amp;rdquo;에 따라 크게 4가지 전략으로 구분됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;각 전략은 균등성, 확장성, 유연성 측면에서 트레이드오프가 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;전략&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;기준&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Range-based&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;키의 범위&lt;/td&gt;
&lt;td&gt;설계 간단, 직관적&lt;/td&gt;
&lt;td&gt;Hotspot 위험&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user_id 1~1000 &amp;rarr; A&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Key-based (Hash)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;해시 함수&lt;/td&gt;
&lt;td&gt;균등 분산&lt;/td&gt;
&lt;td&gt;샤드 추가 어려움&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hash(user_id) % N&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Directory-based&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;매핑 테이블&lt;/td&gt;
&lt;td&gt;유연함, 동적 구성 가능&lt;/td&gt;
&lt;td&gt;매핑 테이블 관리 필요&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lookup(user_id)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Geographic-based&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;사용자 위치 등 지역&lt;/td&gt;
&lt;td&gt;지연 최소화, 규제 대응&lt;/td&gt;
&lt;td&gt;글로벌 동기화 어려움&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EU &amp;rarr; Shard_EU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;    [더보기] 샤딩은 어디서 처리하는가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩은 그 로직을 &lt;b&gt;어디에서 처리하느냐에 따라&lt;/b&gt; 다음과 같이 나뉘며, 시스템 설계에 큰 영향을 줍니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;애플리케이션 레벨&lt;/b&gt;: 개발자가 직접 샤딩 로직 작성 (가장 유연하지만 복잡도 &amp;uarr;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DBMS 레벨&lt;/b&gt;: MongoDB, Citus처럼 DB 자체에서 샤딩 처리 지원&lt;/li&gt;
&lt;li&gt;&lt;b&gt;미들웨어 레벨&lt;/b&gt;: ProxySQL, mongos 등 중간 계층에서 라우팅 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구현 위치에 따라 장애 대응, 확장성, 개발 난이도가 달라지므로 사전 검토가 필수입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cp6jnZ/btsNdLHYILp/k1FuyVPKXMicqIuCOWZXGK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cp6jnZ/btsNdLHYILp/k1FuyVPKXMicqIuCOWZXGK/img.webp&quot; data-alt=&quot;application level sharding - 앱에서 샤드 키 기준으로 분기 처리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cp6jnZ/btsNdLHYILp/k1FuyVPKXMicqIuCOWZXGK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcp6jnZ%2FbtsNdLHYILp%2Fk1FuyVPKXMicqIuCOWZXGK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;548&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;application level sharding - 앱에서 샤드 키 기준으로 분기 처리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;출처: &lt;/span&gt;&lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; href=&quot;https://datageek.blog/2023/08/17/application-level-sharding/&quot;&gt;DataGeek.blog&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;    [더보기] 분산된 데이터를 어떻게 일관되게 다룰까?&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샤딩된 환경에서는 데이터가 여러 DB 인스턴스에 분산되어 저장되기 때문에,&lt;br /&gt;&lt;b&gt;어디서든 같은 데이터를 보고, 동일한 결과를 얻는 것이 어려워질 수 있습니다.&lt;/b&gt;&lt;br /&gt;이런 상황에서는 일관성을 직접 유지할 수 있는 전략적 설계가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;  일관성을 유지하기 위한 전략&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;전략&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;단점&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;2PC (Two-Phase Commit)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;두 단계로 Commit 전송&lt;/td&gt;
&lt;td&gt;강한 일관성&lt;/td&gt;
&lt;td&gt;락 오래 잡음, 실패 시 복잡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SAGA 패턴&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;보상 트랜잭션 기반 순차 처리&lt;/td&gt;
&lt;td&gt;마이크로서비스에 적합&lt;/td&gt;
&lt;td&gt;중간 실패 보상 로직 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Eventual Consistency&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;시간차 동기화 허용&lt;/td&gt;
&lt;td&gt;고가용성 확보&lt;/td&gt;
&lt;td&gt;중간 상태 노출 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;메시지 큐 기반 이벤트 처리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Kafka, RabbitMQ 등으로 분산 동기화&lt;/td&gt;
&lt;td&gt;비동기 처리 구성 가능&lt;/td&gt;
&lt;td&gt;재처리, 순서 보장 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;  파티셔닝과 비교하자면,&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;항목&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;파티셔닝&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;샤딩&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분산 범위&lt;/td&gt;
&lt;td&gt;단일 DB 내부&lt;/td&gt;
&lt;td&gt;여러 DB 인스턴스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일관성 유지&lt;/td&gt;
&lt;td&gt;DBMS가 자동 보장&lt;/td&gt;
&lt;td&gt;애플리케이션 또는 설계자가 직접 보장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;트랜잭션/제약 조건&lt;/td&gt;
&lt;td&gt;자유롭게 가능&lt;/td&gt;
&lt;td&gt;제약 있음, 직접 구현 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;파티셔닝은 &amp;ldquo;일관성 유지가 기본값&amp;rdquo;인 구조고,&lt;br /&gt;샤딩은 &amp;ldquo;일관성을 유지하기 위한 전략이 필요&amp;rdquo;한 구조입니다.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 파티셔닝 vs 샤딩 &amp;ndash; 핵심 비교 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝과 샤딩은 모두 데이터를 나눠서 처리 부하를 줄이고 성능을 개선하기 위한 전략이지만,&lt;br /&gt;&lt;b&gt;그 적용 범위와 목적, 설계 관점은 완전히 다릅니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0FC2P/btsNcTNxqNh/M3XwBvPnUKBLJjE6Hkoquk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0FC2P/btsNcTNxqNh/M3XwBvPnUKBLJjE6Hkoquk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0FC2P/btsNcTNxqNh/M3XwBvPnUKBLJjE6Hkoquk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0FC2P%2FbtsNcTNxqNh%2FM3XwBvPnUKBLJjE6Hkoquk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;(출처: &lt;a href=&quot;https://www.pingcap.com/blog/database-sharding-defined/&quot;&gt;PingCAP / TiDB Docs&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파티셔닝은 &lt;b&gt;DBMS 내부에서 하나의 테이블을 분할하는 방식&lt;/b&gt;으로,&lt;br /&gt;쿼리 성능을 향상시키고 관리 편의성을 높이는 데 초점을 맞춥니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 샤딩은 &lt;b&gt;전체 데이터베이스 인스턴스를 수평으로 분산시키는 구조적 설계&lt;/b&gt;로,&lt;br /&gt;서비스가 커지면서 생기는 트래픽과 저장소 확장의 한계를 넘어가기 위한 선택입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  개념 비교&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;파티셔닝&lt;/th&gt;
&lt;th&gt;샤딩&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정의&lt;/td&gt;
&lt;td&gt;테이블을 내부적으로 나누는 구조&lt;/td&gt;
&lt;td&gt;DB 인스턴스 자체를 수평 분산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;단위&lt;/td&gt;
&lt;td&gt;행(row), 열(column) 기준&lt;/td&gt;
&lt;td&gt;DB 또는 테이블 단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;쿼리 성능 최적화, 관리 효율화&lt;/td&gt;
&lt;td&gt;확장성 확보, 시스템 부하 분산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;적용 위치&lt;/td&gt;
&lt;td&gt;단일 DB 내부&lt;/td&gt;
&lt;td&gt;여러 DB 인스턴스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;트랜잭션, JOIN&lt;/td&gt;
&lt;td&gt;거의 모든 기능 지원&lt;/td&gt;
&lt;td&gt;제한적, 추가 설계 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정합성 / 일관성&lt;/td&gt;
&lt;td&gt;DBMS가 보장&lt;/td&gt;
&lt;td&gt;설계자가 직접 유지해야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  언제 파티셔닝을 고려할까?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단일 테이블이 너무 커서 쿼리가 느려진다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시간 순 데이터가 많아 오래된 데이터를 주기적으로 제거해야 한다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 조건(날짜, 지역 등)으로 자주 조회되는 쿼리가 있다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아직 단일 DB 인스턴스에서 충분히 운영 가능하다&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예시:&lt;br /&gt;월별 로그 데이터를 조회하는 서비스에서는 created_at을 기준으로 RANGE 파티셔닝을 적용하면&lt;br /&gt;오래된 데이터는 DROP으로 쉽게 제거하고, 최신 데이터만 빠르게 조회 가능해집니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  언제 샤딩을 고려할까?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 DB 인스턴스가 더 이상 감당할 수 없는 수준까지 데이터가 증가했다&lt;/li&gt;
&lt;li&gt;동시에 많은 사용자의 요청을 처리해야 한다&lt;/li&gt;
&lt;li&gt;글로벌 리전에 따라 데이터를 나눠야 한다&lt;/li&gt;
&lt;li&gt;서로 다른 데이터 도메인을 분리해서 관리하고 싶다 (ex. 고객 vs 주문)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;br /&gt;전 세계 유저를 보유한 소셜 플랫폼에서는 사용자 ID 기준으로 샤딩을 하면&lt;br /&gt;각 지역 사용자 데이터를 지역별 샤드에 분산시켜 &lt;br /&gt;빠른 응답 속도와 리전 내 저장을 동시에 달성할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⚖️ 함께 쓰는 경우도 많다!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 &lt;b&gt;파티셔닝과 샤딩을 혼합하여 사용하는 경우도 많습니다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;br /&gt;샤드 A &amp;rarr; 2023년 테이블 &amp;rarr; 월별 파티셔닝&lt;br /&gt;샤드 B &amp;rarr; 2024년 테이블 &amp;rarr; 월별 파티셔닝&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;샤딩은 저장소와 시스템 확장을 위한 구조&lt;/b&gt;이고,&lt;br /&gt;&lt;b&gt;파티셔닝은 각 샤드 내부에서 쿼리 성능을 높이기 위한 수단&lt;/b&gt;으로 함께 쓰이는 거죠.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실무 사례와 함께 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 기업들은 단순히 &quot;데이터가 많아졌기 때문&quot;이 아니라,&lt;br /&gt;&lt;b&gt;데이터의 특성, 사용 패턴, 시스템 구조&lt;/b&gt;를 종합적으로 고려해&lt;br /&gt;파티셔닝과 샤딩을 전략적으로 선택하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Airbyte, LINE 사례를 통해&lt;br /&gt;&lt;b&gt;어떤 상황에서 어떤 분산 전략이 선택되었고&lt;/b&gt;,&lt;br /&gt;&lt;b&gt;그로 인해 어떤 아키텍처 구조가 만들어졌는지&lt;/b&gt;를 살펴보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  Airbyte &amp;ndash; ETL(Extract &amp;rarr; Transform &amp;rarr; Load) 파이프라인에서의 파티셔닝 활용&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;단순한 쿼리 성능이 아니라, 병렬 처리와 증분 적재의 효율성을 높이기 위해 파티셔닝을 선택한 사례&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;*데이터 적재(Load): 외부에서 데이터를 끌어와서 데이터베이스에 저장하는 작업&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;*증분 적재(Incremental Load): 전체 데이터를 다시 넣는 게 아니라, &amp;ldquo;변경되거나 새로 추가된 데이터만&amp;rdquo; 적재하는 방식&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmuXG4/btsNdi65qN7/TqfoZTsoyKbNK4JwtNMTuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmuXG4/btsNdi65qN7/TqfoZTsoyKbNK4JwtNMTuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmuXG4/btsNdi65qN7/TqfoZTsoyKbNK4JwtNMTuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmuXG4%2FbtsNdi65qN7%2FTqfoZTsoyKbNK4JwtNMTuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;458&quot; height=&quot;800&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;(출처: &lt;a href=&quot;https://airbyte.com/data-engineering-resources/etl-architecture&quot;&gt;Airbyte&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://airbyte.com/data-engineering-resources/what-is-data-partitioning&quot;&gt;  원문 보기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Airbyte는 대규모 데이터를 처리하는 ETL 파이프라인 도구&lt;/b&gt;입니다.&lt;br /&gt;데이터를 끊임없이 추출, 변환, 적재해야 하는 환경에서 파티셔닝은 다음과 같은 효과를 가져왔습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;created_at&lt;/code&gt; 기준 RANGE 파티셔닝 &amp;rarr; &lt;b&gt;시간 단위로 데이터를 나누고 관리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;각 파티션을 &lt;b&gt;병렬로 처리&lt;/b&gt;하여 전체 작업 시간 단축&lt;/li&gt;
&lt;li&gt;특정 기간 데이터만 적재하는 &lt;b&gt;증분 로딩(incremental load)&lt;/b&gt; 구조와 매우 잘 어울림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 이처럼, &lt;b&gt;읽기 쿼리 최적화 외에도 데이터 적재 흐름에도 파티셔닝은 강력한 전략&lt;/b&gt;이 될 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  LINE &amp;ndash; LINE Manga의 샤딩 구조 설계&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;국내 대형 서비스에서 샤딩을 애플리케이션 단에서 직접 구현한 대표 사례&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://engineering.linecorp.com/ko/blog/line-manga-server-side&quot;&gt;  원문 보기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LINE Manga&lt;/b&gt;는 수많은 만화 콘텐츠와 사용자 트래픽을 처리하는 대형 서비스입니다.&lt;br /&gt;LINE은 다음과 같은 방식으로 샤딩을 도입했습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;manga_id&lt;/code&gt; 기준 Key-based Sharding &amp;rarr; 특정 작품 데이터가 한 샤드에 집중&lt;/li&gt;
&lt;li&gt;애플리케이션 레벨에서 라우팅 구현 &amp;rarr; &lt;code&gt;getShardKey(id)&lt;/code&gt; 함수로 직접 분산&lt;/li&gt;
&lt;li&gt;특정 샤드에 장애 발생 시, 비동기 큐를 활용한 &lt;b&gt;재시도 메커니즘&lt;/b&gt;도 함께 설계&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 이 사례는 단순한 샤딩이 아닌, &lt;b&gt;운영 장애 대응 + 샤드 로직 유연성 확보&lt;/b&gt;까지 함께 고려한 구조입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  LinkedIn 커뮤니티 &amp;ndash; 선택 기준 정리와 조언&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;정답을 알려주는 것이 아니라, 선택 기준을 어떻게 구성해야 하는지 알려주는 사례&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/advice/0/what-best-practices-data-sharding-partitioning&quot;&gt;  커뮤니티 조언 보기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedIn의 기술 커뮤니티에서는 다음과 같은 기준을 추천합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 인스턴스로 운영 가능하면 &lt;b&gt;파티셔닝을 먼저 고려&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;쿼리 패턴이 단일 키에 집중되어 있다면 샤딩이 더 효과적&lt;/li&gt;
&lt;li&gt;시스템 복잡도 vs 개발 효율 vs 확장성의 균형을 고려해야 함&lt;/li&gt;
&lt;li&gt;NoSQL에서는 파티셔닝과 샤딩이 &lt;b&gt;개념적으로 겹칠 수 있음&lt;/b&gt; (&amp;rarr; Mongo, Cassandra 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 이 조언은 실제 선택 상황에서 &amp;ldquo;무조건 이게 정답&amp;rdquo;이 아니라,&lt;br /&gt;&lt;b&gt;상황별 우선순위를 고려해야 한다&lt;/b&gt;는 점을 잘 알려줍니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  실무에서는 &quot;둘 중 무엇?&quot;보다&lt;br /&gt;&quot;언제, 어떻게 함께 쓸 것인가&quot;가 훨씬 더 중요한 질문일 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 마무리 &amp;ndash; 언제, 어떤 전략을 선택할 것인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 많아진다고 무조건 샤딩하거나, 느려진다고 무작정 파티셔닝을 하는 건 올바른 접근이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;파티셔닝과 샤딩은 각각의 목적과 효과가 다르며,&lt;br /&gt;&lt;b&gt;쿼리 패턴, 시스템 구조, 확장성 요구사항, 데이터 정합성/일관성 보장 수준&lt;/b&gt; 등을 함께 고려해 판단해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❓ 이런 질문부터 시작해보세요&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금 문제가 되는 건 &lt;b&gt;읽기 성능&lt;/b&gt;인가요, &lt;b&gt;쓰기 부하&lt;/b&gt;인가요?&lt;br /&gt;&amp;rarr; &lt;i&gt;읽기라면 파티셔닝, 쓰기 트래픽이면 샤딩&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;데이터 크기가 커졌나요, 트래픽(요청 수)이 많아졌나요?&lt;br /&gt;&amp;rarr; &lt;i&gt;데이터 크기엔 파티셔닝, 트래픽엔 샤딩&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;데이터는 &lt;b&gt;시간순&lt;/b&gt;으로 정리되나요? 주기적으로 &lt;b&gt;삭제&lt;/b&gt;되나요?&lt;br /&gt;&amp;rarr; &lt;i&gt;RANGE 파티셔닝 고려&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;시스템은 아직 단일 DB로 충분한가요?&lt;br /&gt;&amp;rarr; &lt;i&gt;충분하면 파티셔닝, 부족하면 샤딩&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;서로 다른 도메인을 물리적으로 나눌 필요가 있나요?&lt;br /&gt;&amp;rarr; &lt;i&gt;샤딩 or 기능적 샤딩 고려&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;모든 데이터가 &lt;b&gt;즉시 일관성을 유지해야 하나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;i&gt;그렇다면 파티셔닝, 약간의 지연 허용되면 샤딩 가능&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  선택 가이드: 언제 어떤 전략을?&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style10&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;상황&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;선택 전략&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;테이블 하나가 너무 커서 쿼리가 느려진다&lt;/td&gt;
&lt;td&gt;✅ 파티셔닝 (RANGE or LIST)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;날짜별/지역별로 자주 조회된다&lt;/td&gt;
&lt;td&gt;✅ 파티셔닝 (Partition Pruning 유도)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자가 수백만 명, 요청이 초당 수천 건 이상&lt;/td&gt;
&lt;td&gt;✅ 샤딩 (Key-based, Geo-based)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;글로벌 사용자 대상으로 리전 분산 필요&lt;/td&gt;
&lt;td&gt;✅ 샤딩 (Geo-based + App Routing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템을 수평 확장하고 싶다&lt;/td&gt;
&lt;td&gt;✅ 샤딩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터는 많지만 DB는 하나로 유지하고 싶다&lt;/td&gt;
&lt;td&gt;✅ 파티셔닝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;둘 다 필요하다&lt;/td&gt;
&lt;td&gt;✅ 혼합 전략 (샤딩 + 파티셔닝 병행)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  선택 기준 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작은 데이터지만 쿼리 최적화가 필요하다 &amp;rarr; 파티셔닝&lt;/li&gt;
&lt;li&gt;시스템 부하를 나눠야 한다 &amp;rarr; 샤딩&lt;/li&gt;
&lt;li&gt;성능 개선이 아니라 확장이 목적이다 &amp;rarr; 샤딩&lt;/li&gt;
&lt;li&gt;JOIN이 중요하고 정합성/일관성이 핵심이다 &amp;rarr; 파티셔닝&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  핵심은 '언제 어떤 전략을 도입해야 할까?'보다,&lt;br /&gt;'왜 이 전략이 필요한가'를 명확히 이해하는 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보면서 늘 그렇듯, 분산 전략은 단순한 기능이 아니라&lt;br /&gt;&lt;b&gt;서비스 성장 단계에서의 아키텍처 결정&lt;/b&gt;인 점을 배웠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ TL;DR&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파티셔닝은 단일 DB 안에서 테이블을 나누는 방식 (논리적 분산)&lt;/li&gt;
&lt;li&gt;샤딩은 DB 자체를 여러 개로 분산 저장하는 방식 (물리적 분산)&lt;/li&gt;
&lt;li&gt;파티셔닝은 관리와 성능, 샤딩은 확장성과 병렬성에 초점&lt;/li&gt;
&lt;li&gt;실무에서는 함께 쓰이기도 하고, 상황에 따라 선택 기준이 다름&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  참고자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Airbyte: &lt;a href=&quot;https://airbyte.com/data-engineering-resources/what-is-data-partitioning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What Is Data Partitioning: Types, Techniques, &amp;amp; Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LINE: &lt;a href=&quot;https://engineering.linecorp.com/ko/blog/line-manga-server-side&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LINE Manga 데이터베이스 샤딩 &amp;ndash; 서버 엔지니어 편&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href=&quot;https://www.linkedin.com/pulse/sharding-rdbms-vs-nosql-vagdevi-kommineni-wvehc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sharding in RDBMS vs NoSQL &amp;ndash; Vagdevi Kommineni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href=&quot;https://www.linkedin.com/advice/0/what-best-practices-data-sharding-partitioning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Best practices for data sharding and partitioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;System Design School: &lt;a href=&quot;https://systemdesignschool.io/blog/sharding-vs-partitioning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sharding vs Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chat2DB: &lt;a href=&quot;https://chat2db.ai/resources/blog/database-sharding#2-key-based-sharding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Database Sharding: How It Works and Its Benefits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chat2DB: &lt;a href=&quot;https://chat2db.ai/resources/blog/sharding-vs-partitioning#technical-implications-of-sharding-vs-partitioning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sharding vs Partitioning: A Comprehensive Guide to Key Database Optimization Techniques&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DEV.to: &lt;a href=&quot;https://dev.to/devcorner/sharding-vs-partitioning-vs-replication-a-complete-guide-17b2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sharding vs. Partitioning vs. Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Yugabyte: &lt;a href=&quot;https://www.yugabyte.com/blog/four-data-sharding-strategies-we-analyzed-in-building-a-distributed-sql-database/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Four Data Sharding Strategies We Analyzed in Building a Distributed SQL Database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>Architecture</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>Distribution</category>
      <category>partitioning</category>
      <category>Sharding</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/48</guid>
      <comments>https://readyoun.tistory.com/48#entry48comment</comments>
      <pubDate>Wed, 9 Apr 2025 04:12:25 +0900</pubDate>
    </item>
    <item>
      <title>NoSQL의 모든 것: 개념, 종류, MongoDB와 Redis 맛보기</title>
      <link>https://readyoun.tistory.com/47</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;lxc3yrygpn310s4oq-NoSQL-Features.svg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;657&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CvJPP/btsNdiEVhf8/vangW5E6yqKkUdX8EX93Wk/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CvJPP/btsNdiEVhf8/vangW5E6yqKkUdX8EX93Wk/tfile.svg&quot; data-alt=&quot;https://www.mongodb.com/ko-kr/resources/basics/databases/nosql-explained&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CvJPP/btsNdiEVhf8/vangW5E6yqKkUdX8EX93Wk/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCvJPP%2FbtsNdiEVhf8%2FvangW5E6yqKkUdX8EX93Wk%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;657&quot; data-filename=&quot;lxc3yrygpn310s4oq-NoSQL-Features.svg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;657&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.mongodb.com/ko-kr/resources/basics/databases/nosql-explained&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요: 왜 NoSQL인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에서 대용량 데이터를 다루거나 수평적 확장이 필요한 상황이라면, RDBMS 대신 NoSQL을 검토해본 적이 있을 것입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;  NoSQL의 의미&lt;/b&gt;&lt;br /&gt;NoSQL은 'Non-SQL' 또는 'Not only SQL'로 해석되며, &lt;br /&gt;SQL처럼 특정 쿼리 언어를 지칭하는 것이 아닌 &lt;br /&gt;새로운 데이터베이스 패러다임을 의미합니다. &lt;br /&gt;&lt;br /&gt;전통적인 관계형 데이터베이스의 제약에서 벗어나 &lt;br /&gt;데이터를 더 자유롭고 유연한 형태로 저장하고 관리하는 접근 방식입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 &lt;b&gt;NoSQL의 주요 네 가지 종류&lt;/b&gt;를 구체적으로 비교하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 NoSQL이 주목받는지&lt;/b&gt;, &lt;b&gt;MongoDB와 Redis의 기본 사용법까지 실습 방법&lt;/b&gt;을 공유합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  참고: 이 글은 『이것이 취업을 위한 컴퓨터 과학이다』 CHAPTER 06, p.605 ~ p.620의 내용을 기반으로 한 설명입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. RDBMS vs NoSQL: 무엇이 다른가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 데이터베이스(RDBMS)는 &lt;b&gt;정형 데이터&lt;/b&gt;, &lt;b&gt;스키마 고정&lt;/b&gt;, &lt;b&gt;ACID 트랜잭션&lt;/b&gt;을 강점으로 삼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;u&gt;대규모 사용자 요청과 다양한 형태의 비정형 데이터&lt;/u&gt;를 처리하기엔 한계가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, NoSQL은 다음과 같은 특성을 가집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스키마 유연성&lt;/b&gt;: 구조가 자유로워 다양한 형태의 데이터를 저장 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수평적 확장성&lt;/b&gt;: 서버를 늘려 성능 개선&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고가용성&lt;/b&gt;: 장애 발생 시 빠른 복구 가능&lt;/li&gt;
&lt;li&gt;ACID보다는 &lt;b&gt;BASE(Basically Available, Soft state, Eventual consistency) 지향&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;생각해보기&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;NoSQL이라는 용어는 단순히 &quot;SQL이 아닌&quot;이라는 의미를 넘어서, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;어떤 특별한 가치와 장점을 제공할까요? &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;RDBMS와 비교했을 때 가장 두드러지는 차이점은 무엇일까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;☞ 관계형 데이터베이스는 &lt;u&gt;테이블 기반의 구조로서 스키마가 고정되어 있는 반면&lt;/u&gt;, 비관계형 데이터베이스인 NoSQL 데이터베이스는 데이터의 저장 및 관리를 위해 &lt;u&gt;고정된 스키마가 없고, 수평 확장이 용이한 구조&lt;/u&gt;를 가지고 있습니다. NoSQL 데이터베이스는 키-값, 도큐먼트, 칼럼 패밀리, 그래프 등의 다양한 형태로 저장할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. NoSQL의 네 가지 대표 유형&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 키-값(Key-Value) 데이터베이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대표 사례&lt;/b&gt;: Redis, Memcached&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조&lt;/b&gt;: 단순히 &lt;code&gt;키(key)&lt;/code&gt;와 &lt;code&gt;값(value)&lt;/code&gt;으로 구성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매우 빠른 읽기/쓰기 속도&lt;/li&gt;
&lt;li&gt;대부분 &lt;b&gt;인메모리(in-memory)&lt;/b&gt; 기반으로 동작 &amp;rarr; 디스크보다 빠름&lt;/li&gt;
&lt;li&gt;단순 조회에 적합하지만, 복잡한 쿼리는 부적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;  인메모리 DB란?&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;데이터를 디스크가 아닌 RAM에 저장하여 초고속으로 접근 가능한 DB입니다. Redis, Memcached가 대표적입니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;생각해보기&lt;br /&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;인메모리 데이터베이스는 데이터를 메모리에 저장하므로 &lt;u&gt;재시작 시 데이터가 손실될 수 있습니다. &lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;그렇다면 Redis와 같은 인메모리 DB들은 이 문제를 어떻게 해결할까요?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;☞ Redis는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;RDB&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(Redis Database)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;스냅샷&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;AOF&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(Append Only File)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;방식&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;을 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;데이터 영속성&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;을 보장합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;RDB&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;는 특정 시점의 데이터를 디스크에 저장하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;AOF&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;는 모든 쓰기 명령을 로그로 저장하여 &lt;u&gt;재시작 시 데이터를 복구할 수 있게 합니다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 도큐먼트(Document) 데이터베이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대표 사례&lt;/b&gt;: MongoDB&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조&lt;/b&gt;: JSON 또는 BSON 형식의 도큐먼트 단위로 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도큐먼트 하나가 하나의 레코드를 구성&lt;/li&gt;
&lt;li&gt;필드마다 타입이 달라도 저장 가능 (스키마 유연성)&lt;/li&gt;
&lt;li&gt;중첩된 데이터(배열, 객체) 구조도 표현 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB는 NoSQL의 대표 주자로, RDBMS의 &lt;b&gt;테이블 &amp;rarr; 컬렉션, 행 &amp;rarr; 도큐먼트&lt;/b&gt;로 대응됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3uNRH/btsNbwLo3GR/LTuN59Bxbrwjk6Kdwd77Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3uNRH/btsNbwLo3GR/LTuN59Bxbrwjk6Kdwd77Y1/img.png&quot; data-alt=&quot;p.606&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3uNRH/btsNbwLo3GR/LTuN59Bxbrwjk6Kdwd77Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3uNRH%2FbtsNbwLo3GR%2FLTuN59Bxbrwjk6Kdwd77Y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;518&quot; height=&quot;277&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;p.606&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;  &lt;/span&gt;&lt;b&gt;생각해보기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;MongoDB는 스키마가 자유롭다고 하지만, 완전히 제약이 없는 것은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;데이터의 일관성과 유효성&lt;/b&gt;을 어떻게 보장할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;☞&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;MongoDB는 &lt;u&gt;JSON Schema 검증, 인덱싱, 애플리케이션 레벨의 검증 로직&lt;/u&gt;을 통해 &lt;b&gt;데이터 일관성&lt;/b&gt;을 유지할 수 있습니다. &lt;a href=&quot;https://www.kenwalger.com/blog/nosql/mongodb/schema-validation-mongodb-3-6/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;특히 MongoDB 3.6 버전부터는 컬렉션 레벨에서 스키마 검증을 설정할 수 있어, 필요한 경우 RDBMS처럼 엄격한 스키마 제약도 가능합니다.&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 그래프(Graph) 데이터베이스&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOJ7rh/btsNbrQ1hKD/JF5F61GUMwQRbbN0L8KAq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOJ7rh/btsNbrQ1hKD/JF5F61GUMwQRbbN0L8KAq1/img.png&quot; data-alt=&quot;wikipedia 그래프 데이터베이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOJ7rh/btsNbrQ1hKD/JF5F61GUMwQRbbN0L8KAq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOJ7rh%2FbtsNbrQ1hKD%2FJF5F61GUMwQRbbN0L8KAq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;616&quot; height=&quot;436&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;wikipedia 그래프 데이터베이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대표 사례&lt;/b&gt;: Neo4j&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조&lt;/b&gt;: 노드(Node)와 간선(Edge)으로 구성된 방향 그래프&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드 간 관계를 빠르게 탐색 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소셜 미디어 친구 관계&lt;/b&gt;, &lt;b&gt;교통망&lt;/b&gt;, &lt;b&gt;추천 시스템&lt;/b&gt; 등 관계형 데이터에 적합&lt;/li&gt;
&lt;li&gt;복잡한 JOIN을 단순한 그래프 탐색으로 대체&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  그래프 구조의 핵심은 &lt;b&gt;노드 간 연결 관계를 직접 저장하고 탐색할 수 있는 성능&lt;/b&gt;에 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;  &lt;/span&gt;&lt;b&gt;생각해보기&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;소셜 미디어나 추천 시스템에서 그래프 데이터베이스가 RDBMS보다 효율적인 이유는 무엇일까요?&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;☞&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&amp;nbsp;&lt;/span&gt;예를 들어 &quot;친구의 친구 찾기&quot;와 같은 기능을 구현할 때, RDBMS에서는 여러 번의 JOIN 연산이 필요하지만, 그래프 DB에서는 &lt;u&gt;노드 간 관계를 직접 탐색할 수 있어 매우 효율적입니다&lt;/u&gt;. 특히 LinkedIn과 같은 소셜 네트워크에서 &quot;n차 연결&quot; 기능을 구현할 때 그래프 DB의 장점이 두드러집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span&gt;why?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;그래프&amp;nbsp;데이터베이스가&amp;nbsp;SNS나&amp;nbsp;추천&amp;nbsp;시스템에서&amp;nbsp;RDBMS보다&amp;nbsp;효율적인&amp;nbsp;이유는&amp;nbsp;&lt;u&gt;데이터&amp;nbsp;탐색&amp;nbsp;방식과&amp;nbsp;데이터&amp;nbsp;모델링의&amp;nbsp;유연성&lt;/u&gt;에&amp;nbsp;있습니다.&amp;nbsp;RDBMS에서는&amp;nbsp;&quot;친구의&amp;nbsp;친구&quot;를&amp;nbsp;찾기&amp;nbsp;위해&amp;nbsp;&lt;u&gt;여러&amp;nbsp;번의&amp;nbsp;JOIN&amp;nbsp;연산&lt;/u&gt;을&amp;nbsp;수행해야&amp;nbsp;하며,&amp;nbsp;&lt;u&gt;탐색&amp;nbsp;깊이가&amp;nbsp;깊어질수록&amp;nbsp;계산량이&amp;nbsp;기하급수적으로&amp;nbsp;증가&lt;/u&gt;합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;반면,&amp;nbsp;그래프&amp;nbsp;데이터베이스는&amp;nbsp;노드(사용자)와&amp;nbsp;엣지(관계)를&amp;nbsp;물리적으로&amp;nbsp;&lt;u&gt;연결된&amp;nbsp;상태&lt;/u&gt;로&amp;nbsp;저장하여&amp;nbsp;&lt;u&gt;직접&amp;nbsp;포인터를&amp;nbsp;따라&amp;nbsp;탐색&lt;/u&gt;하므로&amp;nbsp;탐색&amp;nbsp;복잡도가&amp;nbsp;선형적으로&amp;nbsp;증가(O(n))하며&amp;nbsp;매우&amp;nbsp;빠릅니다.&amp;nbsp;또한&amp;nbsp;그래프&amp;nbsp;DB는&amp;nbsp;스키마가&amp;nbsp;없거나&amp;nbsp;유연한&amp;nbsp;구조를&amp;nbsp;제공해&amp;nbsp;새로운&amp;nbsp;관계&amp;nbsp;유형을&amp;nbsp;쉽게&amp;nbsp;추가할&amp;nbsp;수&amp;nbsp;있고,&amp;nbsp;엣지에&amp;nbsp;&lt;u&gt;가중치나&amp;nbsp;속성&lt;/u&gt;을&amp;nbsp;저장하여&amp;nbsp;추천&amp;nbsp;시스템에서&amp;nbsp;고급&amp;nbsp;분석을&amp;nbsp;가능하게&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;특히 LinkedIn과 같은 소셜 네트워크에서 &lt;u&gt;&quot;n차 연결&quot; 기능&lt;/u&gt;을 구현할 때:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;그래프 DB는 엣지를 따라 &lt;u&gt;실시간으로 관계를 탐색&lt;/u&gt;할 수 있어 &lt;u&gt;대규모 연결 데이터를 효율적으로 처리&lt;/u&gt;할 수 있으며, &lt;u&gt;그래프 알고리즘(PageRank, 최단 경로 등)&lt;/u&gt;을 활용해 &lt;u&gt;사용자 간 관계망 분석이나 추천을 최적화&lt;/u&gt;할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;이러한 이유로 SNS와 추천 시스템에서 그래프 데이터베이스는 RDBMS보다 더 적합한 선택입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4 칼럼 패밀리(Column Family) 데이터베이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대표 사례&lt;/b&gt;: Cassandra, HBase&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조&lt;/b&gt;: 행(Row)과 열(Column) 구조를 가지지만 스키마 고정 X&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 행마다 다른 열을 가질 수 있음&lt;/li&gt;
&lt;li&gt;정규화나 JOIN 없이 사용 (데이터 중복을 허용)&lt;/li&gt;
&lt;li&gt;대규모 쓰기/읽기에 강한 성능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  &quot;칼럼 패밀리&quot;란 연관된 열들을 묶어 저장하는 단위입니다. 한 패밀리 안에서 열 구조는 유연하게 변할 수 있습니다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FStdu/btsNbaaZZL5/mtNduInVQlkNAOIbgrars1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FStdu/btsNbaaZZL5/mtNduInVQlkNAOIbgrars1/img.png&quot; data-alt=&quot;p.608&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FStdu/btsNbaaZZL5/mtNduInVQlkNAOIbgrars1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFStdu%2FbtsNbaaZZL5%2FmtNduInVQlkNAOIbgrars1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;396&quot; height=&quot;142&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;142&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;p.608&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;  &lt;b&gt;생각해보기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;빅데이터 처리에서 칼럼 패밀리 데이터베이스가 선호되는 이유는 무엇일까요? 특히 데이터 압축과 조회 성능 측면에서 생각해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;☞&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&amp;nbsp;&lt;/span&gt;데이터 저장 방식과 효율적인 읽기 성능 이점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;칼럼 패밀리 DB는 데이터를 행(row) 단위가 아닌 &lt;u&gt;열(column) 단위로 저장&lt;/u&gt;합니다. 같은 유형의 데이터를 &lt;u&gt;물리적으로 인접하게 저장&lt;/u&gt;하므로, &lt;u&gt;데이터 압축 효율&lt;/u&gt;이 매우 높아지고 &lt;u&gt;저장 공간&lt;/u&gt;을 절약할 수 있습니다. 예를 들어, 동일한 열에 반복적으로 나타나는 값(예: 센서 데이터의 상태 플래그)을 효과적으로 압축할 수 있습니다.&lt;br /&gt;&lt;br /&gt;또한,&amp;nbsp;칼럼&amp;nbsp;단위로&amp;nbsp;데이터를&amp;nbsp;읽기&amp;nbsp;때문에&amp;nbsp;&lt;u&gt;필요한&amp;nbsp;열만&amp;nbsp;선택적으로&amp;nbsp;조회&lt;/u&gt;할&amp;nbsp;수&amp;nbsp;있어&amp;nbsp;입출력(IO)&amp;nbsp;성능이&amp;nbsp;크게&amp;nbsp;향상됩니다.&amp;nbsp;이는&amp;nbsp;특히&amp;nbsp;&lt;u&gt;대규모&amp;nbsp;데이터셋에서&amp;nbsp;일부&amp;nbsp;열만&amp;nbsp;자주&amp;nbsp;읽는&amp;nbsp;경우&lt;/u&gt;(예: 로그 분석에서 특정 필드만 조회) 매우 유리합니다. 이러한 특성 덕분에 칼럼 패밀리 DB는 센서 데이터, 로그 데이터, 시계열 데이터와 같이 대규모로 생성되고 특정 열에 집중된 분석이 필요한 빅데이터 처리에 적합합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. NoSQL을 선택하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NoSQL은 다음과 같은 상황에서 선택합니다.&lt;/p&gt;
&lt;table style=&quot;width: 423px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 244px;&quot;&gt;조건&lt;/th&gt;
&lt;th style=&quot;width: 69px;&quot;&gt;RDBMS&lt;/th&gt;
&lt;th style=&quot;width: 110px;&quot;&gt;NoSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 244px;&quot;&gt;데이터 정형성&lt;/td&gt;
&lt;td style=&quot;width: 69px;&quot;&gt;높음&lt;/td&gt;
&lt;td style=&quot;width: 110px;&quot;&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 244px;&quot;&gt;트랜잭션 무결성(ACID)&lt;/td&gt;
&lt;td style=&quot;width: 69px;&quot;&gt;중요&lt;/td&gt;
&lt;td style=&quot;width: 110px;&quot;&gt;덜 중요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 244px;&quot;&gt;수평적 확장 필요 여부&lt;/td&gt;
&lt;td style=&quot;width: 69px;&quot;&gt;낮음&lt;/td&gt;
&lt;td style=&quot;width: 110px;&quot;&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 244px;&quot;&gt;데이터 관계 복잡성&lt;/td&gt;
&lt;td style=&quot;width: 69px;&quot;&gt;높음&lt;/td&gt;
&lt;td style=&quot;width: 110px;&quot;&gt;낮음~중간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 244px;&quot;&gt;빠른 읽기/쓰기 성능&lt;/td&gt;
&lt;td style=&quot;width: 69px;&quot;&gt;일반적&lt;/td&gt;
&lt;td style=&quot;width: 110px;&quot;&gt;매우 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 244px;&quot;&gt;유연한 구조의 데이터 처리 필요&lt;/td&gt;
&lt;td style=&quot;width: 69px;&quot;&gt;부족&lt;/td&gt;
&lt;td style=&quot;width: 110px;&quot;&gt;매우 유연&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;⚠️ ACID를 아예 포기하는 것은 &lt;b&gt;아닙니다&lt;/b&gt;. MongoDB, Cassandra 등은 상황에 따라 ACID 일부를 지원하거나 옵션으로 제공합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;생각해보기&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;데이터베이스 선택은 프로젝트의 성공을 좌우하는 중요한 결정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;NoSQL과 RDBMS는 각각 어떤 상황에서 더 적합할까요?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;NoSQL 데이터베이스는 대규모의 비정형 데이터를 처리할 때,&amp;nbsp;높은 확장성과 빠른 읽기/쓰기 성능이 필요할 때 유리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그러나 엄격한 트랜잭션 관리나 데이터 일관성 보장, 관계형 데이터 모델링이 필요한 애플리케이션에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;관계형 데이터베이스가 더 적합하므로 NoSQL 데이터베이스는 불리할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실습으로 이해하는 NoSQL&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;실습 전 준비&lt;/b&gt;&lt;br /&gt;환경 설정은 &lt;a href=&quot;https://github.com/kangtegong/cs?tab=readme-ov-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;강태공 GitHub 실습 자료&lt;/a&gt;를 참고해주세요.&lt;br /&gt;MongoDB와 Redis 모두 로컬 혹은 Docker로 손쉽게 구성할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 MongoDB 실습 요약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB에서 레코드는 &lt;b&gt;도큐먼트 단위&lt;/b&gt;로 저장됩니다. &lt;b&gt;도큐먼트&lt;/b&gt;가 모여 &lt;b&gt;컬렉션&lt;/b&gt;이 되고, 컬렉션이 모여 &lt;b&gt;데이터베이스&lt;/b&gt;를 구성합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;# 데이터베이스 및 컬렉션 생성
use mydb
db.createCollection(&quot;mycollection&quot;)

# 단일 도큐먼트 삽입
db.mycollection.insertOne({ name: &quot;Robin&quot;, age: 28 })

# 다중 도큐먼트 삽입
db.mycollection.insertMany([{ name: &quot;Ash&quot; }, { name: &quot;Hanna&quot; }])

# 도큐먼트 조회
db.mycollection.find()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  여기서 잠깐!&amp;nbsp;&lt;b&gt;MongoDB의 주요 연산자 정리&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;MongoDB는&lt;span&gt;&amp;nbsp;&lt;/span&gt;$set, $inc, $push, $pull&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 연산자를 통해 도큐먼트 내부 필드를 유연하게 갱신할 수 있습니다. SQL의&lt;span&gt;&amp;nbsp;&lt;/span&gt;UPDATE SET과 유사하지만, JSON 구조를 직접 조작한다는 점에서 차별화됩니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgSwF3/btsNdkQgRWS/2jTqQbbFN5tKj53d35HYMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgSwF3/btsNdkQgRWS/2jTqQbbFN5tKj53d35HYMK/img.png&quot; data-alt=&quot;(p.612)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgSwF3/btsNdkQgRWS/2jTqQbbFN5tKj53d35HYMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgSwF3%2FbtsNdkQgRWS%2F2jTqQbbFN5tKj53d35HYMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;459&quot; height=&quot;417&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(p.612)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;br /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;  Tip&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$set과 $eq는 거의 모든 MongoDB 작업에서 사용됩니다&lt;/li&gt;
&lt;li&gt;$in은 여러 조건을 한 번에 처리할 때 매우 유용합니다&lt;/li&gt;
&lt;li&gt;$inc는 카운터나 통계 처리에 필수적입니다&lt;/li&gt;
&lt;li&gt;배열 처리는 $push와 $pull이 가장 기본입니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 Redis : 빠르고&amp;nbsp;유연한&amp;nbsp;인메모리&amp;nbsp;데이터베이스&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;86&quot;&gt;&lt;a href=&quot;https://github.com/redis/redis&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKZaYG/btsNb2ccW1n/rpzQJOZQ4fYjAEUZr37gl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKZaYG%2FbtsNb2ccW1n%2FrpzQJOZQ4fYjAEUZr37gl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;250&quot; height=&quot;86&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis는&amp;nbsp;Remote&amp;nbsp;Dictionary&amp;nbsp;Server의&amp;nbsp;약자로,&amp;nbsp;&lt;b&gt;인메모리&amp;nbsp;기반의&amp;nbsp;키-값&amp;nbsp;데이터베이스&lt;/b&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든&amp;nbsp;데이터를&amp;nbsp;&lt;b&gt;RAM&lt;/b&gt;에&amp;nbsp;저장하여&amp;nbsp;초고속&amp;nbsp;성능을&amp;nbsp;제공하며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스,&amp;nbsp;캐시(Cache),&amp;nbsp;메시지&amp;nbsp;브로커,&amp;nbsp;세션&amp;nbsp;관리,&amp;nbsp;실시간&amp;nbsp;데이터&amp;nbsp;분석&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;용도로&amp;nbsp;활용됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;392&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/redis-its-data-structures-asim-hafeez/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnTpH4/btsNdjw50ck/K8HGBvroIwcAOd2201qfI1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnTpH4%2FbtsNdjw50ck%2FK8HGBvroIwcAOd2201qfI1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;876&quot; height=&quot;392&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;Asim Hafeez - Redis and Its Data Structures&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis는&amp;nbsp;단순한&amp;nbsp;키-값&amp;nbsp;저장소를&amp;nbsp;넘어&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;문자열(String),&amp;nbsp;리스트(List),&amp;nbsp;해시(Hash),&amp;nbsp;집합(Set),&amp;nbsp;정렬된&amp;nbsp;집합(Sorted&amp;nbsp;Set)&amp;nbsp;등&lt;/u&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한&amp;nbsp;자료구조를&amp;nbsp;지원&lt;/b&gt;하여&amp;nbsp;애플리케이션의&amp;nbsp;요구사항에&amp;nbsp;유연하게&amp;nbsp;대응할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;# 문자열 저장 및 조회
SET username &quot;Robin&quot;
GET username

# 리스트 연산
LPUSH tasks &quot;task1&quot;
RPUSH tasks &quot;task2&quot;
LRANGE tasks 0 -1  # 전체 리스트 조회&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/REDIS-%F0%9F%93%9A-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85Collection-%EC%A2%85%EB%A5%98-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 : REDIS- -데이터-타입Collection-종류-정리&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;331&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9awi9/btsNbrwGdej/AxwrKvAkMc6ID8M3TSjCw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9awi9/btsNbrwGdej/AxwrKvAkMc6ID8M3TSjCw0/img.png&quot; data-alt=&quot;p.616&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9awi9/btsNbrwGdej/AxwrKvAkMc6ID8M3TSjCw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9awi9%2FbtsNbrwGdej%2FAxwrKvAkMc6ID8M3TSjCw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;331&quot; height=&quot;273&quot; data-origin-width=&quot;331&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;p.616&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한&amp;nbsp;구조&amp;nbsp;덕분에&amp;nbsp;Redis는&amp;nbsp;&lt;b&gt;지연&amp;nbsp;시간이&amp;nbsp;중요한&amp;nbsp;애플리케이션&lt;/b&gt;에서&amp;nbsp;널리&amp;nbsp;사용되며,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대규모&amp;nbsp;트래픽&amp;nbsp;환경&lt;/b&gt;에서도&amp;nbsp;안정적으로&amp;nbsp;작동합니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &lt;span&gt; 장점: 빠른&amp;nbsp;속도와&amp;nbsp;유연성&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터를&amp;nbsp;디스크가&amp;nbsp;아닌&amp;nbsp;&lt;u&gt;RAM에&amp;nbsp;저장&lt;/u&gt;하기&amp;nbsp;때문에&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;읽기&amp;nbsp;및&amp;nbsp;쓰기&amp;nbsp;작업이&amp;nbsp;마이크로초&amp;nbsp;단위로&amp;nbsp;처리되며,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;초당&amp;nbsp;수백만&amp;nbsp;건의&amp;nbsp;요청을&amp;nbsp;처리&lt;/b&gt;할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한, Redis는 아래 3가지를 지원해&amp;nbsp;확장성과&amp;nbsp;고가용성을&amp;nbsp;제공합니다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터 복제(Replication)&lt;/li&gt;
&lt;li&gt;영속성(Persistence)&lt;/li&gt;
&lt;li&gt;클러스터링(Clustering)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;Redis&amp;nbsp;활용&amp;nbsp;사례&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Redis는 빠른 속도와 유연한 자료구조 덕분에 다음과 같은 다양한 상황에서 활용됩니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;캐싱&lt;/b&gt;: 웹 애플리케이션에서 자주 조회되는 데이터를 저장하여 응답 시간을 단축.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지 브로커&lt;/b&gt;: Pub/Sub 기능을 활용해 실시간 알림 시스템 구현.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세션 관리&lt;/b&gt;: 사용자 로그인 세션을 관리하여 빠르게 접근 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간 분석&lt;/b&gt;: 로그 데이터나 센서 데이터를 처리하여 실시간 통계를 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순위표&amp;nbsp;및&amp;nbsp;리더보드&lt;/b&gt;:&amp;nbsp;정렬된&amp;nbsp;집합(Sorted&amp;nbsp;Set)을&amp;nbsp;활용해&amp;nbsp;실시간&amp;nbsp;순위&amp;nbsp;계산.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;  &lt;/span&gt;&lt;b&gt;생각해보기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;많은 기업들이 Redis를 캐시 시스템으로 활용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Redis의 어떤 특성이 캐시 서버로서 특별한 가치를 제공하는 걸까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;사용자의 로드 시간이 적을수록 &lt;b&gt;전환율&lt;/b&gt;이 높습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그런데 Redis는 &lt;u&gt;인메모리 데이터베이스&lt;/u&gt;이기 때문에 &lt;u&gt;디스크 접근 시간을 단축&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;또한 Redis는 여러 자료구조를 지원하는 키-값 데이터베이스로써,&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;RDBMS보다 &lt;u&gt;정형화되어 있지 않은 데이터&lt;/u&gt;에 대한 빠른 입출력이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;따라서 RDBMS 등을 주요 데이터베이스로 삼고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;u&gt;Redis를 캐시 역할을 수행하는 부차적인 데이터베이스&lt;/u&gt;로 삼으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;주요 데이터베이스의 입출력 성능을 상당 부분 보강할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  Redis와 캐싱 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐싱은 시스템의 성능을 향상시키는 가장 쉬운 방법이라고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis는 특히 &lt;b&gt;캐시(Cache)&lt;/b&gt;로 자주 사용되며, 다양한 캐싱 전략 패턴이 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Static/Dynamic Caching : &lt;/b&gt;데이터 변경 가능성과 일관성 유지 여부 기준
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Static: 읽기 전용, 변경 불가 &amp;rarr; Cache-Aside, Write-Around.&lt;/li&gt;
&lt;li&gt;Dynamic: 읽기/쓰기 가능, 변경 가능 &amp;rarr; Write-Through, Write-Back.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐싱 전략 패턴&lt;/b&gt; : 데이터 처리 흐름 기준&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cache-Aside: 필요할 때만 캐시 사용. 가장 일반적.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Write-Through: 실시간으로 캐시와 DB 동기화.&lt;/li&gt;
&lt;li&gt;Write-Around: 쓰기는 DB에만, 읽기는 캐시에서.&lt;/li&gt;
&lt;li&gt;Write-Back: 쓰기는 먼저 캐시에, 이후 비동기로 DB에 반영.&lt;/li&gt;
&lt;li&gt;Read-Through:&amp;nbsp;읽기를&amp;nbsp;자동으로&amp;nbsp;처리하며&amp;nbsp;필요&amp;nbsp;시&amp;nbsp;DB에서&amp;nbsp;가져옴.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- &lt;a href=&quot;https://minnseong.tistory.com/49&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://minnseong.tistory.com/49&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- &lt;a href=&quot;https://velog.io/@zenon8485/%EC%BA%90%EC%8B%B1%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@zenon8485/%EC%BA%90%EC%8B%B1%EC%A0%84%EB%9E%B5&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 마무리 및 배운 점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NoSQL은 단순히 RDBMS의 대체재가 아닌, 특정 문제에 특화된 대안&lt;/li&gt;
&lt;li&gt;정형 데이터, 트랜잭션 중심이면 여전히 RDBMS가 우위&lt;/li&gt;
&lt;li&gt;반면, 유연성, 확장성, 속도가 중요하면 NoSQL이 탁월&lt;/li&gt;
&lt;li&gt;MongoDB와 Redis의 기본 동작 원리를 알아봄&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Tip: 실제 프로젝트에서는 RDBMS와 NoSQL을 혼합하여 사용하는 하이브리드 구조도 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;『이것이 취업을 위한 컴퓨터 과학이다』 CHAPTER 06, p.605 ~ p.620&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/ko-kr/resources/basics/databases/nosql-explained&quot;&gt;MongoDB - NoSQL이란 무엇입니까?&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sql vs nosql : &lt;a href=&quot;https://www.mongodb.com/ko-kr/resources/basics/databases/nosql-explained/nosql-vs-sql&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.mongodb.com/ko-kr/resources/basics/databases/nosql-explained/nosql-vs-sql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;types: &lt;a href=&quot;https://www.mongodb.com/resources/basics/databases/types&quot;&gt;https://www.mongodb.com/resources/basics/databases/types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/bluQwqMgTsw?si=RXNC8uwwcJZKiQV5&quot;&gt;큰돌의터전 - MySQL과 MongoDB의 완벽한 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/sqVByJ5tbNA?si=dW7CxLZj_q-vT4Dg&quot;&gt;쉬운코드 - BJ.53 NoSQL 설명!! RDB와는 어떤 차이가 있는지도 설명!! MongoDB, Redis 매우 간단한 예제 포함!!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/0buKQHokLK8?si=2Hhtg-XMGo9u5GzG&quot;&gt;Simply Explained - How do NoSQL databases work? Simply Explained!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/VfcRxtBKI54?si=AovB3zYoheDagOuw&quot;&gt;Anton Putra - Types of Databases: Relational vs. Columnar vs. Document vs. Graph vs. Vector vs. Key-value &amp;amp; more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/6szdySvorzA?si=jQ2PpYb4MbaNOhCY&quot;&gt;Awesome - The Fascinating History of Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://f-lab.kr/insight/spring-boot-redis-caching-20240829?gad_source=1&amp;amp;gclid=Cj0KCQjw782_BhDjARIsABTv_JBFc0pwHW8vVqfSWKQutXEYomj1x0UeIYTvMqno4EsY_2ZRZpLlUfQaAv-XEALw_wcB&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;F-Lab 스프링&amp;nbsp;부트와&amp;nbsp;레디스를&amp;nbsp;활용한&amp;nbsp;캐싱&amp;nbsp;전략&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  더 알아보기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CAP 이론과 NoSQL의 일관성 모델: Eventually Consistent란?&lt;/li&gt;
&lt;li&gt;Redis의 TTL(Time to Live)과 만료 처리 전략&lt;/li&gt;
&lt;li&gt;MongoDB의 인덱싱 구조와 복합 인덱스 설계&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>MongoDB</category>
      <category>NoSQL</category>
      <category>Redis</category>
      <category>sql</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/47</guid>
      <comments>https://readyoun.tistory.com/47#entry47comment</comments>
      <pubDate>Tue, 8 Apr 2025 00:07:25 +0900</pubDate>
    </item>
    <item>
      <title>정규화(Normalization): 중복 없는 데이터베이스 설계 (1NF - BCNF)</title>
      <link>https://readyoun.tistory.com/46</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정규화 단계 정리&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 설계를 하다 보면, 모든 정보를 한 테이블에 넣고 싶어질 때가 있어요. 그런데 그렇게 만들면 어떤 문제가 생길까요?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터가 중복되고&lt;/li&gt;
&lt;li&gt;수정할 때 실수하고&lt;/li&gt;
&lt;li&gt;삭제했더니 같이 날아가고  &lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 막기 위해 등장한 게 바로 &lt;b&gt;정규화(Normalization)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화는 테이블을 잘게 나누고, 각 속성을 적절한 자리에 배치해서 &lt;b&gt;데이터의 무결성과 유지보수성&lt;/b&gt;을 높이는 설계 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화를 하면 단순히 중복만 줄이는 게 아니라,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 &lt;b&gt;일관성(consistency)&lt;/b&gt; 유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입/삭제/수정 이상(Anomaly)&lt;/b&gt; 방지&lt;/li&gt;
&lt;li&gt;테이블 구조가 더 &lt;b&gt;확장성 있게 설계&lt;/b&gt;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 이점이 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;  참고: 이 글은 『이것이 취업을 위한 컴퓨터 과학이다』 CHAPTER 06, p.593 ~ p.604의 내용을 기반으로 한 설명입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 정규화 핵심 용어 쉽게 풀어보기&lt;/h2&gt;
&lt;table style=&quot;height: 120px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;용어&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;쉽게 설명하면&amp;hellip;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;함수 종속&lt;/b&gt; (A &amp;rarr; B)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;하나를 알면 다른 게 자동으로 결정돼요. (예: 학번 &amp;rarr; 이름)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;부분 함수 종속&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;키가 여러 개인데, 그 중 일부에만 종속됨 (예: 학번+과목이 키인데 이름은 학번만으로도 알 수 있음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;이행 함수 종속&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간 단계를 거쳐 종속됨 (예: 과목 &amp;rarr; 교수 &amp;rarr; 사무실)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;후보 키&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;기본키로 쓸 수 있는 후보들 (예: 주민번호, 이메일 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;결정자&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;다른 값을 결정짓는 열 (예: 학번이 이름의 결정자)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 제1정규형 (1NF) - 원자값으로만 구성하기&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  책 용어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제1정규형이란, 모든 속성이 &lt;b&gt;원자값(Atomic Value)&lt;/b&gt; 만 가지도록 구성한 테이블입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  쉽게 말하면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 칸에 값이 두 개 이상 들어가면 안 된다는 뜻이에요!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❗ 문제 예시&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;학번&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;수강 과목&lt;/th&gt;
&lt;th&gt;담당 교수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;김현수&lt;/td&gt;
&lt;td&gt;운영체제, 데이터베이스&lt;/td&gt;
&lt;td&gt;김교수, 이교수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 후 (1NF)&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;학번&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;수강 과목&lt;/th&gt;
&lt;th&gt;담당 교수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;김현수&lt;/td&gt;
&lt;td&gt;운영체제&lt;/td&gt;
&lt;td&gt;김교수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;김현수&lt;/td&gt;
&lt;td&gt;데이터베이스&lt;/td&gt;
&lt;td&gt;이교수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 제2정규형 (2NF) - 부분 함수 종속 제거&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  책 용어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제2정규형은 제1정규형을 만족하고, 기본키의 일부에만 종속된 속성이 없어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  쉽게 말하면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;키의 &amp;lsquo;일부&amp;rsquo;만 알아도 값이 정해지는 관계&lt;/u&gt;라서 &lt;b&gt;&amp;lsquo;부분&amp;rsquo; 종속&lt;/b&gt;이라고 불러요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블의 기본키가 두 개일 때, 그 중 하나만 알아도 알 수 있는 값은 따로 빼줘야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❗ 문제 예시&lt;/h3&gt;
&lt;table style=&quot;height: 40px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;학번&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;이름&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;과목&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;성적&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;1001&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;김현수&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;국어&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 (학번 + 과목)이 기본키인데, 이름은 학번만으로도 알 수 있죠. 이게 바로 &lt;b&gt;부분 함수 종속&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 후&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;학생 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;학번&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1001&lt;/td&gt;
&lt;td&gt;김현수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수강 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;학번&lt;/th&gt;
&lt;th&gt;과목&lt;/th&gt;
&lt;th&gt;성적&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1001&lt;/td&gt;
&lt;td&gt;국어&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 제3정규형 (3NF) - 이행 함수 종속 제거&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  책 용어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제3정규형은 제2정규형을 만족하고, 이행 함수 종속이 없어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  쉽게 말하면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 연결된 게 아니라 &lt;u&gt;&amp;lsquo;중간 단계를 거쳐서&amp;rsquo; 값이 정해지니까&lt;/u&gt; &amp;lsquo;이행(거쳐가는)&amp;rsquo; 종속이에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 값을 알면 &amp;rarr; 다른 값을 알고 &amp;rarr; 또 다른 값을 알 수 있다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중간 단계를 거친 종속은 제거해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❗ 문제 예시&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;과목&lt;/th&gt;
&lt;th&gt;교수&lt;/th&gt;
&lt;th&gt;교수 사무실&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;운영체제&lt;/td&gt;
&lt;td&gt;김교수&lt;/td&gt;
&lt;td&gt;3층 301호&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과목 &amp;rarr; 교수 &amp;rarr; 사무실 &amp;rarr; 이행 함수 종속 발생!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 과목만 알아도 교수, 교수만 알아도 사무실을 알 수 있으니&lt;br /&gt;과목 &amp;rarr; 사무실이라는 이행 종속이 생깁니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 후&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;과목-교수 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;과목&lt;/th&gt;
&lt;th&gt;교수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;운영체제&lt;/td&gt;
&lt;td&gt;김교수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;교수 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;교수&lt;/th&gt;
&lt;th&gt;사무실 위치&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;김교수&lt;/td&gt;
&lt;td&gt;3층 301호&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 보이스/코드 정규형 (BCNF) - 결정자 조건 추가&lt;/h2&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;사실 이름만 보면 뭔가 어려워 보이는데, 알고 보면 단순합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Boyce-Codd Normal Form은 그냥&amp;hellip; &amp;ldquo;보이스(Boyce)와 코드(Codd)라는 두 사람 이름을 딴 정규형&amp;rdquo;입니다;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;두 사람이 3NF로는 해결되지 않는 데이터 종속 문제를 발견하고, 이를 해결하기 위해 만든 정규화 기준입니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;BCNF는 &amp;ldquo;모든 결정자가 후보 키여야 한다&amp;rdquo;는 조건을 추가한 &lt;b&gt;제3정규형의 강화 버전&lt;/b&gt;입니다. 제3정규형은 시험 볼 때 &amp;ldquo;틀린 것만 안 쓰면 된다&amp;rdquo; 수준이라면, BCNF는 &amp;ldquo;맞춘 것까지 모두 정답인지 증명해야 한다&amp;rdquo; 수준이라고 보면 됩니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;ldquo;3NF로도 막지 못하는 특이한 종속 케이스를 더 강하게 필터링한 거&amp;rdquo;입니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  책 용어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BCNF는 모든 결정자가 후보 키여야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  쉽게 말하면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 값을 기준으로 다른 값을 정한다면, 그 기준이 기본키로 쓸 수 있는 값이어야 해요.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;후보 키(Candidate Key)&lt;/b&gt;는 테이블에서 각 행을 &lt;u&gt;유일하게 식별할 수 있는&lt;/u&gt; 모든 열 또는 열 조합을 말해요. &lt;br /&gt;&lt;br /&gt;이 중에서 하나를 골라 실제로 &lt;u&gt;테이블의 식별자&lt;/u&gt;로 사용하는 것이 바로 &lt;b&gt;기본 키(Primary Key)&lt;/b&gt;입니다. &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;즉, 모든 기본 키는 후보 키지만, 모든 후보 키가 기본 키인 건 아니에요! &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;예를 들어 주민번호, 이메일, 학번이 모두 유일하다면 셋 다 후보 키이고, &lt;br /&gt;이 중 하나만 기본 키로 선택해서 사용합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  모든 후보 키는 결정자다. 하지만 모든 결정자가 후보 키인 것은 아니다. &lt;br /&gt;그래서 BCNF에서는 &amp;ldquo;모든 결정자는 후보 키여야 한다&amp;rdquo;는 조건을 추가로 요구합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;결정자(Determinant):&lt;/b&gt;&lt;br /&gt;어떤 속성 A가 다른 속성 B를 결정짓는다면, A는 B의 결정자&lt;br /&gt;  예: 학번 &amp;rarr; 이름이면, 학번은 이름의 결정자.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후보 키(Candidate Key):&lt;/b&gt;&lt;br /&gt;테이블에서 튜플(행)을 유일하게 구분할 수 있는 속성 또는 속성 집합&lt;br /&gt;  후보 키는 무조건 테이블의 다른 모든 속성을 결정할 수 있어요 &amp;rarr; 즉, 항상 결정자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만!&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;어떤 결정자는 후보 키가 아닐 수도 있어요.&lt;/b&gt;&lt;br /&gt;  예를 들어 과목 코드 &amp;rarr; 교수인 경우, 과목 코드는 교수는 &lt;u&gt;결정하지만&lt;/u&gt; 학생을 &lt;u&gt;구분하지는 못하니까&lt;/u&gt; 후보 키는 아니죠.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 후보 키는 다 결정자다. 근데 결정자라고 해서 다 후보 키인 건 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;        ┌────────────────────┐
        │     결정자(D)      │ &amp;larr; 가장 큼 (값을 '결정'한다? 전부 포함)
        │  ┌──────────────┐ │
        │  │ 후보 키(CK)   │ &amp;larr; 테이블의 행을 유일하게 식별할 수 있는 키들
        │  │  ┌──────────┐│ │
        │  │  │ 기본 키(PK) │ &amp;larr; 후보 키 중에서 선택된 단 하나의 키
        │  │  └──────────┘│ │
        │  └──────────────┘ │
        └────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;기본 키 &amp;sub; 후보 키 &amp;sub; 결정자&lt;/i&gt;&lt;br /&gt;&lt;i&gt;(선택된 키 &amp;sub; 유일한 키들 &amp;sub; 뭔가를 결정할 수 있는 애들)&lt;/i&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❗ 문제 예시&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;학번&lt;/th&gt;
&lt;th&gt;과목 코드&lt;/th&gt;
&lt;th&gt;담당 교수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CS101&lt;/td&gt;
&lt;td&gt;김교수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 과목 코드가 교수님을 정하지만, 과목 코드 자체는 기본키가 아니에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과목 코드 &amp;rarr; 담당 교수인데, 과목 코드가 &lt;u&gt;후보 키가 아니라면&lt;/u&gt; &lt;b&gt;BCNF 위반&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 후&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;과목 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;과목 코드&lt;/th&gt;
&lt;th&gt;담당 교수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CS101&lt;/td&gt;
&lt;td&gt;김교수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;학생-과목 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;학번&lt;/th&gt;
&lt;th&gt;과목 코드&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;CS101&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. ERD로 보는 정규화 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  ERD 예시&lt;/p&gt;
&lt;pre id=&quot;code_1744023167958&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[비정규형 (UNF)]
학번, 이름, 수강 과목(복수), 교수(복수)

&amp;darr; 원자값 분해

[1NF]
학번, 이름, 과목, 교수

&amp;darr; 부분 종속 제거

[2NF]
학생(학번, 이름)  
수강(학번, 과목, 성적)

&amp;darr; 이행 종속 제거

[3NF]
과목(과목, 교수)  
교수(교수, 사무실)

&amp;darr; 모든 결정자 &amp;rarr; 후보 키

[BCNF]
과목(과목 코드, 교수 코드)  
교수(교수 코드, 사무실)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학생이 수강한 과목과 교수 정보를 1NF &amp;rarr; BCNF까지 정규화한 결과입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LqzX6/btsNcEPmIp6/zEddIOOM0ZVoJau97UaoWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LqzX6/btsNcEPmIp6/zEddIOOM0ZVoJau97UaoWk/img.png&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;312&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.2127%; margin-right: 10px;&quot; data-widthpercent=&quot;32.59&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LqzX6/btsNcEPmIp6/zEddIOOM0ZVoJau97UaoWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLqzX6%2FbtsNcEPmIp6%2FzEddIOOM0ZVoJau97UaoWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;285&quot; height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpLKn5/btsNbRPhkIk/EfKSuFUqXJuJoidcQFAD61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpLKn5/btsNbRPhkIk/EfKSuFUqXJuJoidcQFAD61/img.png&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;280&quot; data-is-animation=&quot;false&quot; style=&quot;width: 66.6245%;&quot; data-widthpercent=&quot;67.41&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpLKn5/btsNbRPhkIk/EfKSuFUqXJuJoidcQFAD61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpLKn5%2FbtsNbRPhkIk%2FEfKSuFUqXJuJoidcQFAD61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;529&quot; height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;1NF, 2NF&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div id=&quot;code_1744028361481&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;iframe width=&amp;quot;560&amp;quot; height=&amp;quot;315&amp;quot; src='https://dbdiagram.io/e/67f3c1184f7afba1849efc0f/67f3c16c4f7afba1849f09f3'&amp;gt; &amp;lt;/iframe&amp;gt;&quot;&gt;&lt;iframe src=&quot;https://dbdiagram.io/e/67f3c1184f7afba1849efc0f/67f3c16c4f7afba1849f09f3&quot; width=&quot;560&quot; height=&quot;315&quot;&gt; &lt;/iframe&gt;&lt;/div&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;bull; 교수&amp;nbsp;이름이&amp;nbsp;바뀌면&amp;nbsp;&amp;rarr;&amp;nbsp;과목과의&amp;nbsp;관계가&amp;nbsp;모두&amp;nbsp;깨질&amp;nbsp;수&amp;nbsp;있음&lt;br /&gt;&amp;bull; 교수명이&amp;nbsp;유일하다는&amp;nbsp;보장도&amp;nbsp;없음&amp;nbsp;(김민수&amp;nbsp;교수&amp;nbsp;3명&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있음)&lt;br /&gt;&lt;b&gt;&amp;bull; 데이터&amp;nbsp;무결성&amp;nbsp;깨질&amp;nbsp;위험&amp;nbsp;+&amp;nbsp;변경&amp;nbsp;이상&amp;nbsp;발생&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;s&gt;틀린 그림 찾기가 아니라 '과목코드' '교수코드'가 추가됨.&amp;nbsp;&lt;/s&gt;&lt;/p&gt;
&lt;div id=&quot;code_1744040174563&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;iframe width=&amp;quot;560&amp;quot; height=&amp;quot;315&amp;quot; src='https://dbdiagram.io/e/67f3f0b04f7afba184a6ec82/67f3f0cc4f7afba184a6ef99'&amp;gt; &amp;lt;/iframe&amp;gt;&quot;&gt;&lt;iframe src=&quot;https://dbdiagram.io/e/67f3f0b04f7afba184a6ec82/67f3f0cc4f7afba184a6ef99&quot; width=&quot;560&quot; height=&quot;315&quot;&gt; &lt;/iframe&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;처음에는&amp;nbsp;하나의&amp;nbsp;테이블에&amp;nbsp;모든&amp;nbsp;정보가&amp;nbsp;들어&amp;nbsp;있었지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화&amp;nbsp;과정에서&amp;nbsp;학생,&amp;nbsp;수강,&amp;nbsp;과목,&amp;nbsp;교수로&amp;nbsp;분리되었고,&lt;br /&gt;각&amp;nbsp;테이블은&amp;nbsp;외래키(FK)를&amp;nbsp;통해&amp;nbsp;관계를&amp;nbsp;맺고&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BCNF에서는&amp;nbsp;&amp;ldquo;모든&amp;nbsp;결정자는&amp;nbsp;반드시&amp;nbsp;후보&amp;nbsp;키여야&amp;nbsp;한다&amp;rdquo;는&amp;nbsp;조건이&amp;nbsp;적용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;예를&amp;nbsp;들어&amp;nbsp;과목명이&amp;nbsp;교수님을&amp;nbsp;결정짓는다면,&amp;nbsp;과목명은&amp;nbsp;반드시&amp;nbsp;&lt;b&gt;후보&amp;nbsp;키&lt;/b&gt;여야&amp;nbsp;해요.&lt;br /&gt;이를&amp;nbsp;위해&amp;nbsp;&amp;lsquo;과목&amp;nbsp;코드&amp;rsquo;와&amp;nbsp;&amp;lsquo;교수&amp;nbsp;코드&amp;rsquo;&amp;nbsp;같은&amp;nbsp;&lt;b&gt;식별&amp;nbsp;가능한&amp;nbsp;속성&lt;/b&gt;으로&amp;nbsp;테이블을&amp;nbsp;재설계하게&amp;nbsp;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  여기서 잠깐! &lt;b&gt;식별 관계 vs 비식별 관계&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;ERD를 설계할 때, 테이블 간 연결 관계는 &lt;b&gt;식별 관계&lt;/b&gt;와 &lt;b&gt;비식별 관계&lt;/b&gt;로 나뉩니다.&amp;nbsp;&amp;nbsp;&lt;br /&gt;두 개념은 &lt;b&gt;외래키&lt;/b&gt;가 &lt;b&gt;기본키&lt;/b&gt;에 &lt;b&gt;포함되는지&lt;/b&gt; 여부에 따라 구분돼요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 58px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.687%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;구분&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.313%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;의미&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.3105%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;외래키 &lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;특징&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.6895%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;예시&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.687%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;식별&amp;nbsp;관계&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;(Identifying)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.313%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;부모 없이는 자식도 존재할 수 &lt;b&gt;없음&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.3105%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;외래키가 &lt;b&gt;기본키에 포함&lt;/b&gt;됨&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.6895%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;주문 &amp;rarr; 주문 상세&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 16.687%; height: 18px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;비식별&amp;nbsp;관계&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;(Non-identifying)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.313%; height: 18px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;부모 없어도 자식은 독립적으로 존재 &lt;b&gt;가능&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.3105%; height: 18px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;외래키는 일반 속성 &lt;br /&gt;(기본키 아님)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.6895%; height: 18px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;사용자 &amp;rarr; 게시글&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- &lt;b&gt;식별 관계&lt;/b&gt;: &amp;ldquo;부모 없으면 나도 없어&amp;rdquo; &amp;rarr; FK가 PK 안에 들어감&amp;nbsp;&amp;nbsp;&lt;br /&gt;- &lt;b&gt;비식별 관계&lt;/b&gt;: &amp;ldquo;부모 없어도 난 있어&amp;rdquo; &amp;rarr; FK는 그냥 참조용&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp; ㄴ &amp;ldquo;외래키는 일반 속성&amp;rdquo;이란? 비식별 관계에서는 외래키가 자식 테이블의 &lt;b&gt;기본키에 포함되지 않는다&lt;/b&gt; : 외래키는 그냥 &amp;ldquo;참조용&amp;rdquo;일 뿐이고, 그&amp;nbsp;자체가&amp;nbsp;이&amp;nbsp;테이블에서&amp;nbsp;행을&amp;nbsp;식별하는&amp;nbsp;기본키&amp;nbsp;역할을&amp;nbsp;하지는&amp;nbsp;않음&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;  예를 들어&lt;/b&gt;&lt;br /&gt;- `주문 상세`는 &lt;b&gt;해당 주문이 반드시 있어야만 존재&lt;/b&gt;할 수 있어요 &amp;rarr; 식별 관계&lt;br /&gt;- `게시글`은 작성한 사용자가 탈퇴해도 &lt;b&gt;게시글 자체는 남길 수 있어요&lt;/b&gt;&amp;nbsp;&amp;rarr; 비식별 관계&lt;br /&gt;&lt;br /&gt;식별&amp;nbsp;관계는&amp;nbsp;부모&amp;nbsp;테이블이&amp;nbsp;삭제되면&amp;nbsp;자식&amp;nbsp;테이블도&amp;nbsp;함께&amp;nbsp;사라질&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;구조로,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;생명선을&amp;nbsp;공유하며&amp;nbsp;논리적으로&amp;nbsp;완전&amp;nbsp;종속된&amp;nbsp;관계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;반면,&amp;nbsp;비식별&amp;nbsp;관계는&amp;nbsp;실무에서&amp;nbsp;더&amp;nbsp;자주&amp;nbsp;사용되며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;데이터&amp;nbsp;삭제나&amp;nbsp;수정&amp;nbsp;시에도&amp;nbsp;유지보수가&amp;nbsp;유연하고&amp;nbsp;독립성이&amp;nbsp;보장되는&amp;nbsp;장점이&amp;nbsp;있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 정규화 흐름도 요약&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9S24u/btsNbyWGU4g/mqsAostRGbZ8DYpkhkX9FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9S24u/btsNbyWGU4g/mqsAostRGbZ8DYpkhkX9FK/img.png&quot; data-alt=&quot;p.603&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9S24u/btsNbyWGU4g/mqsAostRGbZ8DYpkhkX9FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9S24u%2FbtsNbyWGU4g%2FmqsAostRGbZ8DYpkhkX9FK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;133&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;p.603&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  참고: &lt;b&gt;비정규형(UNF)&lt;/b&gt; 이란?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 셀에 여러 개의 값이 들어 있는 상태 (예: 전화번호: &quot;010-1111-2222, 010-3333-4444&quot;)&lt;/li&gt;
&lt;li&gt;정규화를 하기 전의 '지저분한 테이블' 상태예요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 1NF부터는 이걸 원자값으로 분해합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요약&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;1NF&lt;/b&gt;: 칸칸이 정리하자 (엑셀 한 셀에 값 하나씩)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2NF&lt;/b&gt;: 덜 중요한 건 따로 떼자 (부분 종속 분리)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3NF&lt;/b&gt;: 간접적인 연결은 없애자 (이행 종속 제거)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BCNF&lt;/b&gt;: 모든 기준이 진짜 고유해야 한다 (결정자 = 후보 키)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 역정규화는 언제 쓸까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  정규화에도 단점이 있다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블이 지나치게 분리되어 &lt;b&gt;JOIN이 많아지고 성능이 저하될 수 있어요&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;너무 많은 정규형을 적용하면 &lt;b&gt;데이터 구조가 복잡&lt;/b&gt;해져 개발자/쿼리 작성자 모두 힘들 수 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 그래서 실무에서는 '정규화 vs 역정규화'를 적절히 조절하는 게 핵심입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPOsgY/btsNcHyqLn4/sYC1zOe4JkI6XFJAPzNwW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPOsgY/btsNcHyqLn4/sYC1zOe4JkI6XFJAPzNwW0/img.png&quot; data-alt=&quot;p.604&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPOsgY/btsNcHyqLn4/sYC1zOe4JkI6XFJAPzNwW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPOsgY%2FbtsNcHyqLn4%2FsYC1zOe4JkI6XFJAPzNwW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;394&quot; height=&quot;185&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;p.604&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 정규화가 항상 좋은 건 아닙니다. 아래와 같은 경우에는 &lt;b&gt;역정규화&lt;/b&gt;가 필요할 수 있어요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JOIN이 너무 많아서 조회 성능이 떨어지는 경우&lt;/li&gt;
&lt;li&gt;분석/리포트 시스템처럼 빠른 읽기가 중요한 경우&lt;/li&gt;
&lt;li&gt;NoSQL 환경에서는 기본적으로 정규화를 하지 않기도 해요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 땐 의도적으로 중복을 허용하고, 테이블을 통합하기도 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 항상 BCNF까지 정규화를 할 필요는 없어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 무결성이 중요한 테이블은 정규화하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회 성능이 중요한 테이블은 역정규화하는 식의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;균형감 있는 설계가 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화는 단순히 테이블을 쪼개는 게 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 쪼개야 하는지, 어떤 문제가 생기기 때문인지&lt;/b&gt;를 이해하는 게 핵심입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000214014967&quot;&gt;이것이 취업을 위한 컴퓨터 과학이다&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tdan.com/normalizing-with-entity-relationship-diagramming/4583&quot;&gt;Normalizing with Entity Relationship Diagramming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wanderin.dev/databases/database-normalization-example/&quot;&gt;Database Design: Normalization Example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>bcnf</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>Denormalization</category>
      <category>NORMALIZATION</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/46</guid>
      <comments>https://readyoun.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 7 Apr 2025 16:55:17 +0900</pubDate>
    </item>
    <item>
      <title>효율적 쿼리란? - 서브쿼리와 조인, 뷰, 인덱스로 쿼리 최적화</title>
      <link>https://readyoun.tistory.com/45</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdSM62/btsNcTd1dVo/9Xd0KQ3TAxghK7S9Evjl10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdSM62/btsNcTd1dVo/9Xd0KQ3TAxghK7S9Evjl10/img.png&quot; data-alt=&quot;https://www.flaticon.com/free-icon/sql_9543826?related_id=9543826&amp;amp;amp;origin=search&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdSM62/btsNcTd1dVo/9Xd0KQ3TAxghK7S9Evjl10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdSM62%2FbtsNcTd1dVo%2F9Xd0KQ3TAxghK7S9Evjl10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;297&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.flaticon.com/free-icon/sql_9543826?related_id=9543826&amp;amp;origin=search&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;효율적 쿼리란 무엇일까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 수많은 데이터를 저장하고, 이 데이터에 대해 빠르고 정확한 응답을 제공해야 합니다. 하지만 단순히 작동하는 SQL 문을 작성하는 것만으로는 부족합니다. &lt;b&gt;&quot;어떻게 하면 더 빠르게, 더 적은 비용으로 원하는 결과를 가져올 수 있을까?&quot;&lt;/b&gt; 가 바로 효율적인 쿼리를 고민해야 하는 이유입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  참고: 이 글은 『이것이 취업을 위한 컴퓨터 과학이다』 CHAPTER 06, p.573 ~ p.592의 내용을 기반으로 한 설명입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[참고] 쿼리 실행 과정&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;SQL 문은 단순한 명령어처럼 보이지만, DB 내부에서는 복잡한 과정을 거칩니다. 실행 과정을 크게 요약하면 다음과 같습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #666666; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;파싱(Parsing)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; SQL 문법 분석 및 내부 표현으로 변환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화(Optimization)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; 실행 계획 수립 (인덱스, 조인 순서 고려)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행(Execution)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; 결정된 계획에 따라 쿼리 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 중 &quot;최적화&quot; 단계는 성능을 좌우하는 핵심입니다. 어떤 쿼리는 수천 배의 성능 차이를 만들 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿼리 최적화기(Query Optimizer)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 가능한 실행 경로 중 &lt;u&gt;비용이 가장 적은 계획&lt;/u&gt;을 선택합니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이때 비용은 CPU 연산, 디스크 I/O, 네트워크 트래픽 등을 기준으로 평가되며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;통계 정보(statistics)&lt;/b&gt;를 바탕으로 실행 계획을 세웁니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 데이터 양이 급변했거나, 통계 정보가 오래된 경우, 예상보다 비효율적인 계획이 선택될 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조와 실행 과정 참고 : &lt;a href=&quot;https://jaehoney.tistory.com/106&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Real MySQL - MySQL 기본 구조(+ 쿼리 실행 과정, 메모리 할당 구조, ...)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 서브쿼리와 조인 - 여러 테이블에 질의하려면&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 서브 쿼리 - 쿼리 안에 쿼리?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브쿼리는 &lt;u&gt;하나의 쿼리 안에서 또 다른 쿼리를 사용하는 방식&lt;/u&gt;입니다. 특히 &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt;절에서 활용할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev-jk93.tistory.com/22&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자세한 종류 : [SQL]&amp;nbsp;서브쿼리란?&amp;nbsp;서브쿼리&amp;nbsp;종류&amp;nbsp;-&amp;nbsp;스칼라,&amp;nbsp;인라인&amp;nbsp;뷰,&amp;nbsp;중첩&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책에서 다루는 대표 두 가지 유형이 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;SELECT문 안에 SELECT문이 포함된 서브 쿼리&lt;/li&gt;
&lt;li&gt;DELETE문 안에 SELECT문이 포함된 서브 쿼리&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;p.575 예제 - &quot;사용자 테이블의 각 사용자별 게시글 수를 함께 출력하려면?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT users.username,
       (SELECT COUNT(*)
        FROM posts
        WHERE posts.user_id = users.user_id) AS post_count
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;+----------+-------------+
| username | post_count  |
+----------+-------------+
| kim      | 2           |
| lee      | 1           |
| park     | 1           |
+----------+-------------+&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;또는 특정 사용자 이메일로 조건을 걸어 그 사람의 게시글을 모두 삭제하고 싶다면?&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;DELETE FROM posts
WHERE user_id = (
  SELECT user_id
  FROM users
  WHERE email = 'kim@example.com'
);&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브쿼리는 비상관 서브쿼리와 상관 서브쿼리로 나뉩니다. &lt;b&gt;비상관 서브쿼리&lt;/b&gt;는 외부 쿼리와 독립적으로 한 번만 실행되지만, &lt;b&gt;상관 서브쿼리&lt;/b&gt;는 외부 쿼리의 각 행에 대해 반복 실행되므로 성능에 악영향을 줄 수 있습니다. 예를 들어 다음과 같은 형태는 성능상 좋지 않을 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT name FROM student s 
WHERE kor &amp;gt; (SELECT AVG(kor) FROM student WHERE class_id = s.class_id);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;상관 쿼리 vs 비상관 쿼리&amp;nbsp;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mungiyo.tistory.com/41#%EB%B9%84%EC%83%81%EA%B4%80%20%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 : SQL 튜닝 용어 정리(2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.inflearn.com/community/questions/1180399/%EC%83%81%EA%B4%80%EC%BF%BC%EB%A6%AC%EC%99%80-%EB%B9%84%EC%83%81%EA%B4%80%EC%BF%BC%EB%A6%AC%EC%9D%98-%EC%93%B0%EC%9E%84%EC%83%88%EA%B0%80-%ED%97%B7%EA%B9%94%EB%A6%BD%EB%8B%88%EB%8B%A4?focusComment=318657&amp;amp;srsltid=AfmBOoqgStfqUMGKXzlc1pkguG1feyF3zRI1eS-yw77Sv80aYp1-XNp7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;상관쿼리와&amp;nbsp;비상관쿼리의&amp;nbsp;쓰임새가&amp;nbsp;헷깔립니다.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 조인 - 테이블을 연결하는 더 효율적인 방법은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조인은 &lt;u&gt;여러 테이블 간의 연관 데이터를 결합하는 방식&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용자와 게시글 테이블을 조인해 사용자 이름과 게시글 제목을 함께 출력하려면?&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT users.username, users.email, posts.title
FROM users, posts
WHERE users.user_id = posts.user_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;+----------+------------------+-------------------------------+
| username | email            | title                         |
+----------+------------------+-------------------------------+
| kim      | kim@example.com  | One                           |
| kim      | kim@example.com  | Two                           |
| lee      | lee@example.com  | Three                         |
| park     | park@example.com | Four                          |
+----------+------------------+-------------------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;INNER JOIN을 명시적으로 사용해도 되는데, 보통 INNER 를 생략하기도 합니다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT customers.name, customers.age, customers.email,
       orders.product_id, orders.quantity, orders.amount
FROM customers
INNER JOIN orders
ON customers.id = orders.customer_id;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조인에는 다양한 종류가 있습니다.&lt;/p&gt;
&lt;table style=&quot;height: 100px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;종류&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;INNER&lt;/b&gt; JOIN&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;테이블 A와 B의 레코드 중 조인 조건을 모두 만족하는 레코드만 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;LEFT OUTER&lt;/b&gt; JOIN&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;테이블 A의 모든 레코드 + 조인 조건 만족하는 B의 레코드. 만족 못 하면 B는 NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;RIGHT OUTER&lt;/b&gt; JOIN&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;테이블 B의 모든 레코드 + 조인 조건 만족하는 A의 레코드. 만족 못 하면 A는 NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;FULL OUTER&lt;/b&gt; JOIN&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;A와 B 모두의 모든 레코드를 포함. 어느 한쪽이 없으면 상대는 NULL로 채워짐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❗ 유의사항:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조인 조건 누락 시 &lt;b&gt;카티션 곱(Cartesian Product)&lt;/b&gt; 발생 &amp;rarr; 폭발적인 행 수 증가!&lt;/li&gt;
&lt;li&gt;항상 ON 조건 또는 USING을 명확히 지정해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;카티션 곱(Cartesian Product) 발생 가능성과 그로 인한 성능 문제&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;카티션 곱은 조인 조건이 누락되었을 때 발생하며, 두 테이블의 모든 행을 조합하여 결과를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 테이블 A에 1,000개의 행이 있고 테이블 B에 500개의 행이 있다면, 카티션 곱은 1,000 &amp;times; 500 = 500,000개의 행을 반환하게 됩니다. 이러한 결과는 데이터베이스 서버에 과도한 부하를 주고 쿼리 실행 시간을 크게 증가시킬 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;SELECT * FROM table1, table2;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 쿼리는 조인 조건이 없으므로 카티션 곱을 생성합니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;카티션 곱을 방지하기 위한 방법은 항상 조인 조건을 명확히 지정하는 것입니다. SQL에서 ON 또는 USING 절을 사용하여 테이블 간의 관계를 정의해야 합니다. 조건이 명확하지 않으면 SQL은 기본적으로 모든 행을 조합하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;CROSS JOIN으로 처리합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▶ &lt;b&gt;LEFT OUTER JOIN 예제 (p.582)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT customers.name, orders.id AS order_id, orders.product_id,
       orders.quantity, orders.amount
FROM customers
LEFT OUTER JOIN orders
ON customers.id = orders.customer_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▶ &lt;b&gt;RIGHT OUTER JOIN 예제 (p.582)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT customers.name, orders.id AS order_id, orders.product_id,
       orders.quantity, orders.amount
FROM customers
RIGHT OUTER JOIN orders
ON customers.id = orders.customer_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❗ LEFT vs RIGHT OUTER JOIN 유의점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JOIN 순서가 바뀌면 결과도 바뀜 &amp;rarr; 기준이 되는 테이블이 무엇인지 항상 확인할 것&lt;/li&gt;
&lt;li&gt;가독성, 명확한 의도를 위해 LEFT JOIN을 선호하고, RIGHT JOIN은 최소화하는 것이 일반적&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;height: 80px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;항목&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;LEFT OUTER JOIN&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;RIGHT OUTER JOIN&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;기준 테이블&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;왼쪽 테이블(LEFT)이 기준&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;오른쪽 테이블(RIGHT)이 기준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;NULL 채워짐&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;오른쪽 테이블의 매칭 안 되는 값&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;왼쪽 테이블의 매칭 안 되는 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;사용 예&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;고객은 있지만 주문 없는 경우 포함&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;주문은 있지만 고객 정보 없는 경우 포함 (드묾)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▶ &lt;b&gt;FULL OUTER JOIN 구현 예시 (p.583)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT customers.name, orders.id AS order_id, orders.product_id,
       orders.quantity, orders.amount
FROM customers
LEFT OUTER JOIN orders ON customers.id = orders.customer_id
UNION
SELECT customers.name, orders.id AS order_id, orders.product_id,
       orders.quantity, orders.amount
FROM customers
RIGHT OUTER JOIN orders ON customers.id = orders.customer_id;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FULL OUTER JOIN은 MySQL에서 직접 지원되지 않기 때문에 &lt;br /&gt;위와 같이 LEFT JOIN + RIGHT JOIN + &lt;b&gt;UNION&lt;/b&gt;을 조합하여 구현합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▶ &lt;b&gt;JOIN으로 서브쿼리 대체 (p.583)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;SELECT users.username, COUNT(posts.post_id) AS post_count
FROM users
LEFT JOIN posts ON users.user_id = posts.user_id
GROUP BY users.username;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 사용한 서브쿼리 기반 카운트 쿼리를 JOIN과 GROUP BY를 통해 동일하게 구현할 수 있습니다. 이 방식은 &lt;b&gt;보다 효율적이며 명확한 실행 계획&lt;/b&gt;을 만들어주는 장점이 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 뷰(View) - 뷰는 왜 필요할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰(View)는 테이블처럼 사용 가능한 &lt;b&gt;가상의 테이블&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 쿼리를 단순화하고, 보안을 강화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자와 게시글을 조인한 결과를 뷰로 저장하고 활용하려면?&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;CREATE VIEW myview AS
SELECT users.username, users.email, posts.title
FROM users, posts
WHERE users.user_id = posts.user_id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 뷰를 이용한 조회 예시:&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT username, email, title
FROM myview
WHERE username = 'kim';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰는 &lt;code&gt;SHOW TABLES&lt;/code&gt; 명령어를 통해 확인 가능:&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;mysql&amp;gt; SHOW TABLES;
+----------------+
| Tables_in_mydb |
+----------------+
| myview         |
| posts          |
| users          |
+----------------+&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❗ 유의사항:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰는 실제 데이터를 저장하지 않음 &amp;rarr; &lt;b&gt;원본 테이블 변경 시 함께 변경됨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;복잡한 뷰에 대해 또 JOIN하면 &lt;b&gt;실행 성능에 주의&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;여러 테이블을 조인한 뷰에서는 갱신이 제한될 수 있음&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/9433190/mysql-multi-update-error&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ERROR 1393 (HY000): Can not modify more than one base table through a join view&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰는 보안과 재사용성 관점에서 유용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;민감한 정보를 제외한 컬럼만 노출 가능&lt;/li&gt;
&lt;li&gt;복잡한 조인 쿼리를 캡슐화하여 코드의 가독성과 유지보수성 향상&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GRANT&lt;/code&gt;를 통해 특정 사용자에게만 접근 권한 부여 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 인덱스 - 왜 빠른 걸까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스는 테이블의 특정 컬럼에 대한 &lt;b&gt;검색 속도를 향상&lt;/b&gt;시키는 &lt;code&gt;자료구조&lt;/code&gt;입니다. 일종의 책의 목차라고 생각할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 인덱스의 성능 영향&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예제로 인덱스가 성능에 미치는 영향을 확인해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- 테이블에 70만 개의 행이 있는 상태
SELECT COUNT(*) FROM users;
-- 결과: 700000 rows in set (0.86 sec)

-- 인덱스 없이 조건 검색
SELECT * FROM users WHERE nickname='User290562U';
-- 결과: 1 row in set (0.21 sec)

-- 인덱스 생성
CREATE INDEX idx_user ON users(nickname);

-- 다시 실행
SELECT * FROM users WHERE nickname='User290562U';
-- 결과: 1 row in set (0.00 sec)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 사용하면 &lt;b&gt;전체 테이블 탐색(Full Table Scan)&lt;/b&gt; 대신 인덱스를 통해 바로 데이터 위치를 찾을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, &lt;code&gt;SELECT *&lt;/code&gt;와 같은 경우 인덱스만으로는 모든 데이터를 가져올 수 없어 &lt;b&gt;테이블 접근이 추가로 필요합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 인덱스 종류와 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인덱스의 종류&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터형 인덱스(Clustered&amp;nbsp;Index)는 기본 키(primary key)에 적합하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세컨더리 인덱스(Secondary Index, Non-Clustered Index)는 다양한 쿼리를 처리하기 위한 보조 도구로 활용됩니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;&lt;b&gt;클러스터형&lt;/b&gt; 인덱스&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;실제 데이터가 인덱스 순서대로 정렬됨 (MySQL InnoDB 기본값)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.5117%;&quot;&gt;&lt;b&gt;세컨더리&lt;/b&gt; 인덱스&lt;/td&gt;
&lt;td style=&quot;width: 78.4883%;&quot;&gt;별도 인덱스 구조에 실제 데이터 위치를 가리킴&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dev-jwblog.tistory.com/162&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자세히 보기 : [MySQL] Clustered Index와 Secondary Index 정리&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인덱스 자료구조&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;B-Tree&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;균형 이진 트리의 일반화 형태&lt;/li&gt;
&lt;li&gt;범위 검색과 정렬이 가능&lt;/li&gt;
&lt;li&gt;루트 &amp;rarr; 내부 노드 &amp;rarr; 리프 노드 구조&lt;/li&gt;
&lt;li&gt;검색/삽입/삭제 모두 &lt;code&gt;O(log n)&lt;/code&gt; 시간 복잡도&lt;/li&gt;
&lt;li&gt;RDBMS의 기본 인덱스 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;&lt;a href=&quot;https://velog.io/@juhyeon1114/MySQL-Index%EC%9D%98-%EA%B5%AC%EC%A1%B0-B-Tree-BTree&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[MySQL]&amp;nbsp;Index의&amp;nbsp;구조&amp;nbsp;:&amp;nbsp;B-Tree,&amp;nbsp;B+Tree&lt;/a&gt;&lt;br /&gt;- &lt;a href=&quot;https://zorba91.tistory.com/293&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[MySQL] B-tree, B+tree란? (인덱스와 연관지어서)&lt;/a&gt;&lt;br /&gt;- &lt;a href=&quot;https://mangkyu.tistory.com/286&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[MySQL] B-Tree로 인덱스(Index)에 대해 쉽고 완벽하게 이해하기&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Hash Table&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정확히 일치하는 키 검색에 특화&lt;/li&gt;
&lt;li&gt;범위 검색 불가&lt;/li&gt;
&lt;li&gt;NoSQL에서 주로 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;잼씀: &lt;a href=&quot;https://jiwondev.tistory.com/112&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DB 인덱스에서는 왜 HashTable을 사용하지 않을까?&lt;/a&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 인덱스 사용 시 고려사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인덱스가 적용되는 조건:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WHERE, JOIN, ORDER BY 절에 사용된 컬럼&lt;/li&gt;
&lt;li&gt;LIKE 검색은 접두어 기준일 때만 (&lt;code&gt;LIKE 'A%'&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;함수 적용 컬럼에는 적용 안 됨 (&lt;code&gt;WHERE UPPER(name) = 'ROBIN'&lt;/code&gt; ❌)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의사항:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;INSERT/UPDATE/DELETE 시 인덱스도 갱신 필요 &amp;rarr; 쓰기 성능 저하&lt;/li&gt;
&lt;li&gt;인덱스가 많으면 Optimizer가 최적 인덱스 선택을 못할 수 있음&lt;/li&gt;
&lt;li&gt;자주 변경되는 컬럼(예: 로그인 실패 횟수)은 인덱스 설정 신중히 고려&lt;/li&gt;
&lt;li&gt;다중 컬럼 인덱스는 컬럼 순서가 성능에 큰 영향&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXPLAIN&lt;/code&gt;으로 인덱스 사용 여부 확인 필수&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EXPLAIN&lt;/b&gt;은 &lt;u&gt;SQL 쿼리의 실행 계획&lt;/u&gt;을 미리 확인하는 도구다. 인덱스가 쓰였는지, 조인이 어떻게 수행되는지, 몇 행을 탐색하는지 알 수 있다. 성능 개선(쿼리 튜닝)에서는 무조건 확인해야 할 1순위 도구다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론&lt;/b&gt;: 자주 조회되지만 변경이 적은 컬럼 위주로 선택적 인덱스 생성이 중요합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리하며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효율적인 쿼리 작성은 데이터베이스 성능을 최적화하고 애플리케이션의 응답 시간을 줄이는 데 매우 중요합니다. 잘 설계된 쿼리는 불필요한 데이터 검색과 연산을 최소화하여 서버의 부하를 줄이고, 시스템 자원을 효율적으로 활용할 수 있게 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 비효율적인 쿼리는 과도한 I/O 작업과 CPU 사용을 초래하며, 데이터베이스의 성능 저하와 비용 증가로 이어질 수 있습니다. 이를 방지하기 위해 인덱스 활용, 필요한 컬럼만 조회, 조인 및 서브쿼리 최적화, 실행 계획 분석 등 다양한 최적화 기법을 적용해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 단지 SQL이 동작하는 것에 만족하지 말고, &lt;b&gt;동시에 얼마나 빠르고 효율적으로 동작하는가&lt;/b&gt;를 고민해야 합니다. 데이터가 적을 때는 문제가 없어 보여도, 데이터가 많아질수록 설계 미비는 곧바로 성능 저하로 나타납니다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;요약&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 효율적 쿼리란?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 결과를 더 빠르고, 더 적은 비용으로 얻는 SQL&lt;/li&gt;
&lt;li&gt;실행 계획 최적화가 핵심 (쿼리 옵티마이저, 통계 정보)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  서브쿼리 vs 조인&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상관 서브쿼리는 행마다 서브쿼리 실행 &amp;rarr; 느림&lt;/li&gt;
&lt;li&gt;JOIN + GROUP BY는 집합 기반 연산 &amp;rarr; 더 효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  OUTER JOIN 종류&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LEFT JOIN: 왼쪽 테이블 기준, 없는 값은 NULL&lt;/li&gt;
&lt;li&gt;RIGHT JOIN: 오른쪽 테이블 기준 (덜 선호됨)&lt;/li&gt;
&lt;li&gt;FULL OUTER JOIN: MySQL은 UNION으로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;zwj;  VIEW 사용법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 SELECT를 재사용 가능한 가상 테이블로&lt;/li&gt;
&lt;li&gt;보안과 쿼리 간결화에 유용하지만 갱신 제약 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚡ 인덱스 최적화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;B-Tree 기반, 검색 속도 비약적 향상&lt;/li&gt;
&lt;li&gt;SELECT, WHERE, ORDER BY 등에서 유리&lt;/li&gt;
&lt;li&gt;너무 많은 인덱스 = 오히려 비효율 (쓰기 성능 저하)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  팁&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EXPLAIN으로 쿼리 실행 계획을 꼭 확인하자!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000214014967&quot;&gt;이것이 취업을 위한 컴퓨터 과학이다&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>Index</category>
      <category>Join</category>
      <category>query</category>
      <category>sql</category>
      <category>subquery</category>
      <category>view</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/45</guid>
      <comments>https://readyoun.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 7 Apr 2025 15:20:47 +0900</pubDate>
    </item>
    <item>
      <title>웹 개발자라면 꼭 알아야 할 데이터베이스 기초 정리</title>
      <link>https://readyoun.tistory.com/44</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;254&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/File:DB-database-icon.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qSWzr/btsNb9nIgBf/ucWC7mFjOrFq84kZ7rO5sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqSWzr%2FbtsNb9nIgBf%2FucWC7mFjOrFq84kZ7rO5sK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;358&quot; height=&quot;254&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;From Wikipedia, the free encyclopedia&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 데이터베이스가 중요한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서비스를 개발하다 보면 사용자 정보, 게시글, 주문 내역 등 수많은 데이터를 다루게 됩니다. 이 데이터를 안전하고 안정적으로 관리하기 위해 반드시 필요한 것이 바로 &lt;b&gt;데이터베이스(Database)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스란, &lt;b&gt;여러 사람이 공유하고 사용할 목적으로 체계화된 데이터의 집합&lt;/b&gt;이며, 이러한 데이터를 효율적으로 저장, 수정, 조회할 수 있도록 돕는 프로그램이 바로 &lt;b&gt;DBMS(Database Management System)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 데이터베이스는 단순한 저장 공간이 아니라, 웹 서비스의 핵심 기반 인프라입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. DBMS의 종류와 RDBMS가 중요한 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS는 크게 두 가지로 나뉩니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;관계형 DBMS(RDBMS)&lt;/b&gt;: MySQL, Oracle, PostgreSQL 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비관계형 DBMS(NoSQL)&lt;/b&gt;: MongoDB, Redis 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년 개발자 설문조사에 따르면, &lt;b&gt;관계형 데이터베이스가 가장 널리 사용되고 있으며&lt;/b&gt;, 특히 &lt;b&gt;MySQL은 오픈소스이자 높은 점유율&lt;/b&gt;을 자랑합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  신입 개발자라면 RDBMS부터 익히는 것이 실무 진입에 유리합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. DBMS의 역할과 SQL&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS는 단순히 데이터를 저장하는 것에서 그치지 않고, &lt;b&gt;응용 프로그램과 상호작용하며 데이터를 효율적으로 관리&lt;/b&gt;합니다.&lt;br /&gt;이때 사용하는 언어가 바로 &lt;b&gt;SQL(Structured Query Language)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL은 다음과 같은 언어로 구성됩니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DDL (데이터 정의어)&lt;/b&gt;: 테이블 생성/수정/삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DML (데이터 조작어)&lt;/b&gt;: 데이터 조회/삽입/수정/삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DCL (데이터 제어어)&lt;/b&gt;: 권한 부여/회수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TCL (트랜잭션 제어어)&lt;/b&gt;: COMMIT, ROLLBACK 등&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  SQL은 면접에서도 자주 등장하는 핵심 기술입니다. 실무 SQL 작성에 익숙해지는 것이 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 파일 시스템과 데이터베이스는 어떻게 다를까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 프로젝트에서는 데이터를 JSON이나 텍스트 파일로 저장할 수도 있습니다. 하지만 이런 &lt;b&gt;파일 시스템은 데이터의 중복, 무결성, 검색 효율성, 백업 문제&lt;/b&gt;에 취약합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 데이터베이스는 다음과 같은 이유로 더 적합합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터의 &lt;b&gt;일관성&lt;/b&gt; 유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복 저장 방지&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정교한 조건 검색&lt;/b&gt; 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 처리 및 복구 기능&lt;/b&gt; 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  = 파일 시스템 |  ️ = 데이터베이스&lt;br /&gt;✅ 실제 서비스 운영에는 데이터베이스가 필수입니다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 데이터베이스의 저장 단위와 트랜잭션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 다음과 같은 구조로 데이터를 관리합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스키마(Schema)&lt;/b&gt;: 데이터베이스 구조 정의&lt;/li&gt;
&lt;li&gt;&lt;b&gt;엔티티(Entity)&lt;/b&gt;: 실제 데이터가 저장되는 단위 (ex. 테이블)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 데이터베이스와의 &lt;b&gt;논리적 작업 단위&lt;/b&gt;를 &lt;b&gt;트랜잭션(Transaction)&lt;/b&gt; 이라고 하며, 다음 네 가지 특성(ACID)을 보장해야 합니다. 자세한 설명은 &lt;b&gt;9. 트랜잭션과 ACID&lt;/b&gt;에서 이어집니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Atomicity(원자성)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Consistency(일관성)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Isolation(격리성)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Durability(지속성)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  트랜잭션은 실시간 데이터 처리에서 신뢰성을 보장하는 핵심 기능입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 데이터베이스 설계와 무결성 제약 조건&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효율적인 DB 설계를 위해선 다음을 고려해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 &lt;b&gt;테이블&lt;/b&gt;이 필요한가?&lt;/li&gt;
&lt;li&gt;테이블 간 &lt;b&gt;관계(Relation)&lt;/b&gt; 는 어떤가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;무결성 제약 조건&lt;/b&gt;은 무엇인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무결성 제약 조건의 종류는 다음과 같습니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;제약 조건 종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;도메인 제약&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;값의 데이터 타입 제한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;키 제약&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;유일한 값을 보장 (기본키 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;엔티티 무결성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기본키는 NULL이 될 수 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;참조 무결성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;외래키는 실제 존재하는 값만 참조 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  좋은 설계는 불필요한 중복을 줄이고, 데이터 정합성을 높입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. SQL의 주요 명령어 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 SQL 주요 명령어 유형과 그 역할입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ DDL (데이터 정의어)&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CREATE TABLE users (...);
ALTER TABLE users ADD COLUMN age INT;
DROP TABLE users;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ DML (데이터 조작어)&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT * FROM users;
INSERT INTO users VALUES (...);
UPDATE users SET age = 30 WHERE id = 1;
DELETE FROM users WHERE id = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ TCL (트랜잭션 제어어)&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 또는 ROLLBACK;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  실무에서는 DML과 TCL이 가장 자주 사용되며, 트랜잭션 처리가 중요한 역할을 합니다.&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 관계형 DB vs NoSQL &amp;ndash; 상황에 따라 달라지는 선택&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 데이터베이스(RDBMS)는 &lt;b&gt;정형 데이터&lt;/b&gt;, &lt;b&gt;복잡한 관계&lt;/b&gt;, &lt;b&gt;데이터 정합성&lt;/b&gt;이 중요한 시스템에 적합합니다. 테이블 간 관계(1:N, M:N)를 명확하게 설정하고, SQL을 통해 조인, 서브쿼리 등을 활용한 정교한 데이터 처리도 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, NoSQL은 &lt;b&gt;유연한 스키마&lt;/b&gt; 구조와 &lt;b&gt;수평 확장성&lt;/b&gt;이 강점입니다. JSON 형태의 비정형 데이터를 저장할 수 있고, MongoDB나 Redis는 실시간 처리, 캐싱, 로그 저장 등에서 유용하게 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로, 정형 데이터를 주로 다루는 회원관리, 게시판, 주문 처리 등의 시스템에서는 RDBMS가 자연스럽게 선택되며, 복잡한 데이터 구조를 설계하고 관리하는 데 유리합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  정리하자면, &lt;b&gt;데이터의 구조, 읽기/쓰기 패턴, 확장성 요건, 일관성 요구 수준&lt;/b&gt;을 기준으로 적절한 DBMS를 선택하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 트랜잭션과 ACID &amp;ndash; 신뢰할 수 있는 데이터 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션에서 사용자 요청이 DB로 이어질 때, &lt;b&gt;대부분의 조작은 트랜잭션 단위로 처리됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;계좌 이체&lt;/b&gt;처럼 &lt;u&gt;두 테이블에 동시에 영향을 미치는 작업&lt;/u&gt;은 &lt;b&gt;중간에 실패할 경우 모든 처리가 롤백되어야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션의 4가지 핵심 속성(ACID)은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Atomicity (원자성)&lt;/b&gt;: 전체 작업이 전부 수행되거나 전혀 수행되지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Consistency (일관성)&lt;/b&gt;: 트랜잭션 전후에 DB 상태가 유효해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Isolation (격리성)&lt;/b&gt;: 동시에 실행되는 트랜잭션이 서로 간섭하지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Durability (지속성)&lt;/b&gt;: 커밋된 데이터는 시스템 장애에도 보존됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java/Spring 기반의 ERP 시스템 개발 프로젝트에서 생산관리 도메인을 담당하며 &lt;b&gt;트랜잭션의 필요성을 직접 체감&lt;/b&gt;하기도 했는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 하나의 생산 지시가 생성될 때는 다음과 같은 일련의 작업이 함께 수행됩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;생산 지시 등록&lt;/li&gt;
&lt;li&gt;관련 자재 차감 처리&lt;/li&gt;
&lt;li&gt;작업 지시 등록 및 설비 배정&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 한 단계라도 실패할 경우, 전체 작업이 롤백되지 않으면 &lt;b&gt;데이터 정합성이 깨지고, 재고 수량이나 작업 이력이 실제와 불일치&lt;/b&gt;하는 문제가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 ERP 시스템은 &lt;b&gt;운영 데이터가 즉시 현장 업무와 연결되기 때문에&lt;/b&gt;, 일관성 있는 트랜잭션 처리가 필수적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황을 고려해, 실제 프로젝트에서는 주요 비즈니스 로직을 하나의 서비스 계층에서 묶고, Spring에서 제공하는 &lt;code&gt;@Transactional&lt;/code&gt; 기반의 트랜잭션 처리를 적용할 수 있도록 설계했습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Transactional
public void processProductionOrder(ProductionOrderRequest request) {
    productionOrderRepository.save(...);   // 생산 지시 등록
    materialService.deductMaterial(...);   // 자재 차감
    workService.createWorkAssignment(...); // 작업 지시 및 설비 할당
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 실제 구현과는 다르지만, 당시 제가 설계에 접근한 방식을 설명하기 위한 예시입니다. 실제로는 모듈별 책임이 분리되어 있었고, 트랜잭션 범위도 세분화되어 관리되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경험을 통해, 트랜잭션은 단순한 기술 요소를 넘어 &lt;u&gt;업무의 신뢰성과 품질을 보장하는 핵심적인 설계 고려사항&lt;/u&gt;이라는 점을 배웠습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  특히 트랜잭션은 장애 상황, 예외 처리와도 밀접하게 연결되기 때문에, 단순한 개념이 아닌 실무적인 맥락 속에서 체득하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #000000; text-align: left;&quot;&gt;  데이터 정합성이란?&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ERP 시스템과 같은 업무 중심 애플리케이션에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터 정합성(Data Integrity)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 매우 중요합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정합성이란 쉽게 말해, 데이터가 서로 모순되지 않고 실제 업무 흐름과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;논리적으로 일치하는 상태&lt;/b&gt;를 의미합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 생산 지시가 생성되었는데 자재는 차감되지 않았거나, 작업 지시가 없는데 생산 결과가 등록된 경우는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정합성이 깨진 상태&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 개념은 흔히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ACID 트랜잭션의 일관성(Consistency)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;과 혼동되기도 하지만, 조금 다른 의미를 가집니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ACID에서 말하는 일관성은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;트랜잭션 전과 후의 데이터가 정해진 규칙(제약 조건, 트리거 등)을 항상 만족하는 상태&lt;/b&gt;를 말합니다. 예를 들어, 외래키 제약 조건이 깨지지 않는 것, 숫자 필드에 문자열이 들어가지 않는 것이죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터 정합성은 시스템 전반의 '업무적 논리'까지 포함하는 더 넓은 개념&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;즉, 트랜잭션이 일관성을 만족한다고 해서 정합성이 항상 보장되는 것은 &lt;b&gt;아닙니다&lt;/b&gt;.&lt;/u&gt; 여러 트랜잭션이 모여 하나의 비즈니스 흐름을 만들기 때문에, 이들 간의 연결 상태까지 고려해야 진정한 의미의 데이터 정합성을 확보할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; &amp;nbsp;정합성은&amp;nbsp;&lt;u&gt;비즈니스&amp;nbsp;현실과&amp;nbsp;데이터의&amp;nbsp;싱크를&amp;nbsp;맞추는&amp;nbsp;작업&lt;/u&gt;이고,&lt;br /&gt;⚙️&amp;nbsp;ACID의&amp;nbsp;일관성은&amp;nbsp;&lt;u&gt;그&amp;nbsp;데이터가&amp;nbsp;시스템&amp;nbsp;내부&amp;nbsp;규칙을&amp;nbsp;지키는지를&amp;nbsp;보장하는&amp;nbsp;메커니즘&lt;/u&gt;입니다.&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  ACID의 각 특성과 정합성 비교 정리&lt;/h4&gt;
&lt;br /&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%; height: 223px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;항목&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;의미&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;중점&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;예시&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;키워드&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;b&gt;Atomicity (원자성)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;트랜잭션 내 모든 작업이 전부 수행되거나 전혀 수행되지 않아야 함&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;작업의 일괄성&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;자재 차감 중 오류 &amp;rarr; 생산 지시도 취소됨&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&quot;All or Nothing&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;b&gt;Consistency (일관성)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;트랜잭션 전후 DB가 항상 유효한 상태여야 함&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;제약 조건, 규칙&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;외래키 위반 없이 정상 입력됨&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;정해진 룰을 만족하는지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;b&gt;Isolation (격리성)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;여러 트랜잭션이 동시에 실행돼도 서로 간섭하지 않음&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;동시성 보장&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;동시에 재고 차감 시 충돌 방지&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;트랜잭션 간 간섭 방지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;b&gt;Durability (지속성)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;커밋된 데이터는 시스템 장애에도 유지됨&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;장애 복원&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;전원 꺼져도 커밋된 생산이력 보존&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;영속 저장 보장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 43px;&quot;&gt;
&lt;td style=&quot;height: 43px;&quot;&gt;&lt;b&gt;  정합성 (Integrity)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 43px;&quot;&gt;데이터가 현실 업무 흐름과 모순되지 않도록 유지됨&lt;/td&gt;
&lt;td style=&quot;height: 43px;&quot;&gt;업무 논리&lt;/td&gt;
&lt;td style=&quot;height: 43px;&quot;&gt;생산 지시 있음 &amp;rarr; 자재 차감 반드시 수행&lt;/td&gt;
&lt;td style=&quot;height: 43px;&quot;&gt;여러 트랜잭션의 의미적 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;✔️&amp;nbsp;ACID는&amp;nbsp;&lt;u&gt;DB&amp;nbsp;내부&amp;nbsp;동작의&amp;nbsp;신뢰성을&amp;nbsp;위한&amp;nbsp;기술적&amp;nbsp;개념&lt;/u&gt;이고,&lt;br /&gt; &amp;nbsp;정합성은&amp;nbsp;&lt;u&gt;'현실&amp;nbsp;업무와&amp;nbsp;데이터가&amp;nbsp;맞물리는가'에&amp;nbsp;대한&amp;nbsp;비즈니스적&amp;nbsp;검증&lt;/u&gt;입니다.&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ERP나 실시간 재고 시스템처럼 다수의 트랜잭션이 유기적으로 연결된 도메인에서는&lt;br /&gt;ACID만으로는 부족하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정합성 검증 로직&lt;/b&gt;을 따로 구성해야 할 때도 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 생산 지시 등록 트랜잭션은 성공했지만 자재 차감 트랜잭션은 실패한 경우,&lt;br /&gt;&lt;b&gt;기술적으로는 문제없는 상태일지라도, 업무 관점에서는 모순된 데이터가 생성된 것&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이런 부분을 검증하고 복구할 수 있는 흐름 설계가 바로 실전 트랜잭션 설계의 핵심입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 파일 시스템 대신 데이터베이스를 선택하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 프로젝트를 시작할 때는 간단한 데이터를 파일(JSON, CSV 등)에 저장해도 괜찮아 보입니다. 하지만 프로젝트가 커지면서 다음과 같은 문제가 발생합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 조건으로 데이터를 검색하기 어렵고,&lt;/li&gt;
&lt;li&gt;데이터 중복이 자주 발생하며,&lt;/li&gt;
&lt;li&gt;누락되거나 깨진 데이터가 복구되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 저장 방식이 가진 한계입니다. 그러니 필수적으로 RDBMS를 활용하여 데이터의 무결성과 일관성을 확보해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 정규화를 적용해 중복을 최소화하고, 참조 무결성을 통해 잘못된 관계를 막는 설계 방식은 &lt;b&gt;서비스 안정성과 유지보수 측면에서 큰 차이&lt;/b&gt;를 만들어낼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리하며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 단지 데이터를 담아두는 공간이 아니라, &lt;b&gt;웹 서비스의 신뢰성과 확장성을 책임지는 중심 축&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 설계부터 실제 운용, 장애 대응까지 폭넓게 영향을 미치기 때문에, 기본 개념은 물론 실무 상황에 대한 감각까지 갖춰야 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000214014967&quot;&gt;이것이 취업을 위한 컴퓨터 과학이다&lt;/a&gt; Chapter 6. 데이터베이스&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>Acid</category>
      <category>data</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>Integrity</category>
      <category>sql</category>
      <category>Transaction</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/44</guid>
      <comments>https://readyoun.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 7 Apr 2025 11:57:45 +0900</pubDate>
    </item>
    <item>
      <title>프록시와 스케일링: 안정적인 트래픽 처리</title>
      <link>https://readyoun.tistory.com/43</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;627&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NYoYY/btsMVCkULKC/l6Kf2mCkjKtD8SNo6TKvBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NYoYY/btsMVCkULKC/l6Kf2mCkjKtD8SNo6TKvBK/img.png&quot; data-alt=&quot;https://www.techbuyer.com/au/blog/what-is-a-proxy-server&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NYoYY/btsMVCkULKC/l6Kf2mCkjKtD8SNo6TKvBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNYoYY%2FbtsMVCkULKC%2Fl6Kf2mCkjKtD8SNo6TKvBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;627&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.techbuyer.com/au/blog/what-is-a-proxy-server&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트래픽이 몰리는 순간, 시스템은 어떻게 안정성을 유지할까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드 아키텍처에서 핵심이 되는 개념인 &lt;b&gt;프록시, 로드 밸런서, 스케일링 전략&lt;/b&gt;을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;『이것이 취업을 위한 컴퓨터 과학이다』 5-7절 내용을 바탕으로 정리합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 오리진 서버와 중간 서버: 포워드 프록시와 리버스 프록시&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnBGKx/btsMVavGbuJ/hqM3GDlTbl1Wo5trFZ63E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnBGKx/btsMVavGbuJ/hqM3GDlTbl1Wo5trFZ63E1/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』 p.480&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnBGKx/btsMVavGbuJ/hqM3GDlTbl1Wo5trFZ63E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnBGKx%2FbtsMVavGbuJ%2FhqM3GDlTbl1Wo5trFZ63E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;516&quot; height=&quot;161&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』 p.480&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프록시는 말 그대로 &lt;b&gt;중간에서 통신을 중개하는 서버&lt;/b&gt;입니다.&lt;br /&gt;하지만 &amp;lsquo;누구를 대신해서&amp;rsquo; 요청을 보낼 것인지에 따라 &lt;b&gt;두 가지 종류&lt;/b&gt;로 나뉩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 포워드 프록시 (Forward Proxy)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baxkfw/btsMVVEtTJz/5cFdVoXN9vj86niC5tkLHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baxkfw/btsMVVEtTJz/5cFdVoXN9vj86niC5tkLHK/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』 p.481&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baxkfw/btsMVVEtTJz/5cFdVoXN9vj86niC5tkLHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbaxkfw%2FbtsMVVEtTJz%2F5cFdVoXN9vj86niC5tkLHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;168&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』 p.481&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트 입장에서 중간 서버&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;내부망 사용자 &amp;rarr; 외부 서버 요청 시 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 제어, 캐싱, 보안 우회(우회 접속)&lt;/b&gt; 등에 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 회사 내부에서 외부 웹사이트 접근 시, 포워드 프록시 서버를 거쳐야 하는 경우&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 프록시 서버와 VPN의 차이는 무엇인가요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 둘 다 중계 서버 개념이지만, VPN은 전체 트래픽을 암호화하고 IP 자체를 숨겨 '네트워크를 확장하는' 개념입니다. 프록시는 애플리케이션 계층 수준에서 중계합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 리버스 프록시 (Reverse Proxy)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s11a3/btsMVXChPqF/pwlGkOofugtH2rtAabzqIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s11a3/btsMVXChPqF/pwlGkOofugtH2rtAabzqIk/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』 p.482&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s11a3/btsMVXChPqF/pwlGkOofugtH2rtAabzqIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs11a3%2FbtsMVXChPqF%2FpwlGkOofugtH2rtAabzqIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;209&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』 p.482&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;서버 입장에서 중간 서버&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;외부 사용자 &amp;rarr; 여러 내부 서버 중 하나로 연결&lt;/li&gt;
&lt;li&gt;로드 밸런싱, SSL 처리, 보안 필터링 등에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Nginx를 리버스 프록시로 설정하여 여러 웹 서버 앞단에서 트래픽 분산&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 리버스 프록시와 로드 밸런서는 어떻게 다른가요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 리버스 프록시는 외부 요청을 받아 내부로 전달하는 역할, 로드 밸런서는 내부 서버 간 '트래픽 분산'이 핵심입니다. 둘이 함께 쓰이기도 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 고가용성: 로드 밸런싱과 스케일링&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 가용성(Availability)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스가 정상적으로 동작하는 시간의 비율&lt;/li&gt;
&lt;li&gt;&lt;b&gt;업타임(Uptime)&lt;/b&gt;: 서비스가 켜져 있는 시간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다운타임(Downtime)&lt;/b&gt;: 서비스가 꺼져 있는 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파이브 나인스(99.999%)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연간 &lt;b&gt;약 5.26분의 다운타임만 허용&lt;/b&gt;하는 매우 높은 신뢰성 기준&lt;/li&gt;
&lt;li&gt;주요 금융 시스템, 글로벌 IT 기업에서 추구&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 실제로 파이브 나인스를 달성하기 위해선 어떻게 해야 하나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 이중화된 전원, 분산 데이터 센터, 장애 조기 감지 시스템 등 매우 고도화된 인프라와 운영이 필요합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 헬스 체크와 하트비트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;헬스 체크 (Health Check)&lt;/b&gt;:&lt;br /&gt;로드 밸런서가 서버의 상태를 주기적으로 확인 &amp;rarr; 문제가 있으면 요청 대상에서 제외&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하트비트 (Heartbeat)&lt;/b&gt;:&lt;br /&gt;서버 간 정기적으로 신호를 주고받으며 살아있는지 확인&lt;br /&gt;&amp;rarr; 클러스터 환경에서 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 헬스 체크 실패 시, 로드 밸런서는 즉시 해당 서버를 제거하나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 대부분의 로드 밸런서는 여러 번의 실패 후에 제거합니다. false positive를 방지하기 위해 grace time이나 실패 횟수 기준이 설정됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 로드 밸런싱&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 정의 및 필요성&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 서버로 들어오는 요청을 균등하게 분산 처리하여 서버 과부하를 방지하는 기술&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 로드 밸런서는 트래픽 외에도 SSL 처리나 인증 기능을 맡기도 하나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 예, 특히 리버스 프록시와 결합된 경우 TLS 종료(SSL termination), 인증 헤더 삽입 등 기능도 수행합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 로드 밸런싱 알고리즘&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;알고리즘&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;라운드 로빈&lt;/td&gt;
&lt;td&gt;순차적으로 요청 분배&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가중 라운드 로빈&lt;/td&gt;
&lt;td&gt;서버 성능에 따라 가중치 부여&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최소 연결(Least Connection)&lt;/td&gt;
&lt;td&gt;현재 연결 수가 가장 적은 서버 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IP 해시&lt;/td&gt;
&lt;td&gt;클라이언트 IP 기반으로 고정 서버 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 라운드 로빈과 최소 연결 알고리즘은 언제 어떤 기준으로 선택하나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 요청 처리 시간이 짧고 균일하다면 라운드 로빈, 그렇지 않고 요청에 따라 부담이 다르다면 최소 연결이 더 효과적입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 스케일링: 스케일 업, 스케일 아웃, 오토스케일링&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  스케일 업 (Scale-Up)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더 좋은 성능의 장비로 교체 (수직 확장)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  스케일 아웃 (Scale-Out)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 수를 늘림 (수평 확장)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;  오토스케일링 (Auto Scaling)&lt;/h5&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽 상황에 따라 서버를 자동으로 늘리거나 줄이는 기능&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: 오토스케일링이 발생하는 기준은 어떻게 설정하나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; CPU 사용률 80% 초과, 메모리 임계치, 네트워크 트래픽 등을 기준으로 설정 가능하며, 클라우드 환경에서 정책 기반으로 관리됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Nginx로 알아보는 로드 밸런싱 실습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx는 &lt;span&gt;&lt;b&gt;리버스 프록시 + 웹 서버 + 로드 밸런서&lt;/b&gt;&lt;/span&gt; 역할을 모두 할 수 있는 가볍고 강력한 오픈소스 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 로드 밸런싱 기능은 설정만으로도 쉽게 구현할 수 있어, 학습용이나 실무 프로토타이핑에 널리 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;http {
  upstream backend {
    server backend1.example.com;
    server backend2.example.com;
  }

  server {
    listen 80;

    location / {
      proxy_pass http://backend;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;upstream&lt;/span&gt; 블록: 실제 요청을 처리할 &lt;span&gt;&lt;b&gt;백엔드 서버들을 정의&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;proxy_pass&lt;/span&gt;: 클라이언트 요청을 &lt;span&gt;backend&lt;/span&gt; 그룹 중 하나로 &lt;span&gt;&lt;b&gt;자동 전달&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q: upstream 블록에서 서버마다 weight를 설정할 수 있나요?&lt;/b&gt;&lt;br /&gt;&amp;rarr; 예, &lt;code&gt;server backend1.example.com weight=3;&lt;/code&gt; 형식으로 가중치를 부여할 수 있습니다. 처리 능력이 더 높은 서버에 더 많은 요청을 할당하기 위해 사용합니다.&lt;/p&gt;</description>
      <category>Network</category>
      <category>LoadBalancing</category>
      <category>network</category>
      <category>proxy</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/43</guid>
      <comments>https://readyoun.tistory.com/43#entry43comment</comments>
      <pubDate>Wed, 26 Mar 2025 05:35:34 +0900</pubDate>
    </item>
    <item>
      <title>[3편] 브라우저는 어떻게 나를 기억할까? - HTTP 활용</title>
      <link>https://readyoun.tistory.com/42</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;쿠키부터 HTTPS까지, HTTP 활용 기술&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0MTWm/btsMXcyqHz2/KAGwTyKi9dWflu1TqB2sT1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0MTWm/btsMXcyqHz2/KAGwTyKi9dWflu1TqB2sT1/img.webp&quot; data-alt=&quot;IconScout&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0MTWm/btsMXcyqHz2/KAGwTyKi9dWflu1TqB2sT1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0MTWm%2FbtsMXcyqHz2%2FKAGwTyKi9dWflu1TqB2sT1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;450&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;IconScout&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 개발을 하면서 가장 자주 접하게 되는 프로토콜은 &lt;b&gt;HTTP(Hypertext Transfer Protocol)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 흔히 이 프로토콜을 통해 데이터를 주고받고 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 텍스트를 요청하고 응답하는 것 외에도,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용자 상태 유지, 콘텐츠 최적화, 보안 통신, 인증 처리 등 매우 다양한 기능&lt;/b&gt;을 제공한다는 점은 간과하기 쉽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 실전 프로젝트에서 꼭 필요한 다음과 같은 HTTP 활용 기술들을 정리해봅니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자의 로그인 상태를 유지하는 &lt;b&gt;쿠키&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;서버 응답을 효율적으로 재활용하는 &lt;b&gt;캐시&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;클라이언트와 서버가 언어, 포맷을 조율하는 &lt;b&gt;콘텐츠 협상&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;사용자의 신원을 검증하는 &lt;b&gt;인증&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;전송 중 데이터의 보안을 책임지는 &lt;b&gt;HTTPS(보안 통신)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 쿠키 (Cookie)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 쿠키란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 &lt;b&gt;무상태(stateless)&lt;/b&gt; 프로토콜입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 클라이언트와 서버가 통신을 할 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 요청과 현재 요청 간의 상태가 연결되어 있지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 등장한 것이 &lt;b&gt;쿠키(Cookie)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA39rF/btsMXbfgxH2/Fa6f1uRoUlmgDBUR11xrFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA39rF/btsMXbfgxH2/Fa6f1uRoUlmgDBUR11xrFK/img.png&quot; data-alt=&quot;mdn web docs - Using HTTP cookies&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA39rF/btsMXbfgxH2/Fa6f1uRoUlmgDBUR11xrFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA39rF%2FbtsMXbfgxH2%2FFa6f1uRoUlmgDBUR11xrFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;531&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;mdn web docs - Using HTTP cookies&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 Set-Cookie 헤더의 동작 방식&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Set-Cookie: session_id=abcd1234; Path=/; HttpOnly&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 이후 요청마다 다음과 같은 헤더를 전송합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Cookie: session_id=abcd1234&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 쿠키의 주요 속성&lt;/h3&gt;
&lt;table style=&quot;height: 140px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;속성&lt;/th&gt;
&lt;th style=&quot;height: 20px;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;Name=Value&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;쿠키의 이름과 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;Path&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;어떤 경로에 대해 쿠키를 전송할지 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;Domain&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;쿠키를 전송할 도메인 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;Expires&lt;/code&gt; / &lt;code&gt;Max-Age&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;쿠키의 유효 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;Secure&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;HTTPS 통신에서만 쿠키 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;HttpOnly&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;JavaScript에서 접근 불가 &amp;rarr; 보안 강화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 쿠키의 활용과 문제점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 활용 사례&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그인 유지 (&lt;code&gt;session_id&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;방문자 추적 (GA, 광고 등)&lt;/li&gt;
&lt;li&gt;사용자 설정 저장 (언어, 테마 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;❌ 문제점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보안 위험: 쿠키 탈취(XSS), 세션 하이재킹 등&lt;/li&gt;
&lt;li&gt;용량 제한: 도메인당 4KB 이하&lt;/li&gt;
&lt;li&gt;무조건 자동 전송: 필요 없는 요청에도 함께 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✍️ 실전 예시 (가상의 사례)&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Set-Cookie: session_id=abc123; HttpOnly; Secure; Path=/; Max-Age=3600&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 강화를 위해 HttpOnly와 Secure 옵션을 추가하고, 세션 만료 시간 설정으로 안정성 확보.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.5 웹 스토리지: 로컬 스토리지와 세션 스토리지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키 외에도 브라우저는 클라이언트 측에 데이터를 저장하기 위해 &lt;span&gt;&lt;b&gt;Web Storage API&lt;/b&gt;&lt;/span&gt;를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 로컬 스토리지(LocalStorage)와 세션 스토리지(SessionStorage)가 있으며, 쿠키보다 &lt;span&gt;&lt;b&gt;용량이 크고, 단순한 구조&lt;/b&gt;&lt;/span&gt;를 가집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.99228%; height: 20px;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 18.1783%; height: 20px;&quot;&gt;&lt;b&gt;쿠키&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.8062%; height: 20px;&quot;&gt;&lt;b&gt;로컬 스토리지&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.69%; height: 20px;&quot;&gt;&lt;b&gt;세션 스토리지&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.99228%; height: 20px;&quot;&gt;용도&lt;/td&gt;
&lt;td style=&quot;width: 18.1783%; height: 20px;&quot;&gt;&lt;span&gt;상태 유지, 인증&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.8062%; height: 20px;&quot;&gt;&lt;span&gt;클라이언트 데이터 저장&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.69%; height: 20px;&quot;&gt;&lt;span&gt;탭 단위 임시 저장&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.99228%; height: 20px;&quot;&gt;저장 위치&lt;/td&gt;
&lt;td style=&quot;width: 18.1783%; height: 20px;&quot;&gt;&lt;span&gt;서버/브라우저&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.4962%; height: 20px;&quot; colspan=&quot;2&quot;&gt;브라우저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.99228%; height: 20px;&quot;&gt;자동 전송&lt;/td&gt;
&lt;td style=&quot;width: 18.1783%; height: 20px;&quot;&gt;✅ 서버에 매 요청마다 전송&lt;/td&gt;
&lt;td style=&quot;width: 39.4962%; height: 20px;&quot; colspan=&quot;2&quot;&gt;❌ 서버에 전송 안 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.99228%; height: 20px;&quot;&gt;만료 시점&lt;/td&gt;
&lt;td style=&quot;width: 18.1783%; height: 20px;&quot;&gt;&lt;span&gt;지정 가능&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.8062%; height: 20px;&quot;&gt;&lt;span&gt;직접 삭제 전까지&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.69%; height: 20px;&quot;&gt;&lt;span&gt;탭 종료 시 소멸&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.99228%; height: 20px;&quot;&gt;저장 용량&lt;/td&gt;
&lt;td style=&quot;width: 18.1783%; height: 20px;&quot;&gt;약 4KB&lt;/td&gt;
&lt;td style=&quot;width: 39.4962%; height: 20px;&quot; colspan=&quot;2&quot;&gt;수 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;  보안이 중요한 정보(예: JWT)는 쿠키 + HttpOnly 조합으로 저장하고, &lt;b&gt;일반 UI 상태 정보(예: 다크 모드)&lt;/b&gt;는 로컬 스토리지를 활용하는 방식이 이상적입니다.&lt;/i&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 캐시(Cache)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 웹 캐시란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 캐시는 서버로부터 받은 리소스를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트(브라우저)나 중간 서버(CDN, 프록시 등)&lt;/b&gt;에 저장해두었다가,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 요청이 반복될 때 &lt;span&gt;&lt;b&gt;재사용하는 기술&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적: 성능 향상, 트래픽 감소, 서버 부하 완화&lt;/li&gt;
&lt;li&gt;예: 이미지, JS, CSS, API 응답 등을 반복 요청 없이 재사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 캐시의 장점&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 74.7674%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;&lt;span&gt;&lt;b&gt;이점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.1627%;&quot;&gt;&lt;span&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;&lt;span&gt;✅ 성능 향상&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.1627%;&quot;&gt;&lt;span&gt;로딩 속도 개선 (사용자 체감 속도 &amp;uarr;)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;&lt;span&gt;✅ 트래픽 절감&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.1627%;&quot;&gt;&lt;span&gt;동일 리소스 요청 생략&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;&lt;span&gt;✅ 서버 부하 감소&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.1627%;&quot;&gt;&lt;span&gt;동시 접속 수 증가에도 안정성 확보&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.4884%;&quot;&gt;&lt;span&gt;✅ 비용 최적화&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.1627%;&quot;&gt;&lt;span&gt;CDN + 캐시로 네트워크 요금 절감 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 캐시 저장 위치&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저(로컬) : 사용자 개인 장치에 저장 (private cache)&lt;/li&gt;
&lt;li&gt;중간 서버(프록시, CDN) : 다수 사용자 간 공유 캐시 (public cache)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;Cache-Control:&amp;nbsp;private은&amp;nbsp;브라우저&amp;nbsp;캐시에만&amp;nbsp;저장되고,&amp;nbsp;public은&amp;nbsp;공유&amp;nbsp;캐시도&amp;nbsp;허용합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3 캐시 제어 HTTP 헤더&lt;/h4&gt;
&lt;pre id=&quot;code_1742932092682&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Cache-Control: max-age=1200, public
Expires: Tue, 06 Feb 2024 12:00:00 GMT
ETag: &quot;v1.3&quot;
Last-Modified: Mon, 05 Feb 2024 10:00:00 GMT&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  주요 캐시 관련 헤더&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 75.8121%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 20px;&quot;&gt;&lt;span&gt;&lt;b&gt;헤더&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8253%; height: 20px;&quot;&gt;&lt;span&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 20px;&quot;&gt;&lt;span&gt;Cache-Control&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8253%; height: 20px;&quot;&gt;&lt;span&gt;캐시 동작 제어의 핵심&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 20px;&quot;&gt;&lt;span&gt;Expires&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8253%; height: 20px;&quot;&gt;&lt;span&gt;만료 시점 설정 (HTTP/1.0)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 20px;&quot;&gt;&lt;span&gt;ETag&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8253%; height: 20px;&quot;&gt;&lt;span&gt;컨텐츠 식별용 버전 태그&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 20px;&quot;&gt;&lt;span&gt;Last-Modified&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8253%; height: 20px;&quot;&gt;&lt;span&gt;리소스 최종 수정 시각&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Cache-Control 디렉티브&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;b&gt;디렉티브&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;max-age=3600&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;1시간 동안 fresh&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;no-cache&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;캐시 사용 전 서버에 재검사 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;no-store&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;캐시에 &lt;span&gt;&lt;b&gt;절대 저장 금지&lt;/b&gt;&lt;/span&gt; (민감 정보)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;private&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;개인 클라이언트 전용 캐시 (공유 캐시 금지)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;public&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;누구나 캐시 가능 (프록시, CDN 허용)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;must-revalidate&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;만료 시 재검사 반드시 수행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Cache-Control: public, max-age=600, must-revalidate&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4 Expires vs Cache-Control&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.6279%;&quot;&gt;&lt;span&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.2558%;&quot;&gt;&lt;span&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.6279%;&quot;&gt;&lt;span&gt;Expires&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.2558%;&quot;&gt;&lt;span&gt;절대 시간 기반 만료 (HTTP/1.0 스타일)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 31.6279%;&quot;&gt;&lt;span&gt;Cache-Control: max-age&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.2558%;&quot;&gt;&lt;span&gt;상대 시간 기반 만료 (HTTP/1.1 이후 권장)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  두 개가 함께 있을 경우, &lt;span&gt;&lt;b&gt;Cache-Control이 우선 적용&lt;/b&gt;&lt;/span&gt;됩니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.5 ETag vs Last-Modified&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 조건부 요청(Validation)에 사용되는 헤더입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.2558%;&quot;&gt;&lt;span&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.6279%;&quot;&gt;&lt;span&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.2558%;&quot;&gt;&lt;span&gt;ETag&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.6279%;&quot;&gt;&lt;span&gt;리소스의 고유 버전 ID (정밀 비교)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.2558%;&quot;&gt;&lt;span&gt;Last-Modified&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.6279%;&quot;&gt;&lt;span&gt;최종 수정 시각 (초 단위, 정밀도 낮음)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;If-None-Match: &quot;v1.2.3&quot;     &amp;rarr; 서버가 ETag 비교
If-Modified-Since: Tue, 25 Mar 2025 10:00:00 GMT&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  둘 다 있다면 브라우저는 &lt;span&gt;&lt;b&gt;ETag를 우선적으로 사용&lt;/b&gt;&lt;/span&gt;합니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.6 캐시 신선도(freshness)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시가 &lt;b&gt;fresh(신선)&lt;/b&gt;한지, &lt;b&gt;stale(만료)&lt;/b&gt;됐는지를 판단하는 기준&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;현재 시각 - 응답 수신 시각 &amp;lt; max-age &amp;rarr; fresh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fresh: 서버 요청 없이 캐시 사용&lt;/li&gt;
&lt;li&gt;stale: 재검사 필요 &amp;rarr; 304 or 새로 받음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.7 캐시 동작 방식: 3가지 케이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;① 캐시 그대로 사용 (fresh)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;캐시가 아직 유효함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;서버 요청 없이 클라이언트가 그대로 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;② 조건부 요청 (stale, 변경 없음)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;캐시가 만료됐지만 서버 리소스가 변경되지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;304 Not Modified&lt;span&gt; 응답&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;기존 캐시 재사용&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;If-None-Match: &quot;v1.2.3&quot;
&amp;rarr; 304 Not Modified&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;③ 캐시 무효화 (stale, 변경됨)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;캐시 만료 + 리소스 변경됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;서버가 새 리소스를 &lt;span&gt;200 OK&lt;/span&gt;로 재전송&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.8 프록시 캐시 vs 브라우저 캐시&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;b&gt;브라우저 캐시&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;b&gt;프록시 캐시 / CDN&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;대상&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;개인 사용자&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;여러 사용자 공유&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;private&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;✅ 허용&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;❌ 금지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;public&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;✅ 허용&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;✅ 허용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;사용 예&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;로그인 상태 유지&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;정적 리소스 CDN 제공&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✍️ 실전 예시 (가상의 사례)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 프로필 이미지가 변경되었는데도, 브라우저에선 이전 이미지를 계속 보여주는 문제가 발생.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  해결 방안&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;이미지 URL에 버전 쿼리 추가&amp;nbsp;&lt;span&gt;&amp;rarr; &lt;/span&gt;/profile.jpg?v=20250325&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;서버 응답 헤더 설정:&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;Cache-Control: private, max-age=300
ETag: &quot;profile-img-v2&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 캐시 유효 시간이 지나면 서버에&lt;b&gt; &lt;span&gt;If-None-Match&lt;/span&gt;&lt;/b&gt;로 조건부 요청 &amp;rarr;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경 없음: 304 &amp;rarr; 재사용 / 변경됨: 200 &amp;rarr; 새로 받음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 브라우저는 적절히 캐시를 활용하면서도 &lt;span&gt;&lt;b&gt;최신 이미지 동기화&lt;/b&gt;&lt;/span&gt;를 유지할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 캐시 요약 정리&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;&lt;span&gt;&lt;b&gt;요소&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.4651%;&quot;&gt;&lt;span&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;&lt;span&gt;Cache-Control&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.4651%;&quot;&gt;&lt;span&gt;캐시 정책 제어 (핵심)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;&lt;span&gt;ETag&lt;span&gt; / &lt;/span&gt;Last-Modified&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.4651%;&quot;&gt;&lt;span&gt;변경 여부 판단용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;&lt;span&gt;Expires&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.4651%;&quot;&gt;&lt;span&gt;HTTP/1.0 호환 만료 시간&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;&lt;span&gt;Fresh / Stale&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.4651%;&quot;&gt;&lt;span&gt;신선도 판단 기준&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.4186%;&quot;&gt;&lt;span&gt;304 응답&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.4651%;&quot;&gt;&lt;span&gt;조건부 요청의 결과&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 콘텐츠 협상 (Content Negotiation)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 콘텐츠 협상이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 요청 시 수신 가능한 포맷/언어/인코딩을 제안하고, 서버가 최적 콘텐츠를 제공하는 기능&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 콘텐츠 협상의 유형&lt;/h3&gt;
&lt;table style=&quot;width: 348px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 154px;&quot;&gt;유형&lt;/th&gt;
&lt;th style=&quot;width: 194px;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;서버 주도&lt;/td&gt;
&lt;td style=&quot;width: 194px;&quot;&gt;Accept 헤더 기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;에이전트 주도&lt;/td&gt;
&lt;td style=&quot;width: 194px;&quot;&gt;클라이언트 UI 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 154px;&quot;&gt;투명 협상&lt;/td&gt;
&lt;td style=&quot;width: 194px;&quot;&gt;프록시가 판단&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 주요 헤더&lt;/h3&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;Accept: application/json
Accept-Language: ko-KR, en-US;q=0.8
Accept-Encoding: gzip, deflate&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✍️ 실전 예시 (가상의 사례)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 언어 설정 기반으로 자동 언어 제공&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const lang = req.headers['accept-language'];&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[여기서 잠깐!] 인증(Authentication)&lt;/h4&gt;
&lt;table style=&quot;height: 81px; width: 543px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;th style=&quot;height: 21px; width: 81px;&quot;&gt;방식&lt;/th&gt;
&lt;th style=&quot;height: 21px; width: 262px;&quot;&gt;설명&lt;/th&gt;
&lt;th style=&quot;height: 21px; width: 200px;&quot;&gt;보안성&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 81px;&quot;&gt;Basic&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 262px;&quot;&gt;ID/PW를 base64 인코딩&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 200px;&quot;&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 81px;&quot;&gt;Form 기반&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 262px;&quot;&gt;세션과 쿠키 조합&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 200px;&quot;&gt;중간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 81px;&quot;&gt;JWT&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 262px;&quot;&gt;토큰 기반 stateless 인증&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 200px;&quot;&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;주의: HTTPS 미적용 시 인증 정보 노출 위험! 반드시 보안 채널에서만 사용하세요.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 보안 (HTTPS, TLS)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 HTTPS가 필요한 이유&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;평문 전송 문제 해결 (도청, 위조, 변조 방지)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 HTTP 통신은 &lt;b&gt;평문(Plain Text)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 누군가가 네트워크 중간에서 통신을 엿본다면 다음과 같은 정보가 &lt;span&gt;&lt;b&gt;그대로 노출됩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로그인 ID, 비밀번호&lt;/li&gt;
&lt;li&gt;카드번호, 주소 등 민감 정보&lt;/li&gt;
&lt;li&gt;쿠키 값 &amp;rarr; 세션 하이재킹 위험&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 사용되는 것이 바로 &lt;span&gt;&lt;b&gt;HTTPS (HTTP Secure)&lt;/b&gt;&lt;/span&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 HTTPS의 핵심: TLS 프로토콜&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPS는 내부적으로 &lt;span&gt;&lt;b&gt;TLS(Transport Layer Security)&lt;/b&gt;&lt;/span&gt; 프로토콜을 사용하여 다음 3가지를 보장합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기밀성 : 전송되는 데이터가 암호화되어 도청 불가&lt;/li&gt;
&lt;li&gt;무결성 : 중간에 데이터가 변경되었는지 여부 확인 가능&lt;/li&gt;
&lt;li&gt;인증성 : 서버(또는 클라이언트)의 신원을 검증 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 TLS 통신 흐름 요약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPS&amp;nbsp;통신이&amp;nbsp;시작되면,&amp;nbsp;클라이언트와&amp;nbsp;서버는&amp;nbsp;TLS&amp;nbsp;핸드셰이크&amp;nbsp;과정을&amp;nbsp;통해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로의&amp;nbsp;신원을&amp;nbsp;확인하고&amp;nbsp;안전하게&amp;nbsp;대칭키를&amp;nbsp;공유하게&amp;nbsp;됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래&amp;nbsp;이미지는&amp;nbsp;TLS&amp;nbsp;1.3&amp;nbsp;기준의&amp;nbsp;핸드셰이크&amp;nbsp;흐름입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RfYsr/btsMXdqzVWF/Izv7jaYHuBFrD4gt9Trop0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RfYsr/btsMXdqzVWF/Izv7jaYHuBFrD4gt9Trop0/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.475&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RfYsr/btsMXdqzVWF/Izv7jaYHuBFrD4gt9Trop0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRfYsr%2FbtsMXdqzVWF%2FIzv7jaYHuBFrD4gt9Trop0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;441&quot; height=&quot;357&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.475&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;단계별&amp;nbsp;설명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;1. ClientHello : 클라이언트가 지원하는 프로토콜 버전, 암호화 스위트, key_share(선택적) 등을 서버에 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;2. ServerHello : 서버가 선택한 암호화 방식과 자신의 key_share(선택적)을 응답&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;3. EncryptedExtensions : 서버의 추가 옵션 정보를 클라이언트에게 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;4. Certificate : 서버의 공개키 인증서를 클라이언트에게 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;5. CertificateVerify : 서버가 해당 인증서의 개인키로 서명해 신뢰성을 증명&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;6. Finished : 서버가 핸드셰이크 완료를 알림&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;7. Finished : 클라이언트가 인증 확인 후 핸드셰이크 완료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt; &amp;nbsp;TLS&amp;nbsp;1.3에서는&amp;nbsp;보안성과&amp;nbsp;성능을&amp;nbsp;모두&amp;nbsp;고려하여,&amp;nbsp;핸드셰이크가&amp;nbsp;1&amp;nbsp;RTT(왕복&amp;nbsp;시간)만에&amp;nbsp;완료됩니다.&amp;nbsp;또한,&amp;nbsp;일부&amp;nbsp;메시지는&amp;nbsp;선택적으로&amp;nbsp;포함되며,&amp;nbsp;이전&amp;nbsp;버전보다&amp;nbsp;더&amp;nbsp;간결하고&amp;nbsp;안전한&amp;nbsp;구조를&amp;nbsp;제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;* TLS 핸드셰이크는 전송 계층의 TCP 핸드셰이크가 끝난 후에 진행되는 보안 절차임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4 대칭키 vs 공개키 암호화&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt; ️ 대칭키 암호화란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&amp;ldquo;열쇠 하나로 잠그고 여는 방식&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대칭키 암호화는 &lt;b&gt;하나의 동일한 비밀키(key)&lt;/b&gt;를 사용하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 암호화하고 복호화합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;보내는 사람과 받는 사람이 &lt;/span&gt;&lt;b&gt;같은 키를 공유&lt;/b&gt;&lt;span&gt;해야 하기 때문에 &lt;/span&gt;&lt;b&gt;빠르고 효율적&lt;/b&gt;&lt;span&gt;하지만, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그 키를 안전하게 전달하는 것이 큰 과제&lt;/b&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;편지를 보낼 때, 자물쇠로 잠근 뒤 그 열쇠를 따로 전달해야 한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 열쇠가 도중에 유출될 위험이 큼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  사용 알고리즘&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: AES, DES, RC4 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  공개키 암호화란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&amp;ldquo;잠그는 열쇠는 공개, 여는 열쇠는 비밀&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공개키 암호화는 &lt;span&gt;&lt;b&gt;열쇠가 두 개&lt;/b&gt;&lt;/span&gt;입니다.&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;공개키(Public Key)&lt;/b&gt;: 누구나 볼 수 있음 &amp;rarr; 데이터를 잠그는 용도&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개인키(Private Key)&lt;/b&gt;: 서버만 가지고 있음 &amp;rarr; 데이터를 여는 용도&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 서버의 공개키로 데이터를 암호화해서 전송하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 그에 상응하는 개인키로만 이를 복호화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;rarr; &lt;/span&gt;&lt;b&gt;키를 미리 공유할 필요가 없으므로 안전하지만, 처리 속도가 느림&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 금고를 누구나 잠글 수 있지만, 여는 열쇠는 금고 주인만 가지고 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  사용 알고리즘&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RSA, ECC 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;TLS에서 어떻게 쓰일까?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;TLS에서는&amp;nbsp;두 방식의 장점을 모두 활용합니다.&lt;br /&gt;1.&amp;nbsp;클라이언트가 서버의&amp;nbsp;공개키로 Pre-Master Key를 암호화해서 전송&amp;nbsp;(공개키 암호화)&lt;br /&gt;2.&amp;nbsp;서버는 개인키로 이를 복호화하고, 클라이언트와&amp;nbsp;동일한 대칭키를 생성&lt;br /&gt;3.&amp;nbsp;이후 실제 데이터는&amp;nbsp;대칭키로 암호화하여 빠르게 통신&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 결론&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대칭키는 빠르지만 키 전달이 문제&lt;/li&gt;
&lt;li&gt;공개키는 안전하지만 느림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 그래서 TLS에서는 공개키로 안전하게 대칭키를 주고받고, 대칭키로 데이터를 주고받는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 정리 및 배운 점&lt;/h2&gt;
&lt;table style=&quot;width: 581px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 106px;&quot;&gt;주제&lt;/th&gt;
&lt;th style=&quot;width: 229px;&quot;&gt;키워드&lt;/th&gt;
&lt;th style=&quot;width: 246px;&quot;&gt;실전 활용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 106px;&quot;&gt;쿠키&lt;/td&gt;
&lt;td style=&quot;width: 229px;&quot;&gt;세션, 상태 유지&lt;/td&gt;
&lt;td style=&quot;width: 246px;&quot;&gt;로그인 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 106px;&quot;&gt;캐시&lt;/td&gt;
&lt;td style=&quot;width: 229px;&quot;&gt;Cache-Control, ETag&lt;/td&gt;
&lt;td style=&quot;width: 246px;&quot;&gt;정적 자산 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 106px;&quot;&gt;콘텐츠 협상&lt;/td&gt;
&lt;td style=&quot;width: 229px;&quot;&gt;Accept-* 헤더&lt;/td&gt;
&lt;td style=&quot;width: 246px;&quot;&gt;다국어, API 대응&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 106px;&quot;&gt;인증&lt;/td&gt;
&lt;td style=&quot;width: 229px;&quot;&gt;Basic, JWT&lt;/td&gt;
&lt;td style=&quot;width: 246px;&quot;&gt;사용자 검증&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 106px;&quot;&gt;보안&lt;/td&gt;
&lt;td style=&quot;width: 229px;&quot;&gt;HTTPS, TLS, 인증서&lt;/td&gt;
&lt;td style=&quot;width: 246px;&quot;&gt;민감 정보 보호&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.464~479&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies&quot;&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Network</category>
      <category>cache</category>
      <category>Cookie</category>
      <category>HTTP</category>
      <category>https</category>
      <category>network</category>
      <category>ssl</category>
      <category>TLS</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/42</guid>
      <comments>https://readyoun.tistory.com/42#entry42comment</comments>
      <pubDate>Wed, 26 Mar 2025 04:54:37 +0900</pubDate>
    </item>
    <item>
      <title>[2편] HTTP 메서드부터 상태 코드, 주요 헤더까지</title>
      <link>https://readyoun.tistory.com/41</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gp8Lc/btsMVrcSx40/mYsEpDGFhaQh87AMgUiwPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gp8Lc/btsMVrcSx40/mYsEpDGFhaQh87AMgUiwPk/img.png&quot; data-alt=&quot;&amp;amp;ldquo;Top 10&amp;amp;rdquo; HTTP Status Code explained you need to know as a Front End Developer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gp8Lc/btsMVrcSx40/mYsEpDGFhaQh87AMgUiwPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGp8Lc%2FbtsMVrcSx40%2FmYsEpDGFhaQh87AMgUiwPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;534&quot; height=&quot;300&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;ldquo;Top 10&amp;rdquo; HTTP Status Code explained you need to know as a Front End Developer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 HTTP의 핵심 요소인 &lt;b&gt;메서드, 상태 코드, 주요 헤더&lt;/b&gt;에 대해 살펴봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API 설계, 클라이언트-서버 통신 흐름 파악, 인증 및 보안 처리 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실무 전반에서 자주 마주치는 필수 기초&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. HTTP 메서드 &amp;ndash; 요청의 목적을 나타내는 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 클라이언트가 서버에 요청을 보낼 때 &lt;b&gt;무엇을 하고 싶은지를 명시&lt;/b&gt;합니다.&lt;br /&gt;이는 HTTP 메서드(Method)를 통해 표현됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;height: 233px;&quot; width=&quot;730&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;메서드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;GET&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리소스를 조회할 때 사용. URL에 데이터를 포함하고 본문은 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HEAD&lt;/td&gt;
&lt;td&gt;GET과 같지만 본문 없이 헤더 정보만 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;POST&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서버에 리소스를 생성할 때 사용. 본문에 데이터 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;PUT&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리소스를 전체 수정할 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATCH&lt;/td&gt;
&lt;td&gt;리소스를 일부 수정할 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DELETE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리소스를 삭제할 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 예시: GET 요청&lt;/h4&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;GET /posts/1 HTTP/1.1
Host: example.com&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 예시: POST 요청&lt;/h4&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;POST /posts HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 52

{
  &quot;title&quot;: &quot;Hello&quot;,
  &quot;body&quot;: &quot;World&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 상태 코드 &amp;ndash; 요청 결과를 알려주는 번호&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 응답은 항상 세 자리 숫자인 &lt;b&gt;상태 코드(Status Code)&lt;/b&gt; 를 포함하며,&lt;br /&gt;클라이언트가 요청한 작업의 처리 결과를 알려줍니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 상태 코드 범위&lt;/h4&gt;
&lt;table style=&quot;height: 198px;&quot; width=&quot;467&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;범위&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1xx&lt;/td&gt;
&lt;td&gt;처리 중 (정보성 응답)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2xx&lt;/td&gt;
&lt;td&gt;요청 성공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3xx&lt;/td&gt;
&lt;td&gt;리다이렉션 (다른 URL로 이동 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4xx&lt;/td&gt;
&lt;td&gt;클라이언트 오류 (요청 문제)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5xx&lt;/td&gt;
&lt;td&gt;서버 오류 (서버 문제)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 자주 사용하는 2xx 상태 코드&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;200 OK&lt;/td&gt;
&lt;td&gt;요청이 성공적으로 처리됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;201 Created&lt;/td&gt;
&lt;td&gt;새로운 리소스가 생성됨 (POST)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;202 Accepted&lt;/td&gt;
&lt;td&gt;요청을 받았지만 아직 처리되지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zW7j3/btsMWjZsxmd/BRKuo33zKQGPs5SDYfgDK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zW7j3/btsMWjZsxmd/BRKuo33zKQGPs5SDYfgDK0/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』,&amp;amp;nbsp;p.454&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zW7j3/btsMWjZsxmd/BRKuo33zKQGPs5SDYfgDK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzW7j3%2FbtsMWjZsxmd%2FBRKuo33zKQGPs5SDYfgDK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;124&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』,&amp;nbsp;p.454&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 리다이렉션 관련 3xx 상태 코드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리다이렉션(redirection)&lt;/b&gt;이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 클라이언트가 요청한 자원이 다른 곳에 있을 때 다른 곳으로 요청을 이동시키는 것&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hkn8j/btsMVF9IXPF/uDJ0NTjVWQzOZ1lchuUylk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hkn8j/btsMVF9IXPF/uDJ0NTjVWQzOZ1lchuUylk/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.455&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hkn8j/btsMVF9IXPF/uDJ0NTjVWQzOZ1lchuUylk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHkn8j%2FbtsMVF9IXPF%2FuDJ0NTjVWQzOZ1lchuUylk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;457&quot; height=&quot;315&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.455&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;자원이 이동되었을 때 서버는 Location 헤더와 함께 리다이렉션 상태 코드를 반환하여 &lt;br /&gt;&amp;ldquo;이 자원은 여기로 옮겨졌어요&amp;rdquo; 라고 클라이언트에게 알려줍니다. &lt;br /&gt;&lt;br /&gt;클라이언트는 이를 수신한 후, Location에 명시된 주소로 자동으로 재요청을 수행하고, &lt;br /&gt;새 위치의 자원에 대한 응답을 새롭게 받아 처리하게 됩니다.&lt;/blockquote&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;301 Moved Permanently&lt;/td&gt;
&lt;td&gt;요청한 리소스가 영구적으로 이동됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;302 Found&lt;/td&gt;
&lt;td&gt;일시적으로 이동됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;304 Not Modified&lt;/td&gt;
&lt;td&gt;클라이언트 캐시 사용 가능 (변경 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HYdLR/btsMXatSgTJ/Y0oCkwVUBNNXj00AneaJfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HYdLR/btsMXatSgTJ/Y0oCkwVUBNNXj00AneaJfk/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.455&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HYdLR/btsMXatSgTJ/Y0oCkwVUBNNXj00AneaJfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHYdLR%2FbtsMXatSgTJ%2FY0oCkwVUBNNXj00AneaJfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;171&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.455&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;리다이렉션(Redirection)의&amp;nbsp;종류와&amp;nbsp;상태&amp;nbsp;코드&amp;nbsp;비교&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 영구적 리다이렉션 (Permanent Redirect)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;자원이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;영구적으로 이동되었음&lt;/b&gt;을 나타내는 리다이렉션입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대표 상태 코드: `301 Moved Permanently`, `308 Permanent Redirect`&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클라이언트는 이후부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;항상 새 URL을 사용해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;검색 엔진도 URL 변경을 반영함 (SEO 영향 있음)&lt;/p&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Xk7i/btsMWZ0oY4o/0yEUAVOddTY5jwkageJegk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Xk7i/btsMWZ0oY4o/0yEUAVOddTY5jwkageJegk/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.456&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Xk7i/btsMWZ0oY4o/0yEUAVOddTY5jwkageJegk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Xk7i%2FbtsMWZ0oY4o%2F0yEUAVOddTY5jwkageJegk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;187&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.456&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;`301`: 원래는 GET 요청만 고려했으나, 실제 구현에서는 &lt;b&gt;POST &amp;rarr; GET&lt;/b&gt;으로 바뀌는 경우도 있음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;`308`: &lt;b&gt;요청 방식(예: POST)&lt;/b&gt;을 그대로 유지하고 새 URL로 리다이렉트 (보다 명확한 동작)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 일시적 리다이렉션 (Temporary Redirect)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;자원이 &lt;b&gt;임시로 다른 위치에 있는 경우&lt;/b&gt;, 혹은 &lt;b&gt;특정 조건에서만 위치가 변경된 경우&lt;/b&gt; 사용됩니다.&lt;br /&gt;&lt;br /&gt;-&amp;nbsp;대표&amp;nbsp;상태&amp;nbsp;코드:&amp;nbsp;`302&amp;nbsp;Found`,&amp;nbsp;`307&amp;nbsp;Temporary&amp;nbsp;Redirect`,&amp;nbsp;`303&amp;nbsp;See&amp;nbsp;Other`&lt;br /&gt;-&amp;nbsp;이후&amp;nbsp;요청에서는&amp;nbsp;여전히&lt;b&gt; 원래 URL을 사용할 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMJidn/btsMW8bOuNZ/NbBh6ODvp85MxlSylp5s11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMJidn/btsMW8bOuNZ/NbBh6ODvp85MxlSylp5s11/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.457&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMJidn/btsMW8bOuNZ/NbBh6ODvp85MxlSylp5s11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMJidn%2FbtsMW8bOuNZ%2FNbBh6ODvp85MxlSylp5s11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;188&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.457&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;- `302`: 전통적으로 많이 사용되었으나, 명확한 의미 없이 POST &amp;rarr; GET으로 바뀌는 등 &lt;b&gt;불명확성 존재&lt;/b&gt;&lt;br /&gt;- `307`: 요청 메서드를&amp;nbsp;&lt;b&gt;그대로 유지&lt;/b&gt;하여&amp;nbsp;재요청&amp;nbsp;(POST&amp;nbsp;&amp;rarr;&amp;nbsp;POST)&lt;br /&gt;- `303`: 메서드를 &lt;b&gt;GET으로 변경&lt;/b&gt;하여 리소스를 다시 요청하는 방식 (주로 응답 페이지 안내 시 사용)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;✅ 상황에 따라 적절한 리다이렉션 선택이 중요합니다!&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5086%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;상태&amp;nbsp;코드&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.0977%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5918%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;요청 방식 유지 여부&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.8019%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;주 용도&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5086%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;301&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.0977%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;영구 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5918%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;유지 안 될 수 있음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.8019%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;URL 구조 변경&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5086%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;308&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.0977%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;영구 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5918%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;유지됨&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.8019%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;REST API 안전한 리다이렉션&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5086%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;302&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.0977%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;임시 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5918%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;유지 안 됨 (대개 GET)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.8019%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;전통적 웹 페이지 이동&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5086%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;307&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.0977%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;임시 이동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5918%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;유지됨&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.8019%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;폼 제출 등 보존 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.5086%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;303&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.0977%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;다른 위치 보기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5918%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;GET으로 변경됨&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.8019%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;응답 안내 페이지 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;  REST API에서는 308, 307을 사용하는 것이 안전하며, 브라우저 기반 응답 페이지 안내에는 303이 유용합니다.&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 클라이언트 오류 4xx 상태 코드&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;400 Bad Request&lt;/td&gt;
&lt;td&gt;잘못된 요청 형식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;401 Unauthorized&lt;/td&gt;
&lt;td&gt;인증 필요 (로그인 안 됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;403 Forbidden&lt;/td&gt;
&lt;td&gt;권한 없음 (로그인해도 접근 불가)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;404 Not Found&lt;/td&gt;
&lt;td&gt;존재하지 않는 자원 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;405 Method Not Allowed&lt;/td&gt;
&lt;td&gt;지원하지 않는 메서드 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o02CR/btsMVwrBk01/NjkFcbkkWML2KNwep5hKj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o02CR/btsMVwrBk01/NjkFcbkkWML2KNwep5hKj1/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.457&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o02CR/btsMVwrBk01/NjkFcbkkWML2KNwep5hKj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo02CR%2FbtsMVwrBk01%2FNjkFcbkkWML2KNwep5hKj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;159&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.457&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  401 vs 403의 차이:&lt;/b&gt;&lt;br /&gt;401은 &lt;b&gt;인증(authentication)&lt;/b&gt;이 필요함,&lt;br /&gt;403은 인증했지만 &lt;b&gt;인가(authorization)&lt;/b&gt;가 없음.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[&amp;nbsp;여기서&amp;nbsp;잠깐!&amp;nbsp;]&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;인증(Authentication) vs 인가(Authorization)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 130px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 26px;&quot;&gt;
&lt;td style=&quot;width: 15.759%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;구분&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5413%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;인증 (Authentication)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 46.6996%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;인가 (Authorization)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 26px;&quot;&gt;
&lt;td style=&quot;width: 15.759%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;의미&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5413%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&quot;당신이 누구인지 확인&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 46.6996%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&quot;당신이 이걸 할 수 있는 권한이 있는가?&quot;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 26px;&quot;&gt;
&lt;td style=&quot;width: 15.759%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;목적&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5413%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;사용자의 &lt;b&gt;신원 확인&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 46.6996%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;b&gt;접근 권한 부여 여부&lt;/b&gt; 결정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 26px;&quot;&gt;
&lt;td style=&quot;width: 15.759%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;예시&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5413%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;로그인 (ID/PW, 토큰 등)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 46.6996%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;관리자만 설정 페이지 접근 허용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 26px;&quot;&gt;
&lt;td style=&quot;width: 15.759%; height: 26px;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;상태&amp;nbsp;코드&amp;nbsp;관련&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.5413%; height: 26px;&quot;&gt;&lt;i&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;401 Unauthorized&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;width: 46.6996%; height: 26px;&quot;&gt;&lt;i&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;403 Forbidden&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증은 &lt;b&gt;&quot;너 누구야?&quot;&lt;/b&gt;, 인가는 &lt;b&gt;&quot;너 이거 해도 돼?&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;인증 vs 인가 자세히&lt;/b&gt; : &lt;a href=&quot;https://inpa.tistory.com/entry/CS-%F0%9F%91%A8%E2%80%8D%F0%9F%92%BB-Authentication-vs-Authorization-%EC%B0%A8%EC%9D%B4-%EC%97%84%EC%B2%AD-%EC%89%BD%EA%B2%8C-%EC%84%A4%EB%AA%85&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; &amp;zwj;  쉽게 이해하는 Authentication vs Authorization 차이&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 서버 오류 5xx 상태 코드&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;500 Internal Server Error&lt;/td&gt;
&lt;td&gt;서버 내부 처리 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;502 Bad Gateway&lt;/td&gt;
&lt;td&gt;중간 게이트웨이 서버 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ldcih/btsMVxcZvyF/jzcoHRHMVeqmQDH0TNDZOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ldcih/btsMVxcZvyF/jzcoHRHMVeqmQDH0TNDZOk/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.458&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ldcih/btsMVxcZvyF/jzcoHRHMVeqmQDH0TNDZOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fldcih%2FbtsMVxcZvyF%2FjzcoHRHMVeqmQDH0TNDZOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;82&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.458&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1DA1Q/btsMVah4UQX/uRInkCx9zkftJAh9oZHKG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1DA1Q/btsMVah4UQX/uRInkCx9zkftJAh9oZHKG1/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』, p.458&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1DA1Q/btsMVah4UQX/uRInkCx9zkftJAh9oZHKG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1DA1Q%2FbtsMVah4UQX%2FuRInkCx9zkftJAh9oZHKG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;481&quot; height=&quot;128&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.458&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. HTTP 주요 헤더&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 헤더는 요청과 응답 메시지에 포함되어 &lt;b&gt;메타데이터&lt;/b&gt;를 전달합니다.&lt;br /&gt;헤더는 이름과 값으로 구성되며, &lt;code&gt;Header-Name: value&lt;/code&gt; 형식을 가집니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 요청 메시지에서 자주 쓰는 헤더&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;헤더&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;td&gt;요청 대상 도메인 이름 (필수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-Agent&lt;/td&gt;
&lt;td&gt;브라우저/클라이언트 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referer&lt;/td&gt;
&lt;td&gt;이전 요청 페이지의 주소 (출처)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 응답 메시지에서 자주 쓰는 헤더&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;헤더&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;서버 소프트웨어 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Location&lt;/td&gt;
&lt;td&gt;새로 생성된 리소스 주소 (POST 201, 리다이렉션 3xx)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allow&lt;/td&gt;
&lt;td&gt;지원하는 메서드 목록 (405 응답 시 포함됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 요청/응답 공통으로 사용되는 헤더&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;헤더&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;본문의 타입 (예: application/json, text/html)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Length&lt;/td&gt;
&lt;td&gt;본문의 크기 (바이트 단위)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Language&lt;/td&gt;
&lt;td&gt;콘텐츠 언어 (예: ko-KR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Encoding&lt;/td&gt;
&lt;td&gt;압축 방식 (예: gzip)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;메시지 생성 시점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection&lt;/td&gt;
&lt;td&gt;연결 방식 (&lt;code&gt;keep-alive&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 면접 질문 예시&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP의 킵 얼라이브(Keep-Alive)란 무엇인가요?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP/1.0은 요청마다 TCP 연결을 새로 맺는 &lt;b&gt;비지속 연결&lt;/b&gt; 방식이었지만,&lt;br /&gt;HTTP/1.1부터는 기본적으로 연결을 끊지 않고 &lt;b&gt;지속 연결(Persistent Connection)&lt;/b&gt;을 유지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Keep-Alive는 이러한 지속 연결을 가능하게 하는 HTTP 헤더로,&lt;br /&gt;&lt;b&gt;여러 개의 요청/응답을 하나의 TCP 연결로 처리할 수 있도록&lt;/b&gt; 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 연결 수 감소 &amp;rarr; 속도 향상 + 리소스 절약&lt;/li&gt;
&lt;li&gt;예시 헤더: &lt;code&gt;Connection: keep-alive&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;HTTP/1.0에서는 요청을 보낼 때마다 매번 새로운 TCP 연결을 맺고, 응답 후 즉시 연결을 끊는 방식인 비지속 연결을 사용했습니다. 하지만 HTTP/1.1부터는 기본적으로 지속 연결(Persistent Connection)을 지원하며, Connection: keep-alive 헤더를 통해 하나의 TCP 연결을 재사용할 수 있게 되었습니다. 이를 통해 여러 개의 요청과 응답을 하나의 연결로 처리할 수 있어, 연결 수를 줄이고 네트워크 자원을 절약하며 전체 통신 속도를 향상시킬 수 있습니다.&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP 1.1과 HTTP 2.0의 차이점은 무엇인가요?&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;HTTP/1.1&lt;/th&gt;
&lt;th&gt;HTTP/2.0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;데이터 형식&lt;/td&gt;
&lt;td&gt;텍스트 기반&lt;/td&gt;
&lt;td&gt;&lt;b&gt;바이너리 기반&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;연결 방식&lt;/td&gt;
&lt;td&gt;요청당 순차 처리 (HOL blocking 발생)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;멀티플렉싱&lt;/b&gt;으로 동시 요청 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서버 푸시&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;td&gt;&lt;b&gt;서버 푸시(Server Push)&lt;/b&gt; 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;성능&lt;/td&gt;
&lt;td&gt;헤더 중복 많음, 느린 처리&lt;/td&gt;
&lt;td&gt;헤더 압축 + 빠른 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP/1.1은 텍스트 기반 프로토콜로, 요청을 순차적으로 처리하기 때문에 하나의 요청이 끝날 때까지 다음 요청을 대기해야 하는 HOL(Head-of-Line) 블로킹 문제가 있었습니다. &lt;br /&gt;&lt;br /&gt;반면 HTTP/2.0은 바이너리 기반 프로토콜이며, 하나의 연결 내에서 여러 요청과 응답을 동시에 주고받을 수 있는 &lt;b&gt;멀티플렉싱(Multiplexing)&lt;/b&gt;을 지원하여 병목 현상을 해결했습니다. 또한 헤더를 압축해 오버헤드를 줄이고, 서버가 클라이언트 요청 없이도 데이터를 푸시할 수 있는 서버 푸시 기능도 도입되어, 웹 페이지 로딩 성능이 크게 개선되었습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP 메서드인 GET과 POST의 차이는 무엇인가요?&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;GET&lt;/th&gt;
&lt;th&gt;POST&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;데이터 &lt;b&gt;조회&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 &lt;b&gt;생성 / 전송&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 전달 위치&lt;/td&gt;
&lt;td&gt;URL (쿼리 스트링)&lt;/td&gt;
&lt;td&gt;HTTP 본문 (Body)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;브라우저 캐시&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;td&gt;일반적으로 불가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/search?q=chatgpt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/login&lt;/code&gt; (본문에 id/pw 포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET&amp;nbsp;메서드는&amp;nbsp;리소스를&amp;nbsp;조회할&amp;nbsp;때&amp;nbsp;사용되며,&amp;nbsp;전달할&amp;nbsp;데이터가&amp;nbsp;URL의&amp;nbsp;쿼리&amp;nbsp;문자열에&amp;nbsp;포함됩니다.&amp;nbsp;반면&amp;nbsp;POST&amp;nbsp;메서드는&amp;nbsp;리소스를&amp;nbsp;생성하거나&amp;nbsp;서버로&amp;nbsp;데이터를&amp;nbsp;전송할&amp;nbsp;때&amp;nbsp;사용되며,&amp;nbsp;데이터는&amp;nbsp;HTTP&amp;nbsp;메시지의&amp;nbsp;본문(Body)에&amp;nbsp;담깁니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;GET&amp;nbsp;요청은&amp;nbsp;브라우저의&amp;nbsp;캐시에&amp;nbsp;저장되거나&amp;nbsp;URL로&amp;nbsp;공유될&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;반면,&amp;nbsp;POST는&amp;nbsp;그렇지&amp;nbsp;않기&amp;nbsp;때문에&amp;nbsp;민감한&amp;nbsp;정보를&amp;nbsp;전송할&amp;nbsp;때는&amp;nbsp;반드시&amp;nbsp;POST&amp;nbsp;방식을&amp;nbsp;사용하는&amp;nbsp;것이&amp;nbsp;바람직합니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;특히&amp;nbsp;비밀번호,&amp;nbsp;토큰,&amp;nbsp;주민번호와&amp;nbsp;같은&amp;nbsp;정보는&amp;nbsp;URL에&amp;nbsp;노출될&amp;nbsp;경우&amp;nbsp;보안&amp;nbsp;사고로&amp;nbsp;이어질&amp;nbsp;수&amp;nbsp;있으므로,&amp;nbsp;POST&amp;nbsp;본문을&amp;nbsp;활용하고&amp;nbsp;가능하면&amp;nbsp;HTTPS를&amp;nbsp;통해&amp;nbsp;암호화하여&amp;nbsp;전송해야&amp;nbsp;안전합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP 메서드인 PUT과 PATCH의 차이는 무엇인가요?&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;PUT&lt;/th&gt;
&lt;th&gt;PATCH&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;전체 리소스 &lt;b&gt;교체&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일부 필드 &lt;b&gt;수정&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 구조&lt;/td&gt;
&lt;td&gt;전체 객체 필요&lt;/td&gt;
&lt;td&gt;변경될 필드만 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;멱등성&lt;/td&gt;
&lt;td&gt;멱등 (같은 요청 여러 번 가능)&lt;/td&gt;
&lt;td&gt;멱등일 수도, 아닐 수도 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PUT&amp;nbsp;메서드는&amp;nbsp;전체&amp;nbsp;리소스를&amp;nbsp;대체하는&amp;nbsp;방식으로&amp;nbsp;동작하며,&amp;nbsp;해당&amp;nbsp;리소스를&amp;nbsp;통째로&amp;nbsp;덮어쓰기&amp;nbsp;때문에&amp;nbsp;요청&amp;nbsp;본문에는&amp;nbsp;전체&amp;nbsp;객체&amp;nbsp;구조가&amp;nbsp;포함되어야&amp;nbsp;합니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;반면&amp;nbsp;PATCH는&amp;nbsp;리소스의&amp;nbsp;일부&amp;nbsp;필드만&amp;nbsp;선택적으로&amp;nbsp;수정할&amp;nbsp;때&amp;nbsp;사용되며,&amp;nbsp;수정하고자&amp;nbsp;하는&amp;nbsp;필드만&amp;nbsp;전달하면&amp;nbsp;됩니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;예를&amp;nbsp;들어&amp;nbsp;사용자의&amp;nbsp;모든&amp;nbsp;정보를&amp;nbsp;업데이트할&amp;nbsp;때는&amp;nbsp;PUT을&amp;nbsp;사용하고,&amp;nbsp;비밀번호만&amp;nbsp;변경할&amp;nbsp;경우&amp;nbsp;PATCH를&amp;nbsp;사용하는&amp;nbsp;것이&amp;nbsp;적절합니다.&amp;nbsp;PUT은&amp;nbsp;동일한&amp;nbsp;요청을&amp;nbsp;여러&amp;nbsp;번&amp;nbsp;보내더라도&amp;nbsp;결과가&amp;nbsp;같기&amp;nbsp;때문에&amp;nbsp;멱등성을&amp;nbsp;가지지만,&amp;nbsp;PATCH는&amp;nbsp;구현&amp;nbsp;방식에&amp;nbsp;따라&amp;nbsp;멱등성이&amp;nbsp;보장되지&amp;nbsp;않을&amp;nbsp;수도&amp;nbsp;있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. 리다이렉션의 정확한 의미는?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리다이렉션은 서버가 클라이언트에게&lt;br /&gt;&lt;b&gt;&amp;ldquo;요청한 리소스는 다른 곳으로 이동되었어요&amp;rdquo;&lt;/b&gt; 라고 알려주는 응답입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대표 상태 코드: &lt;code&gt;301&lt;/code&gt;, &lt;code&gt;302&lt;/code&gt;, &lt;code&gt;303&lt;/code&gt;, &lt;code&gt;307&lt;/code&gt;, &lt;code&gt;308&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;함께 전달되는 &lt;code&gt;Location&lt;/code&gt; 헤더를 통해 &lt;b&gt;이동할 URL 경로&lt;/b&gt;가 포함됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;HTTP/1.1 301 Moved Permanently
Location: /new-page&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;리다이렉션은 서버가 클라이언트에게 요청한 리소스가 다른 위치로 이동되었음을 알리는 응답을 보내는 것을 말합니다. 이때 클라이언트는 응답에 포함된 Location 헤더 값을 참고하여 자동으로 새 위치로 이동합니다. &lt;br /&gt;&lt;br /&gt;대표적인 상태 코드는 301 Moved Permanently, 302 Found, 303 See Other, 307 Temporary Redirect, 308 Permanent Redirect 등이 있으며, 각각 리다이렉션의 성격에 따라 영구/임시 여부와 요청 방식 유지 여부 등이 다릅니다. 예를 들어 301은 해당 리소스가 완전히 이동되었음을 의미합니다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP 요청 메시지를 보낸 클라이언트들이 이전에 접속한 URL을 알고 싶을 때?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ Referer&lt;s&gt;(오타 아님)&lt;/s&gt; 헤더를 확인하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;Referer: https://www.example.com/previous-page&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저가 이전에 방문한 페이지의 URL을 서버로 전송함&lt;/li&gt;
&lt;li&gt;사용 예시: 유입 경로 분석, 보안 정책 설정 (e.g., 이미지 hotlinking 방지)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이전 페이지에서 현재 페이지로 이동했을 때의 URL 정보를 알고 싶다면, 요청에 포함된 Referer 헤더를 확인하면 됩니다. &lt;br /&gt;&lt;br /&gt;이 헤더는 클라이언트(주로 브라우저)가 현재 요청을 보내기 전 어떤 페이지에서 왔는지를 나타내는 정보를 담고 있어, 유입 경로 분석이나 리퍼러 기반 접근 제어 등에 사용됩니다. &lt;br /&gt;&lt;br /&gt;예를 들어, 이미지 핫링크 방지를 위해 특정 사이트에서 온 요청만 허용하는 등의 보안 정책을 설정할 때도 활용됩니다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP 요청 메시지를 보낸 클라이언트들의 접속 정보를 알고 싶을 때?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ User-Agent 헤더를 확인합니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/123.0&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저, 운영체제, 디바이스 정보가 포함됨&lt;/li&gt;
&lt;li&gt;사용 예시: 사용자 환경별 렌더링, 크롤러 식별 등&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클라이언트의 브라우저 종류나 운영체제, 디바이스 정보 등을 확인하고 싶을 때는 요청 메시지에 포함된 User-Agent 헤더를 확인합니다. &lt;br /&gt;&lt;br /&gt;이 헤더에는 예를 들어 &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/123.0&quot; 같은 문자열이 포함되며, 이를 통해 접속한 클라이언트의 환경을 유추할 수 있습니다. 이 정보는 다양한 디바이스에 맞게 화면을 조정하거나, 웹 크롤러와 일반 사용자를 구분하는 용도로도 사용됩니다.&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 다음을 학습했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 메서드를 통해 요청의 목적을 정의한다.&lt;/li&gt;
&lt;li&gt;상태 코드를 통해 요청 결과를 숫자로 표현한다.&lt;/li&gt;
&lt;li&gt;헤더를 통해 다양한 요청/응답 정보를 함께 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스트에서는 &lt;b&gt;HTTPS, TLS, 인증과 상태 유지 (쿠키/세션/토큰)&lt;/b&gt; 등을 심화 학습할 예정입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;『이것이 취업을 위한 컴퓨터 과학이다』, p.448~463&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@lama.ibrahim96/top-10-http-status-code-you-need-to-know-as-a-front-end-developer-22e283c9f91f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;ldquo;Top&amp;nbsp;10&amp;rdquo;&amp;nbsp;HTTP&amp;nbsp;Status&amp;nbsp;Code&amp;nbsp;explained&amp;nbsp;you&amp;nbsp;need&amp;nbsp;to&amp;nbsp;know&amp;nbsp;as&amp;nbsp;a&amp;nbsp;Front&amp;nbsp;End&amp;nbsp;Developer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN Web Docs &amp;ndash; HTTP Methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN Web Docs &amp;ndash; HTTP Status Codes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Network</category>
      <category>body</category>
      <category>Header</category>
      <category>HTTP</category>
      <category>message</category>
      <category>network</category>
      <category>statuscode</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/41</guid>
      <comments>https://readyoun.tistory.com/41#entry41comment</comments>
      <pubDate>Wed, 26 Mar 2025 03:23:47 +0900</pubDate>
    </item>
    <item>
      <title>[1편] 브라우저는 어떻게 서버를 찾을까? &amp;ndash; DNS와 HTTP 메시지 구조까지</title>
      <link>https://readyoun.tistory.com/40</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7sdKa/btsMW8izLMC/SoQI4zkeo1664AayvmiKo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7sdKa/btsMW8izLMC/SoQI4zkeo1664AayvmiKo1/img.png&quot; data-alt=&quot;flaticon - kerismaker&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7sdKa/btsMW8izLMC/SoQI4zkeo1664AayvmiKo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7sdKa%2FbtsMW8izLMC%2FSoQI4zkeo1664AayvmiKo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;512&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;flaticon - kerismaker&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 들어가며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 개발을 하다 보면 가장 기초적이면서도 중요한 개념이 바로 HTTP입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;하지만 그 시작점인 &lt;b&gt;DNS&lt;/b&gt;, 그리고 &lt;b&gt;HTTP 메시지의 구조&lt;/b&gt;에 대해 정확히 알고 있어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 다음의 흐름을 따라가며 &lt;b&gt;웹 요청의 여정&lt;/b&gt;을 함께 따라가보겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 브라우저에 &lt;code&gt;www.example.com&lt;/code&gt;을 입력하면,&lt;/li&gt;
&lt;li&gt;어떻게 서버의 IP를 찾고,&lt;/li&gt;
&lt;li&gt;어떤 형식의 메시지를 주고받으며,&lt;/li&gt;
&lt;li&gt;어떻게 웹 페이지가 뜨는지?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. DNS와 URI/URL &amp;ndash; 웹 통신의 출발점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 도메인 네임과 DNS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터는 IP 주소(예: 1.2.3.4)로 통신하지만,&lt;br /&gt;우리는 &lt;b&gt;&lt;code&gt;www.example.com&lt;/code&gt;&lt;/b&gt; 같은 도메인 이름을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 IP로 바꿔주는 시스템이 바로 &lt;b&gt;DNS (Domain Name System)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, DNS는 사람이 읽기 쉬운 도메인 네임을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 컴퓨터가 이해할 수 있는 IP 주소로 &lt;b&gt;변환(resolve)&lt;/b&gt; 해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccIsTq/btsMW0yeJ5C/yb9bzb0QkO0DvfQ2XxCHF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccIsTq/btsMW0yeJ5C/yb9bzb0QkO0DvfQ2XxCHF1/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』 p.432&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccIsTq/btsMW0yeJ5C/yb9bzb0QkO0DvfQ2XxCHF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccIsTq%2FbtsMW0yeJ5C%2Fyb9bzb0QkO0DvfQ2XxCHF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;265&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』 p.432&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DNS 서버 역할&lt;/b&gt;: 사용자가 입력한 도메인을 해석하여 IP를 반환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DNS 질의 흐름&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;루트 네임 서버&lt;/li&gt;
&lt;li&gt;최상위 도메인(TLD, &lt;code&gt;.com&lt;/code&gt; 등)&lt;/li&gt;
&lt;li&gt;권한 네임 서버(예: example.com을 관리)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  예시 흐름: www.example.com &amp;rarr; 루트 &amp;rarr; TLD &amp;rarr; NS &amp;rarr; IP 주소 반환&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. FQDN과 도메인 구성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;www.example.com&lt;/code&gt;은 &lt;b&gt;FQDN (Fully Qualified Domain Name)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 정확한 서버를 찾기 위한 전체 경로&lt;/li&gt;
&lt;li&gt;구성: &lt;code&gt;호스트 이름(www)&lt;/code&gt; + &lt;code&gt;도메인 이름(example)&lt;/code&gt; + &lt;code&gt;최상위 도메인(com)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  면접 대비 포인트:&lt;br /&gt;FQDN이란 무엇인가요? &amp;rarr; &quot;정확히 하나의 호스트를 지칭할 수 있는 전체 도메인 네임입니다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Name Server와 DNS 질의 과정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 네임 서버(Name Server)란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 질의를 처리하는 서버로, &lt;b&gt;도메인 이름을 관리&lt;/b&gt;하며 &lt;b&gt;계층 구조&lt;/b&gt;를 가집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;루트 네임 서버&lt;/b&gt;: 최상위 &lt;code&gt;.com&lt;/code&gt;, &lt;code&gt;.org&lt;/code&gt; 등으로 연결&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TLD 네임 서버&lt;/b&gt;: &lt;code&gt;.com&lt;/code&gt;, &lt;code&gt;.net&lt;/code&gt; 등 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;권한 네임 서버&lt;/b&gt;: 실제 도메인의 IP 정보 보유&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. 질의 흐름과 캐싱&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxBXm2/btsMVEwceUm/kdKMmEMpYkDNPSnmkhQv4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxBXm2/btsMVEwceUm/kdKMmEMpYkDNPSnmkhQv4K/img.png&quot; data-alt=&quot;『이것이 취업을 위한 컴퓨터 과학이다』 p.434&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxBXm2/btsMVEwceUm/kdKMmEMpYkDNPSnmkhQv4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxBXm2%2FbtsMVEwceUm%2FkdKMmEMpYkDNPSnmkhQv4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;286&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;『이것이 취업을 위한 컴퓨터 과학이다』 p.434&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트&lt;/b&gt; &amp;rarr; 로컬 DNS 서버 (ISP 또는 OS 내)&lt;/li&gt;
&lt;li&gt;로컬 DNS 서버가 없으면 &lt;b&gt;재귀 질의&lt;/b&gt;를 통해 루트부터 탐색&lt;/li&gt;
&lt;li&gt;자주 쓰이는 도메인은 &lt;b&gt;DNS 캐시&lt;/b&gt;에 저장되어 응답 속도 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  캐시의 TTL(Time To Live)은 제한 시간 내 재사용 가능&lt;br /&gt;  대표적인 퍼블릭 DNS: 8.8.8.8 (Google), 1.1.1.1 (Cloudflare)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. DNS 레코드 타입 &amp;ndash; 도메인과 IP를 연결하는 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 서버에는 다양한 형태의 레코드(기록)가 존재합니다. 이를 통해 도메인 이름이 어떤 리소스를 가리키는지 정의할 수 있습니다.&lt;/p&gt;
&lt;table style=&quot;height: 247px;&quot; width=&quot;322&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;레코드 타입&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;도메인 &amp;rarr; IPv4 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AAAA&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;도메인 &amp;rarr; IPv6 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CNAME&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;도메인 &amp;rarr; 다른 도메인 이름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;NS&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;도메인에 대한 권한 네임 서버 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MX&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메일 서버 관련 레코드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  실무 예시:&lt;br /&gt;example.com &amp;rarr; A 레코드 &amp;rarr; 1.2.3.4&lt;br /&gt;www.example.com &amp;rarr; CNAME &amp;rarr; example.com&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. URI와 URL &amp;ndash; 리소스를 가리키는 방식&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5-1. URI, URL, URN의 차이&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;용어&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;URI&lt;/td&gt;
&lt;td&gt;자원 식별자 전체 개념&lt;/td&gt;
&lt;td&gt;urn:isbn:0451450523&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL&lt;/td&gt;
&lt;td&gt;자원의 위치 (주소)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://example.com/index.html&quot;&gt;https://example.com/index.html&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URN&lt;/td&gt;
&lt;td&gt;이름 기반 식별&lt;/td&gt;
&lt;td&gt;urn:isbn:1234&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;URL은 URI의 한 형태&lt;/b&gt;이며, 우리가 주로 사용하는 주소는 대부분 URL입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. URL의 구성 요소 상세 분석&lt;/h2&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;https://www.example.com:8042/over/there?name=ferret#nose
└──────┬──────┘ └────┬────┘ └──────┬────┘ └──────┬──────┘ └───┬───┘
 scheme  host(DN/IP)   port      path         query         fragment&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 구성요소&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;요소&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;scheme&lt;/td&gt;
&lt;td&gt;프로토콜 명시 (http, https 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;authority&lt;/td&gt;
&lt;td&gt;호스트 주소 (도메인 or IP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;path&lt;/td&gt;
&lt;td&gt;리소스의 경로 (/images/logo.png)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;query&lt;/td&gt;
&lt;td&gt;파라미터 (ex. ?name=value)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fragment&lt;/td&gt;
&lt;td&gt;특정 위치(anchor)로 스크롤 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  실무 예시:&lt;br /&gt;/search?keyword=book &amp;rarr; 검색 키워드&lt;br /&gt;#section1 &amp;rarr; 페이지 내 특정 위치로 이동&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. HTTP의 특징 4가지&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 특징은 HTTP가 웹에서 널리 쓰이는 이유이기도 하며, API 설계나 성능 최적화, 인증 처리 등에서 자주 언급됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;① 요청 응답 기반 프로토콜&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 클라이언트가 &lt;b&gt;요청(Request)&lt;/b&gt;을 보내고, 서버가 그에 대한 &lt;b&gt;응답(Response)&lt;/b&gt;을 보내는 구조로 동작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 브라우저, 앱 등이 요청을 보내고, 서버는 그에 맞는 HTML, JSON 등의 데이터를 응답합니다.&lt;br /&gt;- 단방향 통신이기 때문에, &lt;b&gt;서버는 클라이언트에게 먼저 메시지를 보낼 수 없습니다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  실전 포인트:&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;서버가 먼저 메시지를 보내야 하는 경우는 WebSocket, SSE 같은 별도 기술이 필요합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;② 미디어 독립적 프로토콜&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 전송하는 &lt;b&gt;데이터의 종류에 제한이 없습니다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;HTML, CSS, JS, 이미지, JSON, PDF 등 모든 콘텐츠 유형을 전송할 수 있으며,&amp;nbsp;&amp;nbsp;&lt;br /&gt;어떤 콘텐츠가 오가는지는 &lt;b&gt;Content-Type&lt;/b&gt; 헤더를 통해 명시합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742920765592&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 HTTP는 문서 전송뿐 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API, 이미지 전송, 동영상 스트리밍 등 모든 웹 기능에 대응할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;✅&amp;nbsp;이&amp;nbsp;특성&amp;nbsp;덕분에&amp;nbsp;웹이&amp;nbsp;&amp;lsquo;문서&amp;nbsp;중심&amp;rsquo;에서&amp;nbsp;&amp;lsquo;앱&amp;nbsp;플랫폼&amp;rsquo;으로&amp;nbsp;진화할&amp;nbsp;수&amp;nbsp;있었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;③ 스테이트리스 프로토콜 (Stateless)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 상태를 유지하지 않는(stateless) 프로토콜입니다.&lt;br /&gt;&lt;br /&gt;서버는&amp;nbsp;&lt;b&gt;각&amp;nbsp;요청이&amp;nbsp;독립적&lt;/b&gt;이라고&amp;nbsp;가정하고,&amp;nbsp;&lt;b&gt;이전&amp;nbsp;요청의&amp;nbsp;정보를&amp;nbsp;저장하지&amp;nbsp;않습니다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;이 덕분에 서버 구조는 단순하고, &lt;b&gt;확장성(Scalability)&lt;/b&gt;이 뛰어나지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 상태 유지, 장바구니 유지 등 사용자 상태 저장이 필요한 기능은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; text-align: left;&quot;&gt;별도 기술로 구현해야 합니다. (&amp;rarr; 쿠키, 세션, 토큰 등)&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  면접 단골 질문:&lt;/b&gt;&lt;br /&gt;&amp;ldquo;Stateless한 HTTP에서 사용자 인증 상태는 어떻게 유지할까요?&amp;rdquo;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;④&amp;nbsp;지속&amp;nbsp;연결&amp;nbsp;프로토콜&amp;nbsp;(Persistent&amp;nbsp;Connection)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 HTTP는 요청-응답 후 연결을 끊었지만,&lt;br /&gt;HTTP/1.1부터는&amp;nbsp;연결을&amp;nbsp;유지하여&amp;nbsp;여러&amp;nbsp;요청을&amp;nbsp;한&amp;nbsp;번에&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;&amp;lsquo;지속&amp;nbsp;연결&amp;rsquo;을&amp;nbsp;지원합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예전 방식: 요청할 때마다 TCP 연결 &amp;rarr; 비효율&lt;/li&gt;
&lt;li&gt;지속 연결: 하나의 TCP 연결로 여러 요청/응답 처리 &amp;rarr; 지연(latency) 감소, 속도 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1742920970338&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Connection: keep-alive&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;특히&amp;nbsp;브라우저는&amp;nbsp;HTML,&amp;nbsp;CSS,&amp;nbsp;JS,&amp;nbsp;이미지&amp;nbsp;등&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다수의&amp;nbsp;리소스를&amp;nbsp;병렬로&amp;nbsp;요청해야&amp;nbsp;하므로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지속&amp;nbsp;연결은&amp;nbsp;필수적입니다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt; &amp;nbsp;이후&amp;nbsp;등장한&amp;nbsp;HTTP/2,&amp;nbsp;HTTP/3는&amp;nbsp;이&amp;nbsp;특성을&amp;nbsp;더욱&amp;nbsp;강화합니다.&amp;nbsp;(멀티플렉싱,&amp;nbsp;스트림&amp;nbsp;병렬화&amp;nbsp;등)&lt;br /&gt;&lt;br /&gt;이처럼 HTTP의 4가지 특징은 단순한 개념이 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt; &amp;nbsp;웹의&amp;nbsp;작동&amp;nbsp;원리와&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;서비스&amp;nbsp;설계,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;보안&amp;nbsp;및&amp;nbsp;인증&amp;nbsp;처리,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;성능&amp;nbsp;최적화에까지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영향을&amp;nbsp;줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MIME 타입 (Content-Type)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 다양한 미디어 타입을 지원합니다.&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;타입&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;서브타입&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;plain, html, css&lt;/td&gt;
&lt;td&gt;텍스트 문서, HTML, 스타일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #f9f9f9;&quot;&gt;image&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9;&quot;&gt;jpeg, png, gif&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9;&quot;&gt;이미지 리소스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;video&lt;/td&gt;
&lt;td&gt;mp4, webm&lt;/td&gt;
&lt;td&gt;영상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;background-color: #f9f9f9;&quot;&gt;application&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9;&quot;&gt;json, pdf&lt;/td&gt;
&lt;td style=&quot;background-color: #f9f9f9;&quot;&gt;데이터 포맷&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. HTTP 메시지 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 메시지는 요청과 응답 두 종류로 나뉘며, 다음과 같은 구조를 가집니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 요청 메시지 구조&lt;/h4&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작 라인: 요청 방식(GET), 경로, HTTP 버전&lt;/li&gt;
&lt;li&gt;헤더 필드: 요청 정보들 (브라우저 종류, 허용 포맷 등)&lt;/li&gt;
&lt;li&gt;본문: (POST일 경우) 추가 데이터&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 응답 메시지 구조&lt;/h4&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 648

&amp;lt;html&amp;gt;...&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태 라인: HTTP 버전 + 상태 코드 + 상태 메시지&lt;/li&gt;
&lt;li&gt;헤더 필드: 응답 정보&lt;/li&gt;
&lt;li&gt;본문: 실제 콘텐츠&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;면접 질문&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. HTTP가 스테이트풀한지, 스테이트리스한지에 대해 그 이유와 함께 설명하세요.&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP는 스테이트리스(Stateless) 프로토콜입니다.&lt;/li&gt;
&lt;li&gt;특징:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 요청은 독립적으로 처리&lt;/li&gt;
&lt;li&gt;이전 요청의 정보를 저장하지 않음&lt;/li&gt;
&lt;li&gt;쿠키, 세션으로 상태 관리 보완&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장점: 서버 확장성 향상, 효율적인 자원 관리&lt;/li&gt;
&lt;li&gt;단점: 클라이언트의 추가 정보 전송 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: HTTP는 각각의 요청이 독립적으로 처리되는 스테이트리스 프로토콜로, 서버가 클라이언트의 이전 요청 정보를 저장하지 않아 확장성과 자원 관리 측면에서 효율적이지만, 상태 유지가 필요한 경우 쿠키나 세션과 같은 추가적인 방법을 사용해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. 웹 브라우저에서 '&lt;a href=&quot;https://www.google.com'&quot;&gt;https://www.google.com'&lt;/a&gt; 접속 과정&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DNS 조회: 도메인 이름 &amp;rarr; IP 주소 변환&lt;/li&gt;
&lt;li&gt;TCP 연결 수립 (3-way handshake)&lt;/li&gt;
&lt;li&gt;SSL/TLS 핸드셰이크&lt;/li&gt;
&lt;li&gt;HTTP 요청 전송&lt;/li&gt;
&lt;li&gt;서버 응답 처리&lt;/li&gt;
&lt;li&gt;웹 브라우저 렌더링&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 웹 브라우저에서 구글 접속 시, DNS를 통해 도메인 이름을 IP 주소로 변환하고, TCP 3-way handshake로 연결을 수립한 후, SSL/TLS 핸드셰이크로 보안 연결을 설정합니다. 이후 HTTP 요청을 전송하고 서버로부터 응답을 받아 웹 브라우저가 이를 렌더링하여 사용자에게 보여줍니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q. 도메인 네임 웹사이트 연동 과정&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;도메인 등록 업체에서 도메인 구매&lt;/li&gt;
&lt;li&gt;네임서버 설정&lt;/li&gt;
&lt;li&gt;DNS 레코드 설정 (A 레코드, CNAME 등)&lt;/li&gt;
&lt;li&gt;전파 시간 대기 (24-48시간)&lt;/li&gt;
&lt;li&gt;DNS 설정 확인 및 연결 테스트&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 도메인 네임을 웹사이트에 연동하기 위해서는 먼저 도메인 등록 업체에서 도메인을 구매하고, 호스팅 서버의 네임서버를 설정한 후, A 레코드나 CNAME 등의 DNS 레코드를 설정합니다. 이후 DNS 설정이 전파되는 시간(보통 24-48시간)을 기다린 후, 연결이 제대로 되었는지 확인하고 테스트합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리: HTTP 요청의 출발점 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 다음을 중심으로 정리했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저가 도메인을 입력하면, DNS를 통해 IP를 조회&lt;/li&gt;
&lt;li&gt;조회된 IP로 TCP 연결 후, HTTP 요청 메시지 전송&lt;/li&gt;
&lt;li&gt;HTTP 4가지 특징&lt;/li&gt;
&lt;li&gt;요청 메시지에는 메서드, 경로, 헤더, 본문이 포함&lt;/li&gt;
&lt;li&gt;응답 메시지로는 상태 코드 + 콘텐츠가 돌아옴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이 구조는 API 설계, 네트워크 디버깅, 면접 질문 어디서든 기반이 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다음 편 예고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ [2편]에서는 상태 코드, 쿠키/세션, HTTPS, 그리고 HTTP의 진화(1.1/2.0/3.0)를 살펴봅니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버는 어떻게 로그인 상태를 기억할까요? HTTPS는 왜 필요한 걸까요?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;『이것이 취업을 위한 컴퓨터 과학이다』 p.431~447&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN - HTTP 메시지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/what-is-dns/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cloudflare - What is DNS?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Network</category>
      <category>HTTP</category>
      <category>network</category>
      <author>readyoun</author>
      <guid isPermaLink="true">https://readyoun.tistory.com/40</guid>
      <comments>https://readyoun.tistory.com/40#entry40comment</comments>
      <pubDate>Wed, 26 Mar 2025 01:47:24 +0900</pubDate>
    </item>
  </channel>
</rss>