<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>꾸준함</title>
    <link>https://jaimemin.tistory.com/</link>
    <description>메일: jaimemin@naver.com</description>
    <language>ko</language>
    <pubDate>Sat, 30 May 2026 14:11:39 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>꾸준함.</managingEditor>
    <image>
      <title>꾸준함</title>
      <url>https://t1.daumcdn.net/cfile/tistory/223EB5455913CB5E15</url>
      <link>https://jaimemin.tistory.com</link>
    </image>
    <item>
      <title>[7장] 몽고DB 고급 쿼리</title>
      <link>https://jaimemin.tistory.com/2733</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;집계 프레임워크 소개&lt;/b&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;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;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/41e8f838319aed6ba187cce1ee636d62.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB의 집계가 제공하는 이점&lt;/b&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;몽고DB 집계 시스템의 주요 이점은 네 가지 측면에서 살펴볼 수 있음
&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;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;집계 스테이지&lt;/b&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;몽고DB의 집계 프레임워크는 데이터 처리와 분석을 위한 강력한 도구 시스템이며 기본 CRUD 작업의 범위를 넘어서 데이터의 변환, 필터링, 그리고 의미 있는 통찰력 도출을 가능하게 하는 유연하고 효율적인 방법을 제공함&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;b&gt;$match: &lt;/b&gt;$match는 지정된 조건에 부합하는 문서만을 선별하여 파이프라인의 다음 단계로 전달하는 연산자이며 초기 단계에서 활용하는 것이 바람직함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$limit:&lt;/b&gt; 필요한 결과만을 효율적으로 얻기 위해서는 파이프라인의 초기 단계에서 $limit을 사용하여 후속 단계에서 처리해야 할 문서의 수를 제한하는 것을 권장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$sort:&lt;/b&gt; 데이터 정렬이 필요한 경우, 정렬 인덱스가 이미 구성되어 있다면 이를 활용하는 것이 성능 최적화에 매우 효과적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$skip:&lt;/b&gt; 파이프라인에서 처음 N개의 문서를 제외한 나머지 문서를 후속 단계로 전달하는 역할&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$project, $set, $addFields:&lt;/b&gt; 문서의 구조를 변경하는 데 사용되며, 주로 파이프라인의 최종 단계에서 활용되는데 이는 클라이언트에게 전달할 특정 필드들을 선별하고 구조화하는 데 있어 핵심적인 역할을 수행 &lt;span style=&quot;color: #ee2323;&quot;&gt;(최종 출력 형태를 결정하는 만큼, 효율적인 전달과 활용을 위해 신중하게 구성해야 함)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$group:&lt;/b&gt; 데이터 처리 과정에서 데이터셋을 정제하고 축소한 후, 특정 기준에 따라 데이터를 체계적으로 그룹화하는 데 활용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$unwind:&lt;/b&gt; 배열 형태의 필드를 분리하여 요소별로 독립된 새로운 문서를 생성하는 데 사용되며 해당 연산자를 통해 배열 데이터를 개별 문서로 변환함으로써 더 상세한 분석과 처리가 가능해짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$lookup:&lt;/b&gt; 서로 다른 컬렉션 간의 왼쪽 외부 조인을 수행하는 연산자이며 현재 집계 중인 컬렉션의 문서를 다른 컬렉션의 문서와 연결하는 데 사용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$geoNear:&lt;/b&gt; 지정된 위치를 기준으로 문서들을 거리순으로 정렬하는 데 사용되며 가장 가까운 위치부터 먼 위치 순으로 문서들을 배열하며, 이를 위해서는 해당 컬렉션에 지리 공간 정보가 포함된 필드와 그에 관한 지리 공간 인덱스가 반드시 구성되어 있어야 함 &lt;span style=&quot;color: #ee2323;&quot;&gt;(해당 연산자는 반드시 집계 파이프라인의 첫 번째 단계에서만 사용할 수 있으며, 이는 지리 공간 데이터 처리의 특성상 불가피한 제약)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$redact:&lt;/b&gt; 문서에 저장된 메타데이터나 속성을 기반으로 문서의 접근 범위를 효과적으로 제한할 수 있게 해 주며 주로 조직의 데이터 접근 제어 정책을 구현하는 데 활용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$replaceWith:&lt;/b&gt; 입력 문서의 내용을 지정된 새로운 문서로 완전히 대체하는 데 사용되며 문서의 구조를 근본적으로 변경하고나 재구성할 수 있음; 특히 복잡한 중첩 구조를 단순화하거나 특정 하위 문서를 상위 수준으로 승격시키는 데 효과적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/d6755334f102b587a81a0726c687ed54.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;쿼리 기술&lt;/b&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;/ul&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;b&gt;1. 논리와 비교 연산자&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB의 쿼리 언어는 논리 연산자와 비교 연산자를 통해 데이터를 세밀하게 필터링하고 선택할 수 있는 기능을 제공함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;$or:&lt;/b&gt; 지정된 여러 조건 중 하나라도 충족하는 문서를 검색하여 반환하는 논리 OR 연산을 수행하며 다양한 조건을 유연하게 조합하여 원하는 데이터를 효과적으로 찾아낼 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$and:&lt;/b&gt; 여러 조건을 모두 만족하는 문서를 검색하는 노리 AND 연산을 수행하며 몽고DB에서는 별도의 연산자를 지정하지 않을 경우 기본적으로 AND 연산을 수행하지만, 쿼리의 의도를 명확히 전달하기 위해 해당 연산자를 명시적으로 사용하는 경우가 많음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$not:&lt;/b&gt; 지정된 조건과 일치하지 않는 문서를 선별하는 부정 연산을 수행하며 원하지 않는 조건을 제외하거나, 특정 패턴에 부합하지 않는 데이터를 찾아내는 데 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$nor:&lt;/b&gt; 주어진 모든 조건을 만족하지 않는 문서를 찾아내는데 사용하며 여러 가지 배제 조건을 동시에 적용해야 할 때 특히 유용한 연산자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$in, $nin:&lt;/b&gt; 특정 필드의 값이 지정된 배열 내의 값들과 일치하거나 전혀 일치하지 않는 문서를 검색하는 데 사용하며 여러 가지 가능한 값 중 하나와 일치하는 문서를 효율적으로 찾아내야 할 때 매우 유용함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$eq:&lt;/b&gt; 데이터베이스에서 특정 필드의 값이 지정된 값과 정확히 일치하는 문서를 검색하는 데 사용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$ne:&lt;/b&gt; 데이터베이스에서 특정 필드의 값이 지정된 값과 일치하지 않는 문서를 검색하는 데 사용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$gt, $lt:&lt;/b&gt; 몽고DB에서 수치 기반의 데이터 필터링을 수행하는 데 사용되는 핵심적인 비교 연산자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$gte, $lte:&lt;/b&gt; 몽고DB에서 포괄적인 범위 검색을 수행하는 데 사용되는 비교 연산자&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/ccc7bfbe878fe6ee5727c9b114bd72ec.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;2. 배열 쿼리와 조작&lt;/b&gt;&lt;/h4&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;특히 $elemMatch, $all과 같은 검색 연산자와 $push, $pull과 같은 수정 연사를 통해 배열 기반의 데이터 구조를 정밀하게 다룰 수 있음&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;b&gt;$all:&lt;/b&gt; 몽고DB에서 배열 필드가 특정 요소들을 모두 포함하는 문서를 검색할 때 사용되며 여러 조건을 동시에 만족하는 배열 데이터를 찾아내는 데 매우 효과적인 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$elemMatch:&lt;/b&gt; 지정된 모든 쿼리 조건과 일치하는 요소가 하나 이상 있는 배열 필드가 포함된 문서를 조회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$size:&lt;/b&gt; 배열이 정확히 지정된 수의 요소를 포함하고 있는 문서를 조회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$push:&lt;/b&gt; 배열에 새로운 요소를 추가하는 기능을 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$pull:&lt;/b&gt; 배열에서 조건에 맞는 요소를 제거하는 기능을 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$addToSet:&lt;/b&gt; 배열 내 동일한 값이 없는 경우에만 새로운 요소를 추가하는 기능을 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$pop:&lt;/b&gt; 배열의 처음이나 끝에서 요소를 삭제할 때 사용하며 매개변수로 -1을 전달하면 배열의 첫 번째 요소가 삭제되고, 1을 전달하면 마지막 요소가 삭제됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/0a9407b55f049336e8eccce698b5b512.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;3. 배열 필드의 출력 제어 기법&lt;/b&gt;&lt;/h4&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;$, $elemMatch, $slice와 같은 연산자를 활용하면 필요한 데이터만 선별적으로 조회할 수 있어, 네트워크 대역폭 사용량과 처리 시간을 줄일 수 있으며 이를 통해 데이터베이스 작업의 효율성을 크게 높일 수 있음
&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;$elemMatch:&lt;/b&gt; 배열 요소에 관해 여러 조건을 동시에 적용할 수 있음; 적어도 하나의 배열 요소가 지정된 모든 조건을 충족해야 하며, 이는 특히 객체로 구성된 배열을 다룰 때 효과적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$slice:&lt;/b&gt; 배열에서 반환할 요소의 개수를 지정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/885c4b70bab6059ae5df64355c83a2ed.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;인덱스와 쿼리 최적화&lt;/b&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;인덱스가 없다면 몽고DB는 원하는 결과를 찾기 위해 컬렉션의 모든 문서를 검색해야 하는 반면 인덱스를 활용하면 검색 대상 문서의 수를 대폭 줄일 수 있어 쿼리 처리가 훨씬 효율적으로 이루어짐&lt;/li&gt;
&lt;/ul&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;b&gt;1. 인덱스 사용의 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB에서 인덱스의 장점은 다음과 같음
&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;메모리 사용 최적화:&lt;/b&gt; 인덱스를 활용하면 필요한 데이터만 메모리에 올릴 수 있어, 대용량 데이터 셋도 효율적으로 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #ee2323;&quot;&gt; 추가 저장 공간을 차지&lt;/span&gt;하므로, 인덱스를 생성할 필드를 신중하게 선택해야 함&lt;/li&gt;
&lt;li&gt;또한 인덱스는 읽기 성능은 향상하지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;데이터 수정 시 인덱스도 함께 갱신해야 하므로 쓰기 작업이 다소 느려질 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;2. 인덱스 종류&lt;/b&gt;&lt;/h4&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/a755459618eebe75403e2519d30615a6.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/2977e707cbfee858db6d75071b5877e9.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;li&gt;여러 값을 포함하는 배열 필드에서 특정 값을 검색할 때 성능을 크게 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/e5b3fe5b17152a3adedf1ee6598cf9d8.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;몽고DB는 배열의 각 요소를 자동으로 인덱싱하지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;복합 다중 키 인덱스에는 중요한 제약 사항이 있음&lt;/span&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;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/c806f7cf510b91e00af0610db8c84f8d.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;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;i.g. 게시물 검색 시 제목 필드에는 높은 가중치를, 본문 필드에는 낮은 가중치를 할당하여 제목에서 일치하는 결과를 상위에 표시할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/5a1692b89a3fcae9afa4ceaab19c7270.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/62111f0808f01f87a7517d919a8c7182.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;사. TTL 인덱스&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;li&gt;해당 인덱스를 활용하면 데이터의 수명 주기를 자동으로 관리할 수 있어, 시스템 관리자의 수동 개입 없이도 저장 공간을 효율적으로 유지할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/43a136708d01852dfb086f301cf5e3b1.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;사용자 이메일 주소나 제품 코드와 같이 고유성이 필요한 필드에 해당 인덱스를 적용하면, 몽고DB는 중복된 값이 삽입되는 것을 자동으로 방지함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/dc1aa3b855487e8ad600bc6bbeb061e0.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i.g. 활성 상태인 사용자 계정만 빠른 검색이 필요하거나, 최근 3개월 내의 거래 데이터만 자주 조회되는 경우에 유용하게 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/7d4cc9cd620b5757f26a4a4a5e7a7961.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB 위치 기반 데이터 처리&lt;/b&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;좌표는 위치 데이터를 표현하는 기본적인 방식으로, 경도와 위도 값으로 구성된 배열을 사용하며 이러한 좌표 데이터를 효율적으로 검색하기 위해 몽고DB는 2d 인덱스를 제공함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/00496f358468cf954b098b94ce305957.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;1. GeoJSON 개체&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GeoJSON 객체는 세 가지 유형이 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;점 (Point):&lt;/b&gt; 경도와 위도 좌표로 공간상의 한 지점을 나타냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선 (LineString):&lt;/b&gt; 두 개 이상의 점들이 연결되어 선을 형성함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다각형 (Polygon):&lt;/b&gt; 점들이 연결되어 닫힌 고리를 만들며, 이는 특정 영역을 정의함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;2. 위치 기반 인덱스&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치 기반 인덱스는 몽고DB에서 제공하는 특수 데이터 구조이며 공간 정보를 효율적으로 처리하여 위치 기반 검색의 성능을 크게 향상함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;2d 인덱스:&lt;/b&gt; 2d 인덱스는 2차원 평면에서의 위치 데이터를 효율적으로 처리하기 위해 설계되었으며 주로 위도와 경도로 구성된 자표 데이터를 다룰 때 사용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2dsphere 인덱스:&lt;/b&gt; 몽고DB에서 지구 표면상의 위치 데이털르 처리하기 위해 특별히 설계된 인덱스로 특정 지역 내 위치 검색, 주변 지역 탐색, 정확한 위치 매칭 등 다양한 공간 검색이 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;3. 위치 기반 연산자&lt;/b&gt;&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;$near:&lt;/b&gt; 지정된 위치를 중심으로 가까운 순서대로 결과를 정렬하여 반환하며 사용자 주변의 음식점이나 편의시설을 검색하는 등 근접 위치 검색에 특히 유용함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$nearSphere:&lt;/b&gt; 지구 표면을 기준으로 특정 위치로부터 가까운 지점들을 검색하며 실제 지구의 곡률을 고려하여 거리를 계산하므로 정확한 위치 기반 검색이 가능함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$geoWithin:&lt;/b&gt; 지정된 영역 안에 완전히 포함되는 위치 데이터를 검색하며 해당 연산자를 사용하면 특정 구역이나 경계 내의 모든 위치를 효율적으로 찾을 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$geoIntersects:&lt;/b&gt; 지정된 영역과 겹치거나 교차하는 모든 위치 데이터를 검색하며 도로망과 교차하는 건물 찾기, 특정 경로와 만나는 관심 지점 검색 등 복잡한 공간 분석에 활용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$maxDistance:&lt;/b&gt; $near, $nearSphere를 사용하는 위치 기반 검색에서 검색 범위를 제한하는 데 사용됨; 해당 연산자를 활용하면 배달 가능 거리 설정, 도보 가능 거리 내 시설 검색 등 실용적인 위치 기반 서비를 구현할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/c30f4d0fa418cdd24de6ff73bfbe1070.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마스터링 몽고DB 7.0&lt;/p&gt;</description>
      <category>DB/마스터링 몽고DB 7.0</category>
      <category>MongoDB</category>
      <category>몽고db</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2733</guid>
      <comments>https://jaimemin.tistory.com/2733#entry2733comment</comments>
      <pubDate>Tue, 15 Jul 2025 00:29:45 +0900</pubDate>
    </item>
    <item>
      <title>[6장] 스키마 설계와 데이터 모델링</title>
      <link>https://jaimemin.tistory.com/2732</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론&lt;/b&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;몽고DB와 같은 현대적 데이터베이스의 도입으로, 데이터 관리 전략의 패러다임이 크게 변화하고 있고 특히 유연성과 확장성을 고려한 데이터 구조화의 중요성이 더욱 주목받고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;관계형 데이터베이스를 위한 스키마 설계&lt;/b&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;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;/li&gt;
&lt;/ul&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;RDBMS에서 데이터 이상 현상은 데이터 수정 작업 과정에서 발생하는 정보의 불일치를 의미하며 이는 주로 데이터의 삽입, 삭제, 갱신과 같은 작업을 수행할 때 발생할 수 있음&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;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 정규형&lt;/b&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;/li&gt;
&lt;li&gt;정규형은 데이터베이스 구조를 체계적으로 개선하는 단계적 지침을 제공하며, 이를 통해 데이터 중복을 최소화하고 데이터 조작 과정에서 발생할 수 있는 각종 이상 현상을 예방할 수 있음&lt;/li&gt;
&lt;li&gt;정규형의 특징은 그 계층적 구조에 있고 각 단계의 정규형은 이전 단계의 정규형을 기반으로 하며, 더 높은 수준의 데이터 품질을 보장하기 위해서는 반드시 이전 단계의 요구사항을 충족해야 함&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;b&gt;제1 정규형:&lt;/b&gt; 중복을 제거하고 쿼리를 단순화시킴&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제2 정규형:&lt;/b&gt; 기본키에 관해 모든 비주요 속성이 완전 함수 종속 관계를 맺을 때, 데이터베이스에서 중복된 정보를 제거할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제3 정규형:&lt;/b&gt; 모든 속성이 기본키에만 함수 종속&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BCNF 정규형:&lt;/b&gt; 제3 정규형을 더욱 강화한 형태로, 테이블의 모든 비자명한 함수적 종속성이 반드시 슈퍼키를 통해 성립&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제4 정규형:&lt;/b&gt; 테이블에 다중값 종속성이 없음을 보장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제5 정규형:&lt;/b&gt; 데이터베이스 정규화 과정의 최상위 단계로 데이터베이스의 논리적 완전성을 극대화하기 위해 테이블을 더 작은 단위로 세분화하는 과정을 포함시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #ee2323;&quot;&gt;초기 도메인 모델보다 훨씬 많은 수의 테이블이 생성될 수 있다는 실질적인 한계를 가지고 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB를 위한 스키마 설계&lt;/b&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;효과적인 몽고DB 설계의 핵심은 사용자의 데이터 조회 요구사항을 정확히 파악하는 것이며 이는 시스템 엔티티의 구조를 결정하는 데 결정적인 역할&lt;/li&gt;
&lt;li&gt;관계형 데이터베이스가 정규화를 중시하고 데이터 중복을 지양하는 것과 달리, &lt;b&gt;몽고DB는 성능 최적화와 유연성 확보를 위해 의도적으로 데이터 중복과 비정규화를 활용함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;몽고DB의 문서 모델은 독특한 강점을 제공함
&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;몽고DB는 내장 문서 수준에서도 상세한 쿼리 실행이 가능하므로, 문서 설계에 있어 상당한 자유도를 제공함&lt;/li&gt;
&lt;li&gt;데이터 접근 패턴을 자세히 분석함으로써, 어떤 필드를 문서에 직접 포함시킬지, 또는 별도의 컬렉션으로 분리하여 참조할지를 전략적으로 결정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB의 데이터 모델링&lt;/b&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;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;/li&gt;
&lt;/ul&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;위 두 요소의 균형점을 찾는 것이 몽고DB의 문서 기반 데이터 구조를 설계하는 데 핵심&lt;/li&gt;
&lt;/ul&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;b&gt;1. 문서 구조&lt;/b&gt;&lt;/h4&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;최대 100단계까지 중첩이 가능한 BSON 문서와 배열을 지원하는데, 이는 단순한 기술적 특징을 넘어 실질적인 이점을 제공함
&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;/li&gt;
&lt;/ul&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;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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 내장된 데이터&lt;/b&gt;&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션은 단일&amp;nbsp; 데이터베이스 작업만으로도 연관된 모든 데이터에 접근하고 수정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/60dcae9204b7de7d31da2d3cd7710890.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;b&gt;3. 참조&lt;/b&gt;&lt;/h4&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;대학 강좌 관리 시스템을 예로 들면, 강좌 문서는 교수의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;_id&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값을 참조하여 교수 정보와 연결됨&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;이러한 참조 기반 설계는 컬렉션 간 효율적인 데이터 연결을 가능하게 하며, 데이터의 정규화를 보장함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;특히 데이터의 일관성 유지와 중복 최소화가 중요한 환경에서 유용한 접근 방식&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/53e9259052d4a084795109d7108587c9.js&quot;&gt;&lt;/script&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;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;4. 비정규화&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB에서 비정규화는 전략적인 데이터 중복을 통해 읽기 성능을 최적화하는 설계 방식이며 이는 데이터의 중복성과 성능 사이의 균형을 고려한 의도적인 설계 결정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i.g. 도서 정보를 관리할 때 저자의 이름 authorName을 책 문서에 직접 포함시키는 방식을 고려할 수 있음&lt;/li&gt;
&lt;li&gt;이러한 접근 방식은 데이터 조회 시 단일 작업만으로 필요한 정보를 획득할 수 있어 &lt;b&gt;조회 성능이 현저히 향상&lt;/b&gt;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/1492ebd5c50466cdb4acc34fa5949f82.js&quot;&gt;&lt;/script&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;b&gt;5. BSON과 해당 데이터 유형&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Binary JSON은 몽고DB의 데이터 저장 기반을 형성하는 핵심 요소&lt;/li&gt;
&lt;li&gt;BSON은 JSON과 기본적인 구조는 유사하나, 더욱 다양한 데이터 타입을 지원하며 저장과 검색 성능에 최적화된 특성을 갖추고 있음&lt;/li&gt;
&lt;li&gt;BSON의 설계는 다음과 같은 세 가지 핵심 특성을 중심으로 이루어짐
&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; 데이터 저장과 전송에 있어 공간 효율성은 매우 중요한 요소이며, 이는 BSON 설계의 핵심 원칙 중 하나; 특히 네트워크를 통한 데이터 전송 시에는 공간 오버헤드의 최소화가 성능에 직접적인 영향을 미치며 BSON은 이러한 요구사항을 충족하기 위해 효율적인 데이터 압축과 저장 구조를 채택함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순회 가능:&lt;/b&gt; BSON의 순회 효율성은 몽고DB의 핵심 데이터 표현 방식으로 데이터 구조를 빠르고 효율적으로 탐색할 수 있도록 최적화되어 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효율적:&lt;/b&gt; BSON이 C 데이터 타입을 기반으로 설계되었다는 점은 매우 중요한 기술적 이점을 제공하는데 이러한 설계 선택은 다양한 프로그래밍 언어에서 BSON 데이터의 인코딩과 디코딩을 매우 효율적으로 수행할 수 있게 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;BSON은 몽고DB의 데이터 저장 시스템에서 중추적인 역할을 담당하며, 표준 JSON이 제공하는 것보다 더욱 포괄적인 데이터 타입을 지원함
&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;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB 데이터베이스 모델링: 설계 원칙과 권장 사례&lt;/b&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;몽고DB는 높은 수준의 유연성을 제공하지만, 이러한 유연성을 최대한 활용하기 위해서는 체계적인 데이터 구조화 방법 필요&lt;/li&gt;
&lt;/ul&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;b&gt;1. 읽기-쓰기 비율&lt;/b&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;/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;b&gt;읽기 고려 사항:&lt;/b&gt; 샤딩 클러스터에서의 데이터 접근 방식이 중요한데 특히 스캐더-개더 방식의 쿼리는 가능한 한 지양해야 하며, 이를 위해 연관된 데이터를 단일 문서에 내장하는 전략을 고려할 수 있음 (&lt;span style=&quot;color: #ee2323;&quot;&gt;다만, 과도한 데이터 내장은 문서 크기 증가와 수정 효율성 저하를 초래할 수 있으므로&lt;/span&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;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;설계 패턴과 스키마 설계&lt;/b&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;/ul&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;b&gt;1. 버킷 패턴&lt;/b&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;/li&gt;
&lt;li&gt;해당 패턴은 특히 시계역 데이터, 실시간 분석 그리고 IoT 애플리케이션에서 발생하는 대량의 스트리밍 데이터를 처리하는 데 탁월한 성능을 보여줌&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;/ul&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;실제 적용 사례를 살펴보면, IoT 환경에서의 온도 모니터링 시스템을 예로 들 수 있음
&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/bc5d5b4dfae009004c10445bc4a65e1e.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;2. 속성 패턴&lt;/b&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;/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;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/27061e17ac687a9c8d1e7319f0b964a0.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;3. 다형성 패턴&lt;/b&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;/li&gt;
&lt;li&gt;의료 데이터베이스를 예로 들자면 정기 건강검진 기록, 수술 기록, 치과 진료 기록과 같이 각기 다른 형태의 의료 기록을 하나의 시스템에서 통합적으로 관리해야 하는 경우가 이에 해당함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/2db7f528c8bc446ae909d1c5990eaf3a.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;4. 스키마 버전 관리 패턴&lt;/b&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;/li&gt;
&lt;li&gt;스키마 버전을 체계적으로 관리함으로써 애플리케이션이 다양한 스키마 형태를 효과적으로 처리할 수 있으며, 이는 데이터 마이그레이션과 수정 과정을 더욱 원활하게 해 줌&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/a7cf4b59714fa61def0d0425ee131ad1.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;5. 확장 참조 패턴&lt;/b&gt;&lt;/h4&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;자주 조회하는 필드를 주요 문서에 포함하는 확장 참조 패턴을 적용하면, JOIN 연산의 횟수를 줄이고 데이터 읽기 속도를 향상할 수 있음&lt;/li&gt;
&lt;li&gt;전자상거래 플랫폼의 예시를 통해 살펴보면, 주문 정보를 표시할 때 제품의 모든 상세 정보가 아닌 제품명과 가격과 같은 핵심 정보만을 포함하는 것이 일반적&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/348d4608e44e4247a9a84acf51361015.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;6. 근사치 패턴&lt;/b&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;/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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/0957abcc12414b8abab8cd8d38287b94.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;7. 계산된 패턴&lt;/b&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;/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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/f0387d85d46a29abd0716c2b4cb9e8d6.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;8. 이상치 패턴&lt;/b&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;/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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/548706b57961be6d1543d26ac115d2ec.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;9. 사전 할당 패턴&lt;/b&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;/li&gt;
&lt;li&gt;몽고DB 환경에서 필요한 저장 공간과 문서를 미리 생성해 둠으로써 데이터의 추가와 갱신 프로세스를 효율화할 수 있으며 이러한 접근 방식은 시스템 오버헤드를 최소화하고 안정적인 쓰기 작업을 보장함&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/4af9a9c9a4a8fc3f91fa64915c857ef5.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;10. 부분집합 패턴&lt;/b&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;/li&gt;
&lt;li&gt;특히 문서의 상당 부분이 실제 애플리케이션에서 활용되지 않는 대용량 문서를 처리할 때 효과적이며 이를 통해 시스템 자원을 효율적으로 활용하고 사용자 경험을 개선할 수 있음&lt;/li&gt;
&lt;li&gt;도서관 관리 시스템을 예로 들 수 있으며 각 도선에는 수백 개의 리뷰와 연결되어 있으나, 도서 목록 화면에서는 신속한 정보 탐색을 위해 최근 작성된 5개의 리뷰만을 표시함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/9ae88a126488267d29ad17fd66a69547.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;11. 트리 패턴&lt;/b&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;/li&gt;
&lt;li&gt;데이터가 상위-하위 관계를 형성하거나 트리 형태로 구성되어야 할 때에 특히 적합한 패턴&lt;/li&gt;
&lt;li&gt;참조 방식이나 임베딩 기법을 활용하여 조직 구조도, 파일시스템, 댓글 계층 구조 등을 체계적으로 표현할 수 있음&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/38a0d1788abf3425951d632741a31f26.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;정리&lt;/b&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;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;h4 data-ke-size=&quot;size20&quot;&gt;&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;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마스터링 몽고DB 7.0&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;</description>
      <category>DB/마스터링 몽고DB 7.0</category>
      <category>MongoDB</category>
      <category>몽고db</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2732</guid>
      <comments>https://jaimemin.tistory.com/2732#entry2732comment</comments>
      <pubDate>Fri, 11 Jul 2025 23:08:34 +0900</pubDate>
    </item>
    <item>
      <title>[5장] CRUD 작업과 기본 쿼리</title>
      <link>https://jaimemin.tistory.com/2731</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB 기본 데이터 작업&lt;/b&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;각각의 CRUD 작업은 다음고 ㅏ같은 고유한 목적을 가짐
&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;삭제 작업은 데이터베이스의 문서를 제거하는 데 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;1. mongosh를 이용한 CRUD 작업 수행&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh는 관계형 데이터베이스의 관리 콘솔과 같은 역할을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/25ed1620a7c56783819fb9cdba3196c2.js&quot;&gt;&lt;/script&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 예제를 통해 다음과 같은 주요 사항들을 확인 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;updateOne() 메서드에서 사용된 JSON 문서 { isbn: '101' }는 수정할 특정 문서를 찾기 위한 쿼리 필터&lt;/li&gt;
&lt;li&gt;matchedCount 객체는 쿼리와 일치하는 문서가 한 개 있음을 나타냄&lt;/li&gt;
&lt;li&gt;modifiedCount 객체는 실제로 수정된 문서가 한 개임을 보여줌&lt;/li&gt;
&lt;li&gt;$set 연산자를 통해 특정 필드의 값을 지정된 값으로 변경 가능&lt;/li&gt;
&lt;li&gt;다수의 문서가 필터 조건을 충족하더라도 updateOne() 메서드는 조건과 일치하는 첫 번째 문서만 수정&lt;/li&gt;
&lt;li&gt;find() 메서드를 통해 문서가 의도한 대로 수정되었음을 확인 가능&lt;/li&gt;
&lt;li&gt;문서 삭제 방법은 다양하지만 가장 간단한 방법으로는 문서의 고유 식별자인 _id 필드값을 기준으로 삭제하는 것&lt;/li&gt;
&lt;li&gt;결과가 없는 경우 mongosh는 셸 프롬프트 &amp;gt;만 표시할 뿐 다른 출력값을 반환하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;2. mongosh 스크립팅 활용법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh의 진정한 가치는 자바스크립트 REPL 환경을 제공한다는 점에 있으며 이를 통해 연속적으로 실행해야 하는 복잡한 관리 작업들을 수행할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/7eb35c6b3af7e315fa58aea61176524d.js&quot;&gt;&lt;/script&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크립트 실행 시 알아두면 유용한 주요 사항들은 다음과 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰기 작업은 기본적으로 w: &quot;majority&quot; 쓰기 보장 수준을 사용하는데 과반수 쓰기 보장 수준은 전체 서버의 과반수와 데이터 보유 서버 수 중 작은 값으로 결정됨; 이때 데이터를 보유하지 않은 중재자는 과반수 계산에서 제외됨&lt;/li&gt;
&lt;li&gt;스크립트의 실행 결과를 표준 출력으로 전달하려면 자바스크립트의 기본 제공 함수인 printf()를 사용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;가. mongosh 스크립팅과 대화형 실행 방식 비교&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;mongosh 스크립트 작성 시에는 셸 도우미 기능을 사용할 수 없음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;use &amp;lt;database_name&amp;gt;, show_collections와 같은 몽고DB 명령어들과 기타 도우미 기능들은 셸 내장 기능이므로 스크립트와 자바스크립트 실행 환경에서는 접근할 수 없음&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;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 200px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 22px;&quot;&gt;&lt;b&gt;shell helper method&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 22px;&quot;&gt;&lt;b&gt;자바스크립트 동등한 기능&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;show dbs, show databases&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db.adminCommand('listDatabases')&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;use &amp;lt;database_name&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db = db.getSiblingDB('&amp;lt;database_name&amp;gt;')&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;show collections&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db.getCollectionNames()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;show users&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db.getUsers()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;show roles&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db.getRoles({ showBuiltinRoles: true })&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;show log &amp;lt;logname&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db.adminCommand({ 'getLog': '&amp;lt;logname&amp;gt;' })&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;show logs&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 16px;&quot;&gt;db.adminCommand({ 'getLog': '*' })&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 50px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 50px;&quot;&gt;it&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 50px;&quot;&gt;cursor = db.collection.find()&lt;br /&gt;&lt;br /&gt;if (cursor.hasNext()) {cursor.next()}&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;b&gt;3. mongosh를 이용한 대량 데이터 추가&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현은 단순하고 직관적일 수 있으나, &lt;span style=&quot;color: #ee2323;&quot;&gt;데이터베이스에 불필요한 부하를 유발하여 전반적인 시스템 성능을 저하할 수 있는 잠재적 위험이 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/66cbe09fdb368bb697051cafbbf87701.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;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;b&gt;사용자로서는 실행 속도가 향상되고 데이터베이스의 부하가 감소한다는 장점이 있음&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/f92764d63a85b36d87acf10ee9a999fb.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;4. mongosh의 대량 작업 활용하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB는 정렬된 작업 목록 실행 시 작업을 100,000개 단위의 배치로 분할하고 작업 유형별로 그룹화함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i.g. 100,004개의 삽입, 99,998개의 수정, 100,004개의 삭제, 5개의 삽입 작업이 있다면 다음과 같이 처리됨&lt;/li&gt;
&lt;li&gt;이러한 처리 방식은 작업 순서에는 영향을 미치지 않으나, 실제로는 작업이 10만 개 단위로 데이터베이스에 적용됨을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752222222667&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[100,000 inserts]
[4 inserts]
[99,998 updates]
[100,000 deletes]
[4 deletes]
[5 inserts]&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;bulkWrite 명령어는 세 가지 인수를 받음
&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;writeConcern&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;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/3da66e86fe606843ea0fcdebb2ba391d.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;기존 bulk가 지원하는 작업들을 모두 동일하게 사용할 수 있으며, 지원되는 작업은 다음과 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;insertOne()&lt;/li&gt;
&lt;li&gt;updateMany()&lt;/li&gt;
&lt;li&gt;deleteMany()&lt;/li&gt;
&lt;li&gt;updateOne()&lt;/li&gt;
&lt;li&gt;deleteOne()&lt;/li&gt;
&lt;li&gt;replaceOne()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;파이썬 드라이버를 사용한 CRUD 처리&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB의 공식 드라이버인 PyMongo&lt;/li&gt;
&lt;li&gt;몽고DB를 위한 ODM인 MongoEngine&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;아래 코드를 통해 몽고DB 데이터베이스 서버와의 연결 상태를 확인할&amp;nbsp; 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/347bb0a81d3c94288d31765f9d9829aa.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;몽고DB는 파이썬 개발자를 위해 두 가지 공식 드라이버를 제공함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PyMongo는 파이썬과 몽고DB를 효율적으로 연동하는 기본 드라이버이며 이를 통해 파이썬의 유연한 프로그래밍 특성을 몽고DB의 문서 기반 NoSQL 데이터베이스 시스템과 원활하게 결합할 수 있음&lt;/li&gt;
&lt;li&gt;Motor는 비동기 처리를 위한 공식 드라이버이며 현대의 웹 애플리케이션에서 요구하는 실시간 데이터 처리와 대규모 동시 접속을 지원함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;몽고DB 아틀라스에 비동기 방식으로 연결하기 위해 아래와 같이 asyncio 프레임워크를 활용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/f059635386dc8fbe4f081e3fe7a91b23.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;1. 문서 생성&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB의 파이썬 드라이버는 데이터베이스 작업에 필요한 모든 기본 기능을 담고 있는 CRUD API를 제공하며 이러한 API를 활용하여 파이썬 코드로 몽고DB 켤렉션의 데이터를 손쉽게 관리할 수 있음&lt;/li&gt;
&lt;li&gt;mongo_books라는 데이터베이스 안에 있는 books 컬렉션에 새로운 문서를 추가하는 방법은 다음과 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 문서를 데이터베이스에 추가하기 위해 insert_one() 메서드를 사용하며 이때 문서의 구조는 파이썬의 딕셔너리 형식으로 정의됨&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;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/b7678607a9f043d783fbbd3c4f868b97.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;2. 문서 검색&lt;/b&gt;&lt;/h4&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;mongodb_books 데이터베이스의 books 컬렉션에서 책 제목을 기준으로 특정 도서를 찾는 방법은 다음과 같음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/3ba126a46696941931aec2de242425e8.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 예시에서는 metdata.version을 통해 meta 문서 내부의 version 필드에 접근하여 검색 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/f1a1119f47dc5a42421e7660227737e9.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$eq (동일)&lt;/li&gt;
&lt;li&gt;$gt (초과)&lt;/li&gt;
&lt;li&gt;$gte (이상)&lt;/li&gt;
&lt;li&gt;$lt (미만)&lt;/li&gt;
&lt;li&gt;$lte (이하)&lt;/li&gt;
&lt;li&gt;$ne (불일치)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/67fca993c076b744ad79633f4f6622a3.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;3. 문서 수정&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/b649a17ba11763413f8a898b5206867a.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;4. 문서 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PyMongo의 delete_one 메서드를 활용하면 지정된 조건을 기준으로 컬렉션에서 단일 문서를 삭제할 수 있음&lt;/li&gt;
&lt;li&gt;여러 문서를 동시에 삭제할 때는 delete_many 메서드를 사용&lt;/li&gt;
&lt;li&gt;삭제 기능은 데이터셋에서 특정 문서나 문서 그룹을 제거할 필요가 있을 때 효과적으로 활용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/6ce2556724a927a5f7ae6b92a3fbcb97.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;관리 기능&lt;/b&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;최적의 성능을 달성하기 위해서는 숙련된 몽고DB 개발자나 아키텍트의 전문적인 관리가 필요함&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;li&gt;인덱스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;프로세스 레벨에서는 서버 종료를 위한 shutDown 명령이 제공됨&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;b&gt;dropDatabase:&lt;/b&gt; 데이터베이스 전체 삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;listCollections:&lt;/b&gt; 현재 데이터베이스의 컬렉션 목록 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;drop:&lt;/b&gt; 컬렉션 삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;create:&lt;/b&gt; 컬렉션 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;renameCollection:&lt;/b&gt; 컬렉션명 변경&lt;/li&gt;
&lt;li&gt;&lt;b&gt;cloneCollectionAsCapped:&lt;/b&gt; 고정 크기 컬렉션으로 복제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;convertToCapped:&lt;/b&gt; 고정 크기 컬렉션으로 반환 (샤딩된 클러스터 환경에서는 미지원)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;compact:&lt;/b&gt; WiredTiger 엔진에서 미사용 디스크 공간 회수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;createIndexes:&lt;/b&gt; 신규 인덱스 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;listIndexes:&lt;/b&gt; 기존 인덱스 목록 조회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dropIndexes:&lt;/b&gt; 전체 인덱스 삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;reIndex:&lt;/b&gt; 인덱스 재생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;createSearchIndexes:&lt;/b&gt; 아틀라스 검색 인덱스 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dropSearchIndex:&lt;/b&gt; 아틀라스 검색 인덱스 삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;updateSearchIndex:&lt;/b&gt; 아틀라스 검색 인덱스 갱신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;1. currentOp()와 killOp()&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;db.currentOp() 메서드는 mongod 인스턴스에서 현재 실행 중인 작업의 상세 정보를 문서 형태로 반환하며 각 작업에는 고유한 작업 ID가 할당되어 있음&lt;/li&gt;
&lt;li&gt;killOp() 메서드는 특정 작업 ID를 지정하여 해당 작업을 강제 종료하는 기능을 수행함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;단, 반드시 클라이언트가 시작한 작업에 관해서만 사용해야 하며, 데이터베이스의 내부 작업은 종료되지 않도록 해야 함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/3f1e18277eb09688e8f25d0bc58b528d.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;2. collMod&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB의 collMod 명령어를 통해 컬렉션의 다양한 설정을 변경하거나 뷰의 정의를 수정할 수 있으며 해당 명령어로 수행할 수 있는 주요 작업은 다음과 같음
&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;li&gt;시계열 컬렉션의 구성 변경&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유효성 검사의 강도는 validationLevel 매개변수를 통해 조정 가능&lt;/li&gt;
&lt;li&gt;실제 적용 예시로, bookOrders 컬렉션에서 isbn과 name 필드에 관한 유효성 검사기를 설정하여 모든 추가와 수정 작업에 관해 이를 적용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/4f948eb1051bca05ca7292348e113059.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB에 관한 보안 액세스&lt;/b&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;몽고DB의 보안 체계는 인증 시스템, 접근 제어 메커니즘, 데이터 암호화 등 다양한 보안 요소들을 통합적으로 제공함&lt;/li&gt;
&lt;/ul&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;b&gt;1. 인증과 권한 부여&lt;/b&gt;&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB에서 접근 제어가 활성화되면, 모든 클라이언트는 반드시 인증 과정을 거쳐야 하며, 이를 통해 시스템은 해당 클라이언트의 접근 권한 수준을 결정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;가. 몽고DB를 사용한 인증&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;몽고DB의 기본 인증 체계는 사용자명과 비밀번호를 활용한 인증 방식을 채택하고 있으며 해당 인증 기능을 사용하기 위해서는 서버 실행 시 --auth 매개변수를 지정해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752228349221&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongod --auth&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;몽고DB의 로컬호스트 예외 기능은 접근 제어가 활성화된 상태에서도 시스템 내 초기 사용자와 역할을 설정할 수 있도록 지원함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 기능을 통해 접근 제어가 활성화된 환경에서도 admin 데이터베이스에 최초 사용자를 생성하기 위해 로컬호스트 인터페이스를 통한 연결이 가능함&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;단, mongod 인스턴스의 경우 이러한 로컬호스트 예외는 몽고DB 환경에 사용자나 역할이 아직 정의되지 않은 상황에서만 적용됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/2401d9386fb1e25e1f7edcbd03b8a191.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;몽고DB에서 관리자 계정을 생성할 때, 세 가지 주요 요소를 지정해야 함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;adminUser&amp;gt;는 생성하고자 하는 관리자의 사용자 이름을&lt;/li&gt;
&lt;li&gt;&amp;lt;cleartext password&amp;gt;는 해당 계정의 비밀번호를 의미&lt;/li&gt;
&lt;li&gt;&amp;lt;adminRole&amp;gt;은 자체 호스팅 환경에서 부여할 수 있는 권한 수준을 나타내며, 이는 가장 높은 권한부터 가장 낮은 ㅋ권한까지 차례대로 정렬되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;root&lt;/li&gt;
&lt;li&gt;dbAdminAnyDatabase&lt;/li&gt;
&lt;li&gt;userAdminAnyDatabase&lt;/li&gt;
&lt;li&gt;readWriteAnyDatabase&lt;/li&gt;
&lt;li&gt;readAnyDatabase&lt;/li&gt;
&lt;li&gt;dbOwner&lt;/li&gt;
&lt;li&gt;dbAdmin&lt;/li&gt;
&lt;li&gt;clusterAdmin&lt;/li&gt;
&lt;li&gt;clusterManager&lt;/li&gt;
&lt;li&gt;clusterMonitor&lt;/li&gt;
&lt;li&gt;hostManager&lt;/li&gt;
&lt;li&gt;backup&lt;/li&gt;
&lt;li&gt;restore&lt;/li&gt;
&lt;li&gt;userAdmin&lt;/li&gt;
&lt;li&gt;readWrite&lt;/li&gt;
&lt;li&gt;read&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;몽고DB 아틀라스는 atlasAdmin과 같은 아틀라스 전용 기본 역할을 제공하고 있으며 이 중 root 역할은 시스템의 모든 기능에 관한 완전한 접근 권한을 가진 최상위 관리자 권한을 의미함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그러나 보안상의 이슈로 특수한 상황을 제외하고는 root 권한의 사용을 권장하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;AnyDatabase로 시작하는 역할들을 시스템 내 모든 데이터베이스에 관한 접근 권한을 제공함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특히 dbAdminAnyDatabase 역할은 userAdminAnyDatabase와 readWriteAnyDatabase의 권한을 통합하여, 모든 데이터베이스에서 관리자 수준의 권한을 행사할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i.g. mongodb_book 데이터베이스에 관한 dbAdmin 역할을 부여하고자 할 경우, db.createUser() 명령어의 역할 설정 부분을 수정하여 이를 구현할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/a0a302643529d0824bd9595b9917bfbe.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB Stable API&lt;/b&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 5.0에서는 클라이언트와 서버 간의 안정적인 통신을 보장하는 Stable API가 도입되었으며 해당 API는 통신의 연속성과 신뢰성을 확보하기 위한 중요한 기능을 제공함&lt;/li&gt;
&lt;li&gt;Stable API의 구현은 몽고DB 드라이버나 mongosh 셸을 통해 이루어지며, 다음과 같은 mongosh 예제를 통해 선언할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752229451577&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongosh --apiVersion 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;&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;Stable API는 몽고DB 서버 간 호환성을 보장하는 핵심 기능으로 이를 통해 개발자들은 애플리케이션의 안전성을 유지하면서 몽고DB 서버를 지속적으로 업그레이드할 수 있음&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;클라이언트 측에서 반드시 apiVersion을 명시적으로 선언해야 함&lt;/li&gt;
&lt;li&gt;몽고DB가 공식적으로 지원하는 클라이언트 버전을 사용해야 함&lt;/li&gt;
&lt;li&gt;해당 API 버전이 지원하는 명령어와 기능만을 활용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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://www.mongodb.com/ko-kr/docs/manual/reference/stable-api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt; 참고&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마스터링 몽고DB 7.0&lt;/p&gt;</description>
      <category>DB/마스터링 몽고DB 7.0</category>
      <category>MongoDB</category>
      <category>몽고db</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2731</guid>
      <comments>https://jaimemin.tistory.com/2731#entry2731comment</comments>
      <pubDate>Fri, 11 Jul 2025 19:28:18 +0900</pubDate>
    </item>
    <item>
      <title>[4장] 몽고DB 연결</title>
      <link>https://jaimemin.tistory.com/2730</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;연결 방법&lt;/b&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;br /&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;ODM 계층을 활용하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ODM은 모델 객체와 데이터베이스 문서 사이의 매핑을 효율적으로 처리하여 개발자의 작업을 편리하게 해 줌&lt;/li&gt;
&lt;li&gt;몽고DB는 다양한 프로그래밍 언어를 지원하지만 해당 장에서는 널리 사용되는 네 가지 언어인 PHP, 루비, Node.js, 파이썬에 초점을 맞춤&lt;/li&gt;
&lt;/ul&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;b&gt;1. 루비를 이용한 몽고DB 연결&lt;/b&gt;&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;드라이버를 Gemfile에 추가하여 설치&lt;/li&gt;
&lt;li&gt;데이터베이스에 연결 (실제 환경에서는 복제본 세트에 연결)&lt;/li&gt;
&lt;li&gt;client_host 서버는 클라이언트 드라이버의 시드 서버 역할을 하며, 연결할 수 있는 서버 목록을 제공하며 연결이 완료되면 드라이버는 기본/보조 서버 구성의 읽기/쓰기 설정에 따라 적절한 서버를 선택&lt;/li&gt;
&lt;li&gt;사용자 이름과 비밀번호 설정은 선택 사항이지만, 모든 몽고DB 인스턴스에서 강력히 권장되므로 보안을 위해 mongod.conf 파일에서 인증을 기본으로 활성화하는 것이 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/06f2848e6ad5da53bc36589d95f560f6.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;가. Mongoid&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;루비나 레일즈 애플리케이션에서 몽고DB를 사용할 때는 Mongoid ODM이 효율적인 선택이 될 수 있음&lt;/li&gt;
&lt;li&gt;Mongoid ODM은 루비 드라이버의 유연성을 그대로 유지하면서도, 개발 시간을 단축하고 코드를 간소화하여 전체 프로세스를 최적화함&lt;/li&gt;
&lt;li&gt;ORM 도구와 마찬가지로, ODM은 모델과 데이터베이스 사이를 효과적으로 연결해 줌&lt;/li&gt;
&lt;li&gt;Mongoid ODM은 다음과 같은 장점을 제공
&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; 몽고DB는 스키마가 없지만, Mongoid를 통해 스키마를 정의하고 데이터 저장 전에 구조화된 유효성 검사가 가능함&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;ORM 사용 경험이 있다면 몽고DB로 전환 시 Mongoid를 직관적으로 활용할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매끄러운 통합:&lt;/b&gt; 애플리케이션 모델과 몽고DB 데이터베이스 사이의 데이터 변환과 처리를 매끄럽게 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 지원: &lt;/b&gt;여러 작업을 하나의 원자적 단위로 실행할 수 있도록 트랜잭션 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;2. 파이썬을 이용한 몽고DB 연결&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루비의 Mongoid ODM처럼 파이썬에서도 MongoEngine ODM을 사용할 수 있으며, 공식 몽고DB 드라이버인 PyMongo도 제공됨&lt;/li&gt;
&lt;li&gt;PyMongo는 pip 또는 easy_install 명령어를 통해 설치할 수 있으며 이후 아래 예시처럼 데이터베이스에 연결할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/c9a918ed0e8fde1007a05da8220d059f.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;가. MongoEngine ODM&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;MongoEngine은 몽고DB와 파이썬 간의 효과적인 상호작용 방법을 제공함&lt;/li&gt;
&lt;li&gt;몽고DB의 유연성과 파이썬 스타일의 친숙한 API를 통합하여 관계형 데이터베이스와 ORM에 익숙한 개발자들이 더 쉽게 사용할 수 있음&lt;/li&gt;
&lt;li&gt;mongoengine은 pip 명령어를 통해 설치 가능하고 옵션은 name=value 형태로 구성하며 각각의 옵션은 &amp;amp; 기호로 구분해야 함
&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://docs.mongoengine.org/guide/installing.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.mongoengine.org/guide/installing.html&lt;/a&gt;&amp;nbsp;참고&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;MongoEngine도 다른 ODM이나 ORM처럼 일정 수준의 오버헤드가 발생하지만 이러한 부하는 미미한 수준이며, 개발 생산성 향상으로 그 단점이 상쇄됨
&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; 몽고DB의 공식 파이썬 드라이버인 &lt;b&gt;PyMongo를 직접 사용&lt;/b&gt;하는 것을 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;3. PHP를 이용한 몽고DB 연결&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB의 PHP 드라이버는 아래와 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 구조의 최상단에는 Composer 패키지 형태로 배포되는 PHP 라이브러리가 자리를 잡고 있으며 다른 몽고DB 드라이버들과 동일한 API를 제공함&lt;/li&gt;
&lt;li&gt;그 아래에는 PECL을 통해 배포되는 PHP 확장이 있으며, 이는 PHP와 몽고DB의 시스템 라이브러리들 간의 중개자 역할을 수행&lt;/li&gt;
&lt;li&gt;PHP 확장을 직접 사용하는 것도 가능하지만, 라이브러리는 최소한의 오버헤드만 발생시키므로 몽고DB 기반 대부분의 애플리케이션에서 기본적으로 사용하게 될 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;624&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JKPyk/btsPd9VeGAX/fNHbhSBWVCVDKP8BJBW3IK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JKPyk/btsPd9VeGAX/fNHbhSBWVCVDKP8BJBW3IK/img.jpg&quot; data-alt=&quot;https://www.mongodb.com/ko-kr/docs/drivers/php-drivers/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JKPyk/btsPd9VeGAX/fNHbhSBWVCVDKP8BJBW3IK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJKPyk%2FbtsPd9VeGAX%2FfNHbhSBWVCVDKP8BJBW3IK%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;624&quot; height=&quot;449&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.mongodb.com/ko-kr/docs/drivers/php-drivers/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB extension을 설치해야 하고 해당 extension은 설치된 PHP 버전과 호환되어야 함&lt;/li&gt;
&lt;li&gt;PHP의 대표적인 의존성 관리자인 composer를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/54c8224e9d5c4b5a358978a400f18220.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;가. 엘로퀀트 ORM&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;Laravel은 세련된 문법과 표현력 있는 코딩 스타일을 특징으로 하며, 특히 엘로퀀트 ORM에서 이러한 특징이 잘 드러남&lt;/li&gt;
&lt;li&gt;엘로퀀트는 데이터베이스와의 상호작용을 위한 풍부하고 직관적인 인터페이스를 제공하며, 독트린의 데이터 매퍼 패턴과는 달리 액티브 레코드 패턴을 구현한 것으로 알려져 있음&lt;/li&gt;
&lt;li&gt;몽고DB와 엘러퀀트를 함께 사용하기 위해서는 라라벨의 엘로퀀트 ORM을 몽고DB와 연동해주는 패키지를 설치해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752213687255&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;composer require mongodb/laravel-mongodb&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;b&gt;4. Node.js를 이용한 몽고DB 연결&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node.js는 우수한 성능을 바탕으로 가장 널리 사용되는 웹 기술 중 하나로 자리 잡은 오픈소스 크로스 플랫폼 런타임 환경&lt;/li&gt;
&lt;li&gt;몽고DB는 Node.js와 함께 Express.js, React.js와 결합하여 MERN 스택이라고 불리게 되었음
&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;현재는 Strapi와 같은 다수의 CMS가 MERN 스택을 기반으로 개발되고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;Node.js 드라이버는 노드 패키지 매니저를 통해 설치할 수 있으며 설치 후에는 아래 예시와 같이 코드를 통해 데이터베이스에 연결할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/3ae34477d6d4eeeba418b67083d1487a.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/82185a68555391d6cedfae3aeba2f994.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;다른 드라이버들과 마찬가지로 Node.js 드라이버도 메시지 압축 기능을 제공하며 몽고DB와 애플리케이션 간의 데이터 전송량을 줄일 수 있음&lt;/li&gt;
&lt;li&gt;Node.js 드라이버는 다음 세 가지 압축 알고리즘을 지원함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Snappy:&lt;/b&gt; 높은 속도와 적정 수준의 압축률을 제공하는 알고리즘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;zlib:&lt;/b&gt; 무손실 데이터 압축을 지원하는 라이브러리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Zstandard:&lt;/b&gt; zstd라고도 불리며, zlib 수준의 실시간 압축 성능과 향상된 압축률을 제공하는 고속 무손실 압축 알고리즘&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;압축 기능을 활성화하려면 연결 문자열에 compressors 매개변수를 추가해야 하고 복수의 압축 알고리즘을 지정할 때는 쉼표로 구분하여 입력&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/dd7b480182c24476df228d89df10b89b.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&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;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마스터링 몽고DB 7.0&lt;/p&gt;</description>
      <category>DB/마스터링 몽고DB 7.0</category>
      <category>MongoDB</category>
      <category>몽고db</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2730</guid>
      <comments>https://jaimemin.tistory.com/2730#entry2730comment</comments>
      <pubDate>Fri, 11 Jul 2025 15:16:57 +0900</pubDate>
    </item>
    <item>
      <title>[3장] 개발자 도구</title>
      <link>https://jaimemin.tistory.com/2729</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론&lt;/b&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와 그 생태계의 잠재력을 충분히 활용하기 위해서는 몽고DB가 제공하는 다양한 개발자 도구에 관한 숙련도가 필수적&lt;/li&gt;
&lt;li&gt;몽고DB는 오랫동안 개발자들에게 최상의 도구를 제공하여 몽고DB 클러스터와 데이터를 효과적으로 다룰 수 있도록 지원해 옴
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2011년 몽고DB 1.0 버전 출시 이후 2년 만에 10gen은 몽고DB 관리 서비스를 출시했으며, 이는 후에 Ops 매니저로 발전했고 시스템 관리와 모니터링을 위한 핵심 포털 임무를 수행했음&lt;/li&gt;
&lt;li&gt;초기 릴리즈부터 몽고DB 생태계의 필수 요소였던 관리 도구는 몽고DB의 중요성을 잘 보여주며, DB 시스템 아키텍처의 발전과 함께 개발자 도구 제공이라는 두 가지 목표를 추구했음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;개발 도구 소개&lt;/b&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;/ul&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;b&gt;1. 개발 도구의 유형&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB가 공식 제공하는 개발자 도구들은 다양한 시나리오에서 사용자 지원을 목적으로 하며 이러한 도구들은 몽고DB 인스턴스 내 데이터 관리, 협력업체 소프트웨어를 위한 플러그인 제공, 클러스터 관리 및 성능 모니터링 등 각각의 용도에 맞게 설계되었음&lt;/li&gt;
&lt;li&gt;이러한 도구들은 사용 사례 시나리오에 따라 분류가 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;mongosh:&lt;/b&gt; 몽고DB와의 상호작용을 위한 완전한 기능을 갖춘 자바스크립트와 Node.js REPL 환경; mongosh를 통해 데이터베이스와 직접 소통하며 쿼리와 작업을 테스트할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;몽고DB Compass:&lt;/b&gt; 몽고DB 데이터를 시각적 환경에서 쿼리, 집계, 분석할 수 있는 강력한 GUI 도구&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;몽고DB 데이터베이스를 외부 저장소에 백업하거나, 기존 몽고DB 클러스터에 데이터베이스 백업을 복원하기 위해 설계됨&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;b&gt;mongodump:&lt;/b&gt; 데이터베이스 내용을 이진 형식으로 내보내기 위한 명령줄 유틸리티&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mongostore:&lt;/b&gt; mongodump를 통해 생성된 binary 데이터베이스 덤프로부터 데이터를 복원하기 위한 명령줄 도구&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;mongostat:&lt;/b&gt; 몽고DB 인스턴스의 실시간 성능 통계를 모니터링하기 위한 명령줄 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mongotop:&lt;/b&gt; 몽고DB 인스턴스의 데이터 읽기와 쓰기 소요 시간을 추적하기 위한 명령줄 도구&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BI를 위한 몽고DB 커넥터:&lt;/b&gt; 전통적인 비즈니스 인텔리전스 도구들의 표 형식 데이터 처리를 지원하며 이를 통해 태블로, 파워 BI, 엑셀 등의 도구에서 SQL을 사용하여 몽고DB 데이터를 쿼리 할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Visual Studio Code를 위한 몽고DB 플러그인:&lt;/b&gt; VS Code 환경에서 몽고DB 데이터를 원활하게 다룰 수 있도록 지원하며 문법 강조, 코드 스니핏, 코드 제안, 연결 관리, 쿼리 실행 등의 기능을 제공함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;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; 몽고DB가 제공하는 공식 쿠버네티스 운영자로, 쿠버네티스 호나경에서 몽고DB 클러스터의 배포, 확장, 관리를 간소화함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테라폼 템플릿 지원:&lt;/b&gt; 인프라 프로비저닝을 자동화할 수 있어, 다양한 클라우드 플랫폼에서 몽고DB 클러스터의 설정과 유지보수가 용이해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB 셸&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh는 몽고DB와의 상호작용을 위한 완전한 기능을 갖춘 자바스크립트와 Node.jss 기반의 REPL 환경&lt;/li&gt;
&lt;li&gt;mongosh는 인터프리터 임무를 수행하는 강력하고 다재다능한 명령줄 인터페이스로서, 이를 통해 데이터베이스와 직접 소통하며 생성, 읽기, 수정, 삭제 등 CRUD 작업은 물론 관리 작업, 집계, 인덱싱 등을 수행할 수 있음&lt;/li&gt;
&lt;/ul&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;b&gt;1. 설치&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh는 다음과 같은 방법으로 설치할 수 있음
&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.mongodb.com/try/download/community-edition/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;몽고DB 다운로드 센터&lt;/a&gt;에서 독립 실행형 패키로 제공됨&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/mongodb-shell/install/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;몽고DB 공식 문서의 설치 가이드&lt;/a&gt;를 따라 내려받기와 설치가 가능함&lt;/li&gt;
&lt;li&gt;Node.js 기반으로 개발되어 npm을 통한 설치도 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752073061565&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g mongosh&lt;/code&gt;&lt;/pre&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;b&gt;2. 몽고DB에 mongosh를 사용하여 연결하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh 설치 후에는 터미널이나 명령 프롬프트에서 mongosh 명령어만으로 실행이 가능함&lt;/li&gt;
&lt;li&gt;기본적으로 로컬호스트의 기본 포트 27017에서 실행 중인 몽고DB 배포에 연결을 시도함&lt;/li&gt;
&lt;li&gt;원격 몽고DB 배포 연결은 다음과 같이 원하는 호스트와 포트를 지정한 연결 문자열을 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752073194518&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongosh &quot;mongodb://username:password@hostname:port/test&quot;&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;몽고DB 배포에 성공적으로 연결되면 test&amp;gt; 프롬프트가 표시되며, 이는 셸이 test 데이터베이스에 연결되어 명령 실행이 가능한 상태임을 나타냄
&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;이 상태에서 show dbs 명령을 통해 모든 데이터베이스를 조회하거나 특정 데이터베이스로 전환할 수 있으며, mongosh 인터페이스를 통해 데이터베이스 컬렉션에 관한 CRUD 작업 등 몽고DB 클러스터에서 다양한 명령을 실행할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;962&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oTF4g/btsPcfzPtvW/7uc53UnPiRlp6hzjuB3H5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oTF4g/btsPcfzPtvW/7uc53UnPiRlp6hzjuB3H5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oTF4g/btsPcfzPtvW/7uc53UnPiRlp6hzjuB3H5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoTF4g%2FbtsPcfzPtvW%2F7uc53UnPiRlp6hzjuB3H5K%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;962&quot; height=&quot;209&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;mongosh는 지능형 자동 완성과 제안 기능을 제공하여 명령어를 더욱 신속하고 정확하게 작성할 수 있도록 지원하며 추가 옵션은 help 명령어를 실행하여 확인할 수 있음&lt;/li&gt;
&lt;/ul&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;1324&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pjKhz/btsPbg02Hyr/imQLPabZLrq6HAV1JLlfk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pjKhz/btsPbg02Hyr/imQLPabZLrq6HAV1JLlfk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pjKhz/btsPbg02Hyr/imQLPabZLrq6HAV1JLlfk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpjKhz%2FbtsPbg02Hyr%2FimQLPabZLrq6HAV1JLlfk1%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;1324&quot; height=&quot;542&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;b&gt;3. mongosh와 mongo&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh는 기존의 mongo와 비교하여 다음과 같은 다양한 장점이 있음
&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; 명령어 입력 시 Tab 키를 통해 명령어 구문을 보완해 줘 사용자의 편의성을 높임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구문 강조 기능:&lt;/b&gt; 명령어와 결과를 명령줄 설정에 맞는 색상과 정돈된 형식으로 표시하여 코드의 가독성과 처리를 쉽게 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로깅 기능:&lt;/b&gt; ndjson을 활용하여 세션 로그를 저장하며, 로그 ID를 기반으로 몽고DB 셸 세션의 로그를 실시간 확인하거나 조회할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이전 메서드 호환성:&lt;/b&gt; 하위 호환성을 보장하기 위해 mongosh는 기존 mongo의 메서드와 동일한 구문을 유지함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;4. mongosh의 주요 기능&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh는 데이터베이스 관리자와 개발자 모두에게 필수적인 도구로서, 실시간 피드백과 함께 몽고DB 활용 경험을 향상하는 다양한 기능을 제공함&lt;/li&gt;
&lt;li&gt;mongosh의 활용도가 높아질수록 데이터베이스와 컬렉션을 더욱 효율적으로 다룰 수 있는 새로운 기능들을 발견하게 될 것&lt;/li&gt;
&lt;li&gt;mongosh의 대표적인 기능들은 다음과 같음
&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; mongosh를 통해 데이터베이스 관리와 데이터 또는 클러스터 구성 문제 해결을 위한 관리 메서드를 실행할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스크립트 작성:&lt;/b&gt; mongosh를 통해 몽고DB의 데이터 수정이나 클러스터 관리 작업을 위한 스크립트 작성이 가능하며 이러한 스크립트는 코드의 배포, 관리, 재사용을 쉽게 하는 스니핏으로 활용될 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;셸 로그 검색:&lt;/b&gt; mongosh는 ndjson 형식을 활용하여 세션 로그를 저장하며 1.0.5 버전부터는 몽고DB 셸 로그 형식이 몽고DB 서버 로그 형식과 일치하도록 개선되었으며, 로그 ID를 기반으로 mongosh 세션의 로그를 실시간으로 확인하거나 조회할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명령어 편집기로 사용:&lt;/b&gt; mongosh는 명령을 한 번에 하나씩 실행하는 인터페이스를 제공하기 때문에 데이터베이스에서 연속적인 작업을 수행하려면 각 작업을 개별적으로 작성하여 실행하거나 앞서 설명한 것처럼 스크립트로 작업을 실행해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;5. mongosh의 주요 사용 사례&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongosh는 현대적이고 사용자 친화적인 다기능 대화형 도구로서, 다음과 같은 사용 사례에 적합함
&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; mongosh는 몽고DB 데이터베이스의 대화식 탐색에 탁월하며 셸에서 직접 쿼리 실행, 문서 검사, 다양한 명령어 실험이 가능함&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; 몽고DB의 집계 프레임워크를 지원하여 복잡한 데이터 변환과 분석 작업을 수행할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복제본 세트와 샤딩 클러스터 작업:&lt;/b&gt; 복제본 세트와 샤딩 클러스터의 관리, 모니터링, 상태 확인, 장애 조치 시나리오 관리가 가능함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 분석과 모니터링:&lt;/b&gt; db.serverStatus(), db.stats() 등의 명령어를 통해 몽고DB의 성능을 모니터링할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;6. mongosh 사용을 위한 모범 사례&lt;/b&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;정기적인 버전 업데이트:&lt;/b&gt; 최신 기능, 개선 사항, 버그 수정의 이점을 누리려면 mongosh 버전을 최신 상태로 유지하는 것을 권장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연결 문자열 사용:&lt;/b&gt; 개별 연결 매개변수를 지정하는 대신 몽고DB 연결 문자열을 사용하여 데이터베이스에 연결하면 연결 설정을 보다 쉽게 이식하고 관리할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쉬운 코드 작성:&lt;/b&gt; mongosh는 지능형 자동 완성과 구문 강조 기능을 제공하므로 명령을 쉽게 탐색하고 실행할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;출력 이해:&lt;/b&gt; find(), aggregate()와 같은 명령의 출력 형식에 익숙해지면 대량의 데이터를 쉽게 조회 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도움말 명령 사용:&lt;/b&gt; help 명령을 사용하여 사용할 수 있는 명령, 구문 및 사용 예제에 관한 정보를 얻을 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안전한 환경에서 연습:&lt;/b&gt; 관리 작업이나 스크립트를 실험할 때는 프로덕션 데이터에 변경 사항을 적용하기 전에 테스트 또는 개발 환경에서 작업하는 것을 권장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 모범 사례:&lt;/b&gt; 적절한 인증 메커니즘과 권한 부여 역할을 사용하여 몽고DB 배포에 안전하게 연결할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 백업:&lt;/b&gt; 잠재적으로 파괴적인 작업을 수행하기 전에 실수로 인한 데이터 손실을 방지하기 위해 데이터를 백업하는 것을 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB CLI&lt;/b&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 CLI는 터미널 환경에서 몽고DB 서비스를 관리할 수 있는 현대적인 명령줄 인터페이스 도구이며 이를 통해 아틀라스, 클라우드 매니저, Ops 매니저에서 몽고DB 클러스터의 배포와 관리가 가능함&lt;/li&gt;
&lt;/ul&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;b&gt;1. 설치&lt;/b&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;a href=&quot;https://www.mongodb.com/try/download/mongocli&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;몽고DB CLI는 공식 웹사이트&lt;/a&gt;에서 내려받아 설치할 수 있으며 설치 완료 후에는 사용자 친화적인 명령줄 인터페이스를 통해 아틀라스, 클라우드 매니저, Ops 매니저 배포를 위한 클라우드 환경과 상호작용하고 클러스터를 원격으로 관리할 수 있음&lt;/li&gt;
&lt;/ul&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;b&gt;2. 구성&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB CLI의 클러스터 구성과 인증은 다음 단계로 진행됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API 키 생성:&lt;/b&gt; 아틀라스 UI에서 조직이나 프로젝트에 관한 프로그래밍 방식 접근을 위한 API 키 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트 생성:&lt;/b&gt; 기존 프로젝트가 없는 경우, 사용자, 설정 또는 환경을 공유하는 클러스터들을 그룹화할 프로젝트를 새로 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연결 설정:&lt;/b&gt; 몽고DB 서비스의 API 접근 목록에 IP 주소나 CIDR 블록을 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;위와 같은 준비가 완료되면, 터미널에서 &quot;mongocli config&quot; 명령어를 통해 프로필을 생성할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로필 설정이 시작되면, 아틀라스 클러스터 구성을 위한 공개 또는 비공개 API 키, 조직, 프로젝트 정보를 선택적으로 입력하는 메시지가 표시됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;3. 몽고DB CLI 작업하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로필 생성 후에는 셸에서 아틀라스 클러스터에 접근할 수 있으며, 아틀라스 GUI와 동일한 방식으로 명령을 실행하여 응답을 시뮬레이션함으로써 클러스터와의 모든 상호작용을 스크립트로 작성할 수 있음&lt;/li&gt;
&lt;li&gt;몽고DB CLI는 아틀라스 클러스터 연결을 위한 인터페이스로 활용될 뿐만 아니라, mongocli auth 명령을 통해 클라우드 배포의 인증 수단으로도 사용할 수 있음&lt;/li&gt;
&lt;/ul&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;b&gt;4. mongocli auth&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mongocli auth 명령은 명령줄 인터페이스의 인증 상태를 관리하는 데 사용됨&lt;/li&gt;
&lt;li&gt;auth 명령을 통해 아틀라스나 클라우드 매니저에 인증할 수 있으며, mongocli logout 명령으로 명령줄 인터페이스에서 로그아웃할 수 있음&lt;/li&gt;
&lt;/ul&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;b&gt;5. 몽고DB CLI의 주요 기능&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB CLI는 GUI 사용이나 복잡한 스크립트 작성 없이도 몽고DB 배포를 관리하고 운영할 수 있는 효율적인 방법을 제공하며 주요 기능은 다음과 같음
&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; 몽고DB 클러스터의 생성, 수정, 삭제 등 클러스터 관리가 가능함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 작업: &lt;/b&gt;명령줄에서 직접 데이터베이스, 컬렉션, 문서의 생성, 데이터 조회, 갱신 등 다양한 데이터베이스 관련 작업을 수행할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 가져오기와 내보내기:&lt;/b&gt; .json, .csv 등 다양한 형식의 데이터를 몽고DB 데이터베이스로 가져오거나 내보낼 수 있어, 환경 간 데이터 마이그레이션이나 데이터베이스 백업과 복원 작업에 유용함&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;/li&gt;
&lt;/ul&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;b&gt;6. 몽고DB CLI 사용 사례&lt;/b&gt;&lt;/h4&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;li&gt;기존 자동화 워크플로에 몽고DB 아틀라스 관리 통합&lt;/li&gt;
&lt;/ul&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;b&gt;7. 몽고DB CLI 활용을 위한 모범 사례&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB CLI를 몽고DB 아틀라스와 함께 사용할 때는 적절한 인증과 권한 설정을 반드시 확인&lt;/li&gt;
&lt;li&gt;몽고DB CLI를 통해 프로그래밍 방식으로 클러스터를 생성과 관리하고, 크기 조정, 업그레이드 같은 클러스터 유지보수 작업을 수행&lt;/li&gt;
&lt;li&gt;데이터의 정기적인 백업 생성을 위해 몽고DB CLI를 백업 작업에 활용&lt;/li&gt;
&lt;li&gt;몽고DB 아틀라스 CLI로 사용자 및 역할 관리를 자동화할 때는 최소 권한 원칙 준수&lt;/li&gt;
&lt;li&gt;아틀라스 CLI를 CI/CD 파이프라인에 통합하여 데이터베이스 관련 작업을 수행하고, 스크립트를 통해 다른 도구와 연동하여 개발과 배포 프로세스를 간소화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB Compass&lt;/b&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 Compass는 몽고DB 데이터베이스의 관리, 쿼리 작성, 데이터 시각화를 위해 설계된 강력하고 직관적인 GUI 도구&lt;/li&gt;
&lt;li&gt;Compass를 통해 복잡한 쿼리를 직접 작성하지 않고도 데이터베이스의 컬렉션을 탐색하고, 데이터를 확인 및 분석하며, CRUD 작업을 수행할 수 있음&lt;/li&gt;
&lt;li&gt;대부분의 쿼리와 인덱스 성능에 관한 시각화를 제공하여, 데이터베이스 관리자가 TLS 암호화된 연결을 통해 클러스터를 효과적으로 모니터링하고 문제를 해결할 수 있음&lt;/li&gt;
&lt;/ul&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;b&gt;1. 설치&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Compass는 &lt;a href=&quot;https://www.mongodb.com/docs/compass/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;몽고DB 공식 사이트&lt;/a&gt;에서 무료로 내려받을 수 있음&lt;/li&gt;
&lt;/ul&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;b&gt;2. 구성&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB 클러스터나 몽고DB 아틀라스 호스팅 배포에 연결하기 위해서는 연결 매개변수를 구성해야 하며 이는 URI 형식의 연결 문자열을 제공하거나, 연결 매개변수 대화 상자에 호스트 이름, 포트, 인증 정보를 직접 입력하는 방식으로 가능함&lt;/li&gt;
&lt;/ul&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;1420&quot; data-origin-height=&quot;829&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2o4dN/btsPearMELB/iEu7ZYr4NALzS3cof4MdO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2o4dN/btsPearMELB/iEu7ZYr4NALzS3cof4MdO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2o4dN/btsPearMELB/iEu7ZYr4NALzS3cof4MdO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2o4dN%2FbtsPearMELB%2FiEu7ZYr4NALzS3cof4MdO0%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;1420&quot; height=&quot;829&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;829&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;b&gt;3. Compass를 사용하여 데이터를 시각적으로 탐색하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB에 연결된 후에는 Compass를 통해 다양한 작업을 수행할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSV나 JSON 형식의 데이터를 몽고DB 클러스터로 가져오거나, 직관적인 인터페이스에서 데이터를 관리할 수 있음&lt;/li&gt;
&lt;li&gt;임시 쿼리를 작성하여 데이터를 필터링하고 컬렉션의 경향과 특징을 파악할 수 있으며, 집계 파이프라인을 통해 컬렉션의 문서를 여러 단계를 거쳐 집계된 결과물로 처리되는 과정을 확인할 수 있음&lt;/li&gt;
&lt;li&gt;내장된 몽고DB 셸을 활용하여 대화형 자바스크립트 환경에서 데이터를 조작할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;4. 몽고DB Compass의 주요 기능&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB Compass는 시각적 환경에서 몽고DB 데이터의 쿼리, 집계, 분석을 위한 다양한 기능을 제공함
&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; 몽고DB 서버의 실시간 성능을 분석할 수 있으며, 쿼리 실행 시간과 인덱스 사용 등을 모니터링하여 데이터베이스 성능을 최적화할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스키마 분석:&lt;/b&gt; 데이터의 스키마를 자동으로 시각화하여 데이터 구조에 관한 중요한 인사이트를 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 시각화:&lt;/b&gt; 내장된 시각화 도구를 통해 몽고DB 데이터로부터 차트와 그래프를 쉽게 생성하여 분석과 보고가 가능함&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;/li&gt;
&lt;/ul&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;b&gt;5. 몽고DB Compass 사용 사례&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB Compass의 대화형 GUI와 도구를 통해 다음과 같은 작업이 가능함
&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;Compass 스키마 뷰를 통해 컬렉션과 문서의 구조를 설계하고 시각화할 수 있음&lt;/li&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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 몽고DB Compass를 위한 모범 사례&lt;/b&gt;&lt;/h4&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 Compass를 정기적으로 업데이트&lt;/li&gt;
&lt;li&gt;데이터나 스키마의 큰 변경 전에는 데이터 손실 방지를 위해 반드시 백업 생성&lt;/li&gt;
&lt;li&gt;관리 작업이나 새로운 쿼리 테스트 시 프로덕션 데이터 보호를 위해 개발 또는 스테이징 환경 활용&lt;/li&gt;
&lt;li&gt;Indexes 탭을 통해 기존 인덱스를 검토하고 최적화가 필요한 영역 파악&lt;/li&gt;
&lt;li&gt;쿼리 빌더의 효과적인 활용법을 익히고, 필요한 데이터 검색을 위해 필터링, 정렬, 프로젝션 등의 기능 적극 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마스터링 몽고DB 7.0&lt;/p&gt;</description>
      <category>DB/마스터링 몽고DB 7.0</category>
      <category>MongoDB</category>
      <category>몽고db</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2729</guid>
      <comments>https://jaimemin.tistory.com/2729#entry2729comment</comments>
      <pubDate>Thu, 10 Jul 2025 00:56:23 +0900</pubDate>
    </item>
    <item>
      <title>[2장] 몽고DB 아키텍처</title>
      <link>https://jaimemin.tistory.com/2728</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론&lt;/b&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;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;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;복제와 샤딩&lt;/b&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;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;span style=&quot;color: #ee2323;&quot;&gt;만약 특정 샤드가 단일 서버로만 운영될 경우, 해당 서버 장애 시 데이터에 접근할 수 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;하지만 각 샤드에 복제 시스템을 구축할 경우 서버 장애 상황에서도 중단 없는 서비스가 가능해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;복제&lt;/b&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의 복제본 세트는 동일한 데이터를 공유하는 여러 mongod 프로세스의 그룹이며 이는 데이터의 중복 저장과 고가용성을 보장하여 실제 서비스 환경의 근간이 됨&lt;/li&gt;
&lt;li&gt;몽고DB 복제본 세트에서 주 서버는 모든 쓰기 작업을 담당하며, 데이터의 변경 사항을 oplog에 기록
&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;/li&gt;
&lt;/ul&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;보조 서버들은 주 서버의 oplog를 참조하여 동일한 작업을 수행함으로써 데이터의 일관성을 유지함
&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;/li&gt;
&lt;/ul&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;/li&gt;
&lt;/ul&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;740&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwuyrw/btsO0fBN4ka/hHh03cxoyVNeQhE7eatfU0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwuyrw/btsO0fBN4ka/hHh03cxoyVNeQhE7eatfU0/img.jpg&quot; data-alt=&quot;https://www.mongodb.com/ko-kr/docs/manual/core/replica-set-architecture-three-members/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwuyrw/btsO0fBN4ka/hHh03cxoyVNeQhE7eatfU0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwuyrw%2FbtsO0fBN4ka%2FhHh03cxoyVNeQhE7eatfU0%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;740&quot; height=&quot;280&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.mongodb.com/ko-kr/docs/manual/core/replica-set-architecture-three-members/&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 복제본 세트 선출&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;몽고DB는 분산 시스템의 데이터 일관성 보장을 위해 RAFT 합의 알고리즘을 기반으로 한 프로토콜을 사용하는데 해당 프로토콜은 복제본 세트에서 주 노드를 선출하는 투표 메커니즘을 포함하고 있음&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;주 서버와 보조 서버 간 Heartbeat 응답 지연 시간이 허용 범위를 초과하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;몽고DB 드라이버는 주 서버 장애를 감지하고 특정 읽기나 쓰기 작업을 자동으로 재시도할 수 있어, 선거 과정에서 추가적인 안정성을 제공함&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;/li&gt;
&lt;/ul&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;660&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FRfNN/btsO0NSi3Iu/alKccr56JIZ8GC9tlzhdW1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FRfNN/btsO0NSi3Iu/alKccr56JIZ8GC9tlzhdW1/img.jpg&quot; data-alt=&quot;https://www.mongodb.com/docs/manual/core/replica-set-elections/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FRfNN/btsO0NSi3Iu/alKccr56JIZ8GC9tlzhdW1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFRfNN%2FbtsO0NSi3Iu%2FalKccr56JIZ8GC9tlzhdW1%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;660&quot; height=&quot;500&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.mongodb.com/docs/manual/core/replica-set-elections/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.1 구성원 우선순위&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그러나 더 높은 우선순위를 가진 구성원이 있더라도 낮은 우선순위의 구성원이 일시적으로 주 서버 임무를 수행할 수 있으며 &lt;/span&gt;가장 높은 우선순위를 가진 구성원이 주 서버가 될 때까지 선거 과정이 계속됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;복제본 세트는 최대 50개의 구성원을 포함할 수 있지만 투표권을 가진 구성원은 최대 7개로 제한되어 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;투표권이 없는 구성원의 우선순위는 반드시 0으로 설정되어야 함&lt;/li&gt;
&lt;li&gt;우선순위가 0인 구성원은 주 서버가 될 수 없으며 선거를 요청할 수도 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 복제본 세트 oplog&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;oplog는 몽고DB 데이터베이스의 모든 데이터 변경 작업을 차례대로 기록하는 특수한 제한 컬렉션&lt;/li&gt;
&lt;li&gt;몽고DB에서 모든 쓰기 작업은 우선 주 서버에서 실행된 후 해당 서버의 oplog에 기록됨
&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;복제본 세트의 모든 구성원은 local.oplog.rs 컬렉션에 oplog의 사본을 보관하여 데이터베이스의 최신 상태를 유지함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;복제 기능을 지원하기 위해 복제본 세트의 모든 구성원은 서로 하트비트 혹은 ping을 주고받으며 각 보조 구성원은 다른 구성원으로부터 oplog 항목을 가져올 수 있음&lt;/li&gt;
&lt;li&gt;oplog의 모든 작업은 멱등성을 가지고 있어, 동일한 작업을 N번 실행해도 항상 같은 결과를 보장함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.1 oplog 윈도&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;oplog 항목에는 타임스탬프가 포함되어 있으며, oplog 윈도는 로그에 기록된 &lt;b&gt;가장 최근 타임스탬프와 가장 오래된 타임스탬프 사이의 시간 간격&lt;/b&gt;을 의미함&lt;/li&gt;
&lt;li&gt;보조 서버가 주 서버와의 연결이 끊어진 경우, 해당 oplog 윈도 기간 내에 재연결이 이루어져야만 복제를 통한 재동기화가 가능함&lt;/li&gt;
&lt;li&gt;시스템은 다음과 같은 조건에서만 oplog 항목을 삭제함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;oplog가 설정된 최대 용량에 도달했고, oplog 항목이 호스트 시스템 시간을 기준으로 지정된 보존 기간을 초과함&lt;/li&gt;
&lt;li&gt;최소 oplog 보존 기간이 설정되지 않은 경우, 몽고DB는 기본 설정에 따라 oplog가 최대 크기를 초과하지 않도록 가장 오래된 항목부터 차례대로 제거함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 복제본 세트 배포 아키텍처&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;일반적인 운영 환경에서는 3개의 구성원으로 이루어진 복제본 세트를 배포하는 것이 표준이며 이러한 구성은 데이터 중복성과 장애 복구 능력을 제공함&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;네트워크 분할 상황에서 의사결정이 분산되는 것을 방지하고, 더 큰 네트워크 세그먼트에서 쓰기 작업이 가능하도록 홀수 개의 투표 구성원을 유지 (PSS 구조)&lt;/li&gt;
&lt;li&gt;투표 구성원이 짝수인 경우, 데이터를 보유한 새로운 투표 구성원을 추가하는 것이 바람직하지만, 어려운 경우에는 중재자인 Arbiter를 도입할 수 있음 (PSA 구조)&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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.1 복제본 세트 중재자 (Arbiter)&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;span style=&quot;color: #ee2323;&quot;&gt;실제 데이터의 복사본은 보유하지 않으며 주 서버 임무를 수행할 수도 없음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중재자는 선거 과정에서 한 표의 투표권만을 행사할 수 있으며, 기본적으로 우선순위는 0으로 설정됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.2 숨김 복제본 세트 구성원&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;span style=&quot;color: #ee2323;&quot;&gt;숨김 구성원은 주 서버 임무를 수행할 수 없으며, 클라이언트 애플리케이션에서도 확인할 수 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;그러나 이러한 비가시성에도 불구하고, 숨김 구성원은 선거 과정에 참여하고 투표할 수 있는 권한을 유지함&lt;/li&gt;
&lt;li&gt;숨김 서버는 주로 백업 작업을 수행하거나 특정 보고서 쿼리를 실행하기 위한 전용 복제본 세트 구성원으로 활용됨&lt;/li&gt;
&lt;li&gt;숨김 서버를 설정하고 해당 구성원이 주 서버로 선출되는 것을 방지하기 위해서는, 우선순위를 0으로 설정하고 hidden 매개변수를 true로 지정하면 됨&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/24d794061f8c8c539a11acb938302144.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.3 지연 복제 세트 구성원&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;지연 구성원은 숨김 구성원의 특수한 형태로, 원본 oplog로부터 작업을 복제하고 적용할 때 의도적인 시간 지연을 두어 복제본 세트의 과거 상태를 유지함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i.g. 현재 시각이 12:07이고 구성원의 지연 시간이 1시간으로 설정되어 있다면, 해당 지연 구성원은 11:07 이전까지의 작업만을 반영한 상태를 유지하게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/64e9aac0a9f5c06389e7421c21f06dd4.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 쓰기 보장 수준 (Write Concern)&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;쓰기 보장 수준은 몽고DB가 복제본 세트에서 쓰기 작업의 완료를 확인하는 방식을 결정하며 이는 데이터가 지정된 개수의 서버에 성공적으로 기록되었는지 확인한 후에만 쓰기 작업을 승인하는 방식으로 작동함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.1 쓰기 보장 수준의 구성 요소&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; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;w 매개변수&lt;/b&gt;는 쓰기 작업의 확인이 필요한 복제본 세트 구성원의 수를 지정하며 쓰기 보장 수준은 다음과 같은 &amp;lt;value&amp;gt;들로 설정할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;0:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;확인 절차 없이 쓰기 작업이 진행되며 가장 낮은 데이터 안정성을 가지지만, 최고의 성능을 제공함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;주 서버로부터만 확인을 받음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;숫자:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;지정한 수만큼의 복제본 세트 구성원으로부터 확인을 받음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;majority&quot;:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;복제본 세트 구성원의 과반수로부터 확인을 받으며 몽고DB 5.0 버전부터 default 값&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&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;b&gt;j:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;쓰기 작업이 디스크의 저널에 기록되었는지 확인하며 true로 설정할 경우 저널 기록이 완료될 때까지 대기함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;wtimeout:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;쓰기 보장 수준에 관한 시간제한을 밀리초 단위로 설정하며 지정된 시간 내에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;필요한 수준의 확인이 이루어지지 않으면 오류가 발생함&lt;/span&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751469121248&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ w: &amp;lt;value&amp;gt;, j: &amp;lt;boolean&amp;gt;, wtimeout: &amp;lt;number&amp;gt; }&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;몽고DB 4.4 버전부터는 복제본 세트와 샤딩 클러스터 모두에서 전역 기본 쓰기 보장 수준을 설정할 수 있음
&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;setDefaultRWConcern 명령어를 사용하면 읽기 또는 쓰기 보장 수준에 관한 전역 기본값을 설정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/d378d1b765e7e59ef561fdf110964565.js&quot;&gt;&lt;/script&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB 5.0 버전부터는 기본 쓰기 보장 수준이 { w: &quot;majority&quot; }로 설정되어 있지만 &lt;span style=&quot;color: #ee2323;&quot;&gt;중재자가 포함된 배포에서는 다음과 같은 예외 상황이 적용됨&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;투표 과반수는 투표할 수 있는 구성원 수의 절반에 1을 더한 후 내림한 값으로 계산됨; 데이터를 보유한 투표 가능 구성원의 수가 해당 투표 과반수에 미치지 못한 경우, 기본 쓰기 보장 수준은 { w: 1 }으로 조정됨&lt;/li&gt;
&lt;li&gt;그 외의 모든 경우에는 기본 쓰기 보장 수준이 { w: &quot;majority&quot; }를 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.2 쓰기 보장 수준의 중요성&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;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;i&gt; w: 0&lt;/i&gt;과 같은 낮은 쓰기 보장 수준은 쓰기 작업의 지연 시간을 줄여 성능을 향상할 수 있지만 &lt;span style=&quot;color: #ee2323;&quot;&gt;데이터의 안정성을 저해할 수 있는 위험 존재&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내구성 측면:&lt;/b&gt; &lt;i&gt;w: &quot;majority&quot;&lt;/i&gt;와 같은 높은 쓰기 보장 수준은 과반수 서버로부터의 확인을 통해 데이터의 안전성을 보장하지만 &lt;span style=&quot;color: #ee2323;&quot;&gt;쓰기 작업에 약간의 지연이 발생할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 읽기 선호도 (Read Concern)&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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.1 읽기 선호도 구성 요소&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;몽고DB는 다음과 같은 다섯 가지 읽기 선호도 모드를 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;primary:&lt;/b&gt; 모든 읽기 작업을 주 서버로 전달 (default)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;primaryPreferred:&lt;/b&gt; 먼저 주 서버에서 읽기를 수행하며, 불가능한 경우 보조 서버를 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;secondary:&lt;/b&gt; 모든 읽기 작업을 보조 서버로 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;secondaryPreferred:&lt;/b&gt; 먼저 보조 서버에서 읽기를 수행하며, 불가능한 경우 주 서버를 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;nearest:&lt;/b&gt; 서버의 상태와 관계없이 네트워크 지연이 가장 낮은 서버에서 읽기를 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.2 읽기 선호도의 중요성&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;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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;6. 읽기 보장 수준&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;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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.1 읽기 보장 수준의 구성 요소&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;몽고DB에서 지원하는 읽기 보장 수준은 다음과 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&quot;local&quot;:&lt;/b&gt; 복제 상태와 관계없이 쿼리 시작 시점에 몽고DB 인스턴스에서 접근할 수 있는 최신 데이터를 반환 (default)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;available&quot;:&lt;/b&gt; 쿼리 시점에 분산 시스템에서 즉시 사용 가능한 데이터를 반환하며 이는 가장 빠른 응답 시간을 제공하지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;데이터의 일관성은 보장하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;majority&quot;:&lt;/b&gt; 복제본 세트 구성원의 과반수가 확인한 데이터를 반환하여 높은 수준의 데이터 일관성을 보장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;linearizable&quot;:&lt;/b&gt; 읽기 작업 시작 이전에 완료된 모든 과반수 확인 쓰기를 반영하는 데이터를 반환함으로써 최고 수준의 데이터 일관성을 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;snapshot&quot;:&lt;/b&gt; 모든 복제본 세트 구성원에서 특정 시점의 데이터를 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.2 읽기 보장 수준의 중요성&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;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; &quot;majority&quot;나 &quot;linearizable&quot;과 같은 높은 수준의 읽기 보장을 설정하면 복제본 세트의 모든 서버에서 일관된 데이터가 반환되도록 보장할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;격리성 측면:&lt;/b&gt; &quot;snapshot&quot; 읽기 보장 수준을 사용하면 트랜잭션 전체에서 일관된 데이터 뷰를 유지할 수 있으며, 동시에 발생하는 쓰기 작업으로부터 트랜잭션을 격리할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;7. 복제 메서드&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;mongosh는 복제본 세트를 쉽게 관리할 수 있는 다양한 셸 도우미 메서드를 제공하며 다음은 복제된 몽고DB 환경을 관리하는 데 필요한 주요 메서드들
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;rs.add():&lt;/b&gt; 복제본 세트에 새로운 구성원 추가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.addArb():&lt;/b&gt; 복제본 세트에 중재자 추가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.conf():&lt;/b&gt; 복제본 세트의 현재 구성 정보 표시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.initiate(): &lt;/b&gt;새로운 복제본 세트를 초기화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.printReplicationInfo():&lt;/b&gt; 주 서버 관점에서의 복제본 세트 상태 요약 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.status():&lt;/b&gt; 복제본 세트의 현재 상태 정보를 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.reconfig():&lt;/b&gt; 기존 복제본 세트의 구성을 새로운 설정으로 변경&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rs.stepDown():&lt;/b&gt; 현재 주 서버를 보조 서버로 강제 전환하여 새로운 선거를 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i.g. &quot;replSetResizeOplog&quot; 명령은 복제본 세트의 가변 oplog 크기를 조정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;샤딩&lt;/b&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;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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 왜 샤딩이 필요한가?&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;span style=&quot;color: #ee2323;&quot;&gt;성능 저하를 유발&lt;/span&gt;할 수 있음&lt;/li&gt;
&lt;li&gt;또한 대부분의 시스템은 효율적으로 관리할 수 있는 데이터양에 제한이 있어, 이를 초과할 경우 &lt;span style=&quot;color: #ee2323;&quot;&gt;시스템 장애가 발생&lt;/span&gt;할 수 있음&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;b&gt;수직 확장:&lt;/b&gt; 단일 서버의 성능을 향상하는 방식으로, CPU 업그레이드, RAM 증설, 저장 공간 확장 등이 포함되지만 단일 서버가 처리할 수 있는 작업량에는 기술적 한계가 존재하여 해당 방식은 &lt;span style=&quot;color: #ee2323;&quot;&gt;근본적인 제약이 존재&lt;/span&gt;함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수평 확장:&lt;/b&gt; 시스템의 데이터와 작업량을 여러 서버에 분산시키는 방식으로, 필요에 따라 서버 수를 증가시키는 방식으로 &lt;b&gt;각 서버가 전체 작업의 일부만 처리하므로 단일 고성능 서버보다 효율적&lt;/b&gt;일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 샤딩 클러스터의 주요 요소&lt;/b&gt;&lt;/p&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;mongos:&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;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;969&quot; data-origin-height=&quot;691&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1sokb/btsO4NLYWUk/KkQjkvhpHdkqKQsDk6NCwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1sokb/btsO4NLYWUk/KkQjkvhpHdkqKQsDk6NCwk/img.png&quot; data-alt=&quot;https://www.oreilly.com/library/view/mastering-mongodb-3x/9781783982608/d9f7fa19-f9a1-4a1e-864b-e487d1c6e78a.xhtml&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1sokb/btsO4NLYWUk/KkQjkvhpHdkqKQsDk6NCwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1sokb%2FbtsO4NLYWUk%2FKkQjkvhpHdkqKQsDk6NCwk%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;969&quot; height=&quot;691&quot; data-origin-width=&quot;969&quot; data-origin-height=&quot;691&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.oreilly.com/library/view/mastering-mongodb-3x/9781783982608/d9f7fa19-f9a1-4a1e-864b-e487d1c6e78a.xhtml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&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;몽고DB의 데이터 샤딩은 컬렉션 단위로 이루어지며 하나의 컬렉션에 속한 데이터가 클러스터 내 여러 샤드에 분산되어 저장되는 방식
&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;/li&gt;
&lt;/ul&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;새로운 데이터베이스가 생성될 때, mongos 프로세스는 클러스터 내에서 가장 적은 데이터를 보유한 샤드를 주 샤드로 자동 선택하며 이때 listDatabases 명령어가 반환하는 totalSize 필드가 선택 기준의 하나로 활용됨&lt;/li&gt;
&lt;li&gt;데이터베이스가 생성된 후에도 movePrimary 명령어를 사용하여 주 샤드를 다른 샤드로 이동할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 마이크로 샤딩&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;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;/li&gt;
&lt;/ul&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;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 프로세스의 캐시 크기 설정이 중요한데, 이는 WiredTiger 스토리지 엔진의 storage.wiredTiger.engineConfig.cacheSizeGB 설정을 통해 조정할 수 있으며 해당 캐시는 각 프로세스의 작업 세트를 충분히 수용할 수 있을 만큼의 크기를 확보해야 함 (default 값은 전체 RAM에서 1GB를 뺀 값의 50%)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단일 서버에서 여러 몽고DB 프로세스를 운영할 때는 해당 설정값을 조정&lt;/b&gt;해야 하며 &lt;span style=&quot;color: #ee2323;&quot;&gt;모든 프로세스가 사용하는 총 메모리가 서버의 가용 RAM을 초과하지 않도록 주의해야 함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ex) 16GB RAM이 탑재된 서버에서 두 개의 몽고DB 프로세스를 실행하는 경우 각 프로세스의 storage.wiredTiger.engineConfig.cacheSizeGB 값을 기본값인 50%가 아닌 25%인 4GB로 설정하는 것이 바람직함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. 샤딩의 이점&lt;/span&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; 샤드 개수를 늘리면 전체 용량을 늘리는 효과가 있음 i.g. 샤드 하나의 저장 공간이 4TB라면, 새로 샤드를 추가할 때마다 전체 저장 용량이 4TB씩 늘어남&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Zone 샤딩을 통한 데이터의 지역성 확보:&lt;/b&gt; 데이터베이스를 여러 지역에 분산 배치할 수 있어 글로벌 분산 애플리케이션에 매우 적합함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 데이터 분산&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;샤딩된 몽고DB 클러스터에는 데이터를 적절하게 분산하는 것이 매우 중요함&lt;/li&gt;
&lt;li&gt;데이터가 효율적으로 분산되어 있을 때 작업 부하가 균형을 이루고, 전반적인 시스템 성능이 향상되며, 확장성도 높아짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.1 샤드 키&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;몽고DB는 컬렉션 단위로 샤딩을 수행하여 사용자가 원하는 컬렉션을 선택적으로 샤딩할 수 있는데 이때 샤드 키의 선택이 매우 중요함&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;부적절한 샤드 키 선택은 데이터 분배의 비효율성, 샤드 간 불균형한 부하, 그리고 쿼리 성능 저하를 초래할 수 있음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이러한 문제로 인해 일부 샤드에만 과도한 부하가 집중되고 다른 샤드는 충분히 활용되지 못할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;심각한 경우에는 핫 샤드라고 불리는 특정 샤드에 병목현상이 발생하여 클러스터 전체의 성능에 심각한 영향을 미칠 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;몽고DB는 하나 이상의 문서 필드로 구성된 샤드 키를 사용하여 컬렉션의 문서들을 여러 샤드에 분산시킴
&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.2 샤딩 전략&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몽고DB는 데이터를 분산하기 위해 두 가지 샤딩 전략을 제공합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가. 범위 기반 샤딩 (default)&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;li&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;span style=&quot;color: #ee2323;&quot;&gt;모여 있는 청크가 병목 지점&lt;/span&gt;이 될 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비단조 증감 값:&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;점진적으로 증가하거나 감소하는 값을 샤드 키로 사용하면 삽입 작업이 단일 청크에 집중&lt;/span&gt;될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&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;/li&gt;
&lt;li&gt;해시 샤딩은 범위 기반 샤딩과 달리 &lt;span style=&quot;color: #ee2323;&quot;&gt;연속적인 범위의 데이터를 조회할 때는 효율적이지 않지만&lt;/span&gt; ObjectId나 타임스탬프처럼 단조증가하는 필드를 샤드 키로 사용할 때 적합한 방식&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;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;몽고DB 4.4 버전부터는 단일 해시 필드를 포함하는 복합 인덱스를 생성할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복합 해시 인덱스를 만들려면 인덱스 생성 시 특정 인덱스 키 값을 hashed로 지정하면 됨&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;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/fd12861e3f79a3ec7d860ada1788f7d7.js&quot;&gt;&lt;/script&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;위 명령을 통해 planets 컬렉션에 관해 name 필드는 오름차순으로, _id 필드는 해시 값으로 구성된 복합 해시 인덱스가 생성되며, 이를 기반으로 샤딩이 수행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.3 샤드 키 인덱스&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;반면, 비어 있는 컬렉션을 샤딩할 때 좀 더 유연한데 이때는 지정된 샤드 키에 맞는 인덱스가 없더라도 몽고DB가 자동으로 필요한 지원 인덱스를 생성해 줌&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;6. 청크&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;몽고DB는 샤딩된 데이터를 청크 또는 범위라고 불리는 개별 단위로 관리됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;몽고DB 5.2 버전부터는 청크의 기본 크기가 128MB로 설정되어 있으며, 이전 버전에서는 64MB였음&lt;/li&gt;
&lt;li&gt;각 청크는 샤드 키를 기준으로 하한값과 상한값이 정해지며, 특정 샤드 내에서 연속된 샤드 키 값들을 포함함&lt;/li&gt;
&lt;li&gt;이전 버전에서는 청크의 크기가 설정된 최대 크기를 초과하면 자동 분할 기능이 지원됐지만 6.1 버전부터는 자동 분할 기능이 제거되는 대신 청크가 서로 다른 샤드 간에 이동될 때만 분할이 이루어지도록 수정됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.1 밸런서와 균일한 청크 분해&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;몽고DB 6.0.3 버전부터는 샤딩 클러스터의 데이터 분산 기준이 청크의 수가 아닌 실제 데이터의 크기로 변경됨
&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;/li&gt;
&lt;/ul&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;span style=&quot;color: #ee2323;&quot;&gt;실행 중에 시스템 성능에 약간의 영향을 끼칠 수 있음&lt;/span&gt;&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;각 샤드는 한 번에 하나의 마이그레이션에만 참여할 수 있음; 밸런서는 데이터 마이그레이션을 차례대로 수행하며 n개의 샤드로 구성된 클러스터에는 최대 n/2개의 동시 마이그레이션이 가능함&lt;/li&gt;
&lt;li&gt;특정 컬렉션에서 데이터가 가장 많은 샤드와 가장 적은 샤드 간의 차이가 마이그레이션 임곗값에 도달할 때만 밸런싱을 시작; 샤드 간 데이터 차이가 청크 크기의 3배 미만일 경우 해당 컬렉션은 균형이 잡힌 것으로 간주함&lt;/li&gt;
&lt;li&gt;운영 환경에서는 서비스 영향을 최소화하기 위해 밸런서 윈도라고 불리는 특정 시간대를 지정하여 밸런서의 작동 시간을 제한할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;7. 청크 관리&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7.1 점보 청크&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;몽고DB에서는 지정된 크기를 초과하면서도 자동으로 분할이 불가능한 청크를 jumbo 상태로 분류함&lt;/li&gt;
&lt;li&gt;일반적으로 몽고DB가 청크의 분할과 밸런싱을 자동으로 관리하지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;점보 청크의 경우에는 수동 개입이 필요한 상황이 발생할 수 있음&lt;/span&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;청크 분할이 가능한 경우 몽고DB는 분할 작업을 수행한 뒤 자동으로 점보 플래그를 제거함&lt;/li&gt;
&lt;li&gt;이러한 점보 청크 분할을 위해 sh.splitAt() 또는 sh.splitFind() 메서드를 활용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7.2 나눌 수 없는 청크&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;span style=&quot;color: #ee2323;&quot;&gt;몽고DB에서는 단일 샤드 키값의 범위만을 가진 청크와 같이 특정 상황에서 더 이상 점보 상태가 아닌 청크도 분할이 불가능할 수 있음&lt;/span&gt;&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;점보 플래그를 수동으로 제거하려면 admin 데이터베이스에서 clearJumboFlag 명령을 실행해야 하며 이때 샤딩된 컬렉션의 네임스페이스와 함께 다음 중 하나를 지정해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/8a8ddea2b89edbc3acdcc74fe376e21c.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7.3 범위 사전 분할&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;span style=&quot;color: #ee2323;&quot;&gt;몽고DB가 충분한 범위를 생성하지 못하거나, 필요한 처리량만큼의 속도로 데이터를 분산시키지 못하는 상황이 발생할 수 있음&lt;/span&gt;&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;빈 범위를 수동으로 나누기 위해서는 split 명령을 사용할 수 있으며 해당 명령은 샤딩 클러스터에서 하나의 청크를 두 개의 독립된 청크로 나눔
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 split 명령은 반드시 admin 데이터베이스에서 실행해야 함&lt;/li&gt;
&lt;li&gt;아래 예제는 myapp.products 컬렉션에서 price 필드를 샤드 키로 사용하고 있고, 이를 네 개의 서로 다른 가격 구간으로 사전에 나누는 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/f65803462d82f27230e743b26efcff6c.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;몽고DB 6.0부터는 밸런서가 데이터의 실제 크기를 기준으로 샤드 간 분배를 수행하므로 위 예제처럼 &lt;span style=&quot;color: #ee2323;&quot;&gt;단순히 범위를 나누는 것만으로는 데이터가 각 샤드에 균등하게 분산된다고 보장할 수 없음&lt;/span&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/0213b7900739d94ab3c85b8382517362.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;8. 샤딩된 데이터 쿼리하기&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;몽고DB의 샤딩 클러스터에서 데이터를 조회하는 방식은 단일 서버나 복제본 세트에서의 조회 방식과는 차이가 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 서버나 복제본 세트의 주 서버에 직접 연결하는 대신, mongos라는 쿼리 라우터에 연결하여 데이터를 요청함&lt;/li&gt;
&lt;li&gt;mongos는 요청된 데이터가 어떤 샤드에 있는지 판단하고 쿼리를 적절한 위치로 라우팅하는 임무를 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.1 mongos 라우터&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;mongos 인스턴스는 몽고DB 클러스터의 단일 접점 임무를 수행함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션은 개별 샤드에 직접 연결하지 않고 mongos를 통해 클러스터와 통신하며, mongos는 쿼리를 실행하고 결과를 취합하여 애플리케이션에 전달함&lt;/li&gt;
&lt;li&gt;mongos는 상태를 저장하지 않는 가벼운 프로세스로 시스템 자원을 많이 사용하지 않는다는 장점이 있음&lt;/li&gt;
&lt;li&gt;주요 역할은 쿼리 요청을 프록시하는 것으로, 수신된 쿼리를 분산하여 적절한 샤드를 선택하고 해당 샤드에 커서를 설정함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.2 find&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;쿼리에 샤드 키나 샤드 키의 접두사가 포함되어 있다면, mongos는 대상이 되는 샤드만을 선택적으로 쿼리하는 표적화된 작업을 수행함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿼리가 샤드 키의 접두사 혹은 완전한 샤드 키를 포함할 경우, mongos는 해당 데이터가 있는 특정 샤드만을 대상으로 쿼리를 수행함&lt;/li&gt;
&lt;li&gt;반면, 샤드 키에 포함되지 않는 필드를 대상으로 쿼리 할 경우 적&lt;span style=&quot;color: #ee2323;&quot;&gt;절한 샤드를 특정할 수 없어 모든 샤드를 대상으로 브로드캐스팅 쿼리를 수행&lt;/span&gt;하는데 이를 스캐터-개더 작업 또는 팬아웃 쿼리라고도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.3 sort(), limit(), skip()&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;샤드 키를 정렬 기준으로 사용하면, mongos가 쿼리할 샤드의 순서를 효율적으로 결정하여 최적화된 작업을 수행할 수 있음&lt;/li&gt;
&lt;li&gt;샤드 키가 아닌 다른 기준으로 정렬하면 팬아웃 쿼리가 발생하며 이 경우 주 샤드는 mongos에 정렬된 결과를 전달하기 전에 로컬에서 분산 병합 정렬을 수행함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;쿼리의 limit은 개별 샤드와 mongos 단계에서 각각 적용되는데 이는 여러 샤드에서 결과가 반환될 수 있기 때문&lt;/li&gt;
&lt;li&gt;반면 skip 연산은 개별 샤드에 전달되지 않고, mongos가 모든 결과를 로컬에서 확인한 후 적용됨&lt;/li&gt;
&lt;li&gt;skip()과 limit() 커서 메서드를 함께 사용하면 mongos가 이 두 값을 개별 샤드에 전달하여 쿼리를 최적화시키며 이는 페이지네이션 구현에 특히 유용함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.4 수정과 삭제&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;몽고DB 7.0 버전부터는 update, delete와 같은 문서 수정 작업의 처리 방식이 단순화됨&lt;/li&gt;
&lt;li&gt;쿼리의 find() 부분에서 샤드 키가 포함된 경우, mongos는 기존처럼 해당 샤드로 쿼리를 직접 전달하지만 find 부분에 샤드 키가 없더라도 이전 버전과 달리 팬아웃 작업이 발생하지 않음&lt;/li&gt;
&lt;li&gt;updateOne(), deleteOne(), findAndModify() 작업을 수행할 때도 더 이상 샤드 키나 _id 값을 필수적으로 포함할 필요가 없음
&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.5 헤지 읽기 (hedge read)&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;몽고DB 4.4 버전부터 mongos 인스턴스는 헤지 읽기라는 기능을 통해 비주요 읽기 선호도를 활용할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 기능을 사용하면 mongos 인스턴스가 쿼리가 필요한 각 샤드의 복제본 세트에서 두 구성원에게 동시에 읽기 작업을 요청하고, 각 샤드에서 가장 먼저 응답한 결과를 반환함&lt;/li&gt;
&lt;li&gt;헤지 읽기 지원하는 작업에는 collStats, count, dataSize, dbStats, distinct, filemd5, find, listCollections, listIndexes, planCacheListFilters가 포함됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;9. 샤딩 메서드&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;몽고DB는 데이터 분산 관리를 위한 다양한 도우미 메서드를 제공하고 있으며 이러한 메서드들은 샤딩 활성화, 데이터 분산 방식 정의, 샤딩, 상태 모니터링 등에 활용됨&lt;/li&gt;
&lt;li&gt;sh.shardCollection()은 몽고DB에서 샤딩을 설정하는 데 필수적인 메서드
&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;db.collection.getShardDistribution()은 특정 샤딩된 컬렉션의 샤드 간 데이터 분포에 관한 상세 정보를 제공하며 해당 명령어의 출력 정보는 다음과 같음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;&lt;b&gt;종류&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;shard-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;문자열&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;샤드 이름을 보유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;host-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;문자열&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;호스트 이름을 보유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;size-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;숫자&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;측정 단위를 포함한 데이터의 크기를 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;count-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;숫자&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;샤드에 있는 문서 수를 보고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;numberof chunks-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;숫자&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;샤드의 청크 수를 보고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;size-x&amp;gt;&lt;br /&gt;/&lt;br /&gt;&amp;lt;numberof chunks-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;계산된 값&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;샤드의 청크당 예상 데이터 크기를 반영&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;count-x&amp;gt;&lt;br /&gt;/&lt;br /&gt;&amp;lt;numberofchunks-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;계산된 값&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;샤드에 관한 청크당 예상 문서 수를 반영&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;stats.size&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;숫자&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;측정 단위를 포함하여 샤드된 컬렉션에 있느 데이터와 총 크기를 보고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;stats.count&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;숫자&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;샤드된 컬렉션의 문서 총수를 보고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;calctotallchunks&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;계산된 값&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;모든 샤드의 청크 수를 보고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;estDataPercent-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;계산된 값&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&quot;&gt;각 샤드의 예상 데이터의 크기를 컬렉션의 전체 데이터 크기 대비 백분율로 나타냄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.8216%; text-align: center;&quot;&gt;&lt;b&gt;&amp;lt;estDocPercent-x&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7985%; text-align: center;&quot;&gt;계산된 값&lt;/td&gt;
&lt;td style=&quot;width: 64.3798%; text-align: left;&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;&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;sh.status()는 샤딩 클러스터의 정보를 제공함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;verbose 매개변수를 통해 출력의 상세 수준을 조정할 수 있어 개요나 상세 보고서 중 선택이 가능함&lt;/li&gt;
&lt;li&gt;해당 명령어는 샤딩 버전, 각 샤드의 세부 정보, 활성 mongos 인스턴스 상태, 자동 분할 상태, 밸런서 상태 그리고 데이터베이스와 샤딩된 컬렉션 정보를 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;sh.getBalancerState()는 현재 밸런서의 활성 상태를 나타내는 불리언 값을 반환&lt;/li&gt;
&lt;li&gt;집계 단계에서 $shardedDataDistribution은 샤딩 클러스터의 데이터 분포 정보를 반환&lt;/li&gt;
&lt;li&gt;몽고DB 5.0 버전부터는 sh.reshardCollection() 메서드를 통해 컬렉션의 샤드 키를 수정하여 클러스터 전반의 데이터 분산 방식을 변경할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;단, 재샤딩 작업 전에는 애플리케이션이 2초간의 쓰기 차단을 허용할 수 있는지 확인해야 함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;또한 데이터베이스 서버에 스토리지, I/O, CPU 사용량과 같은 필수 자원이 갖춰져야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;몽고DB 7.0 버전의 새로운 샤딩 클러스터 기능&lt;/b&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 7.0 버전은 운영과 개발자 사용 사례 면에서 샤딩 클러스터의 관리와 이해를 더욱 단순화했음
&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 샤드 키 조언자 명령어&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;몽고DB 7.0 버전의 신규 기능들은 복잡한 데이터 패턴과 상충 관계로 인해 까다로웠던 샤드 키 선택 과정을 간소화하는 데 중점을 둠
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;analyzeShardKey는 기존 데이터를 기반으로 후보 샤드 키를 평가할 수 있게 해주며 몽고DB 7.0의 샤드 키 분석은 고유성, 빈도, 단조성 등의 지표를 통해 샤드 키의 적합성을 평가함&lt;/li&gt;
&lt;li&gt;configureQueryAnalyzer는 클러스터 전반의 쿼리 라우팅 패턴에 관한 지표를 제공하여 불균형한 부하와 과부하 샤드를 식별하는 데 도움을 주며 해당 명령어는 기존 구성과 새로운 구성을 설명하는 필드들이 포함된 문서를 반환함; 이러한 두 명령어를 통해 초기 샤드 키를 설정하거나 실시간 리샤딩을 준비할 때 필요한 데이터를 바탕으로 더욱 확신 있는 의사결정이 가능해짐&lt;/li&gt;
&lt;li&gt;mergeAllChunksOnShard 명령어는 특정 샤드가 보유한 컬렉션의 모든 병합할 수 있는 데이터 청크를 통합하도록 설계되었으며 이는 특정 샤드에서 병합할 수 있는 모든 청크를 찾아 병합함으로써 샤딩 유지보수 작업 중 발생하는 성능 저하 문제를 해결함; 이를 통해 쿼리 대상 청크의 수를 줄여 단편화를 감소시키고 성능을 향상할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. AutoMerger&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;AutoMerger는 특정 병합 가능성 요구사항을 충족하는 청크들을 자동으로 병합하는 기능이며 프로세스는 밸런싱 작업의 하나로 백그라운드에서 실행됨&lt;/li&gt;
&lt;li&gt;AutoMerger는 비활성화되지 않는 한 밸런서가 처음 활성화될 때 시작되며 각 실행 후 설정된 간격 (autoMergerIntervalSecs)동안 일시 중지됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활성화 상태에서는 정해진 간격마다 자동 병합을 수행하며, 각 컬렉션에 관해 연속적인 병합 사이에 최소 지연 시간 (autoMergerThrottlingMS)을 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 샤드 키 없는 명령어 지원&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;몽고DB 7.0부터는 updateOne, deleteOne, findAndModify 등의 명령어들이 샤딩 클러스터와 일반 클러스터 모두에서 일관되게 작동하며 필요한 경우에는 성능 최적화를 위한 옵션도 함께 제공됨&lt;/li&gt;
&lt;/ul&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;b&gt;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마스터링 몽고DB 7.0&lt;/p&gt;</description>
      <category>DB/마스터링 몽고DB 7.0</category>
      <category>MongoDB</category>
      <category>몽고db</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2728</guid>
      <comments>https://jaimemin.tistory.com/2728#entry2728comment</comments>
      <pubDate>Sat, 5 Jul 2025 01:04:03 +0900</pubDate>
    </item>
    <item>
      <title>LLM 기반 GitLab Merge Request 자동 리뷰 PoC</title>
      <link>https://jaimemin.tistory.com/2727</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도입 배경&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 업무 프로세스 상 새로운 기능을 개발할 때 feature 브랜치를 생성하여 작업을 진행한 뒤, main 브랜치로의 병합(Merge Request)을 요청하는 표준적인 협업 프로세스를 따르고 있고 이 과정에서 리뷰어는 Merge Request가 생성될 때마다 변경된 코드와 커밋된 파일을 꼼꼼하게 확인하고, 직접 리뷰 후 승인을 진행해야 함&lt;/li&gt;
&lt;li&gt;그러나 실제 업무 현장에서는 리뷰어의 업무가 몰리거나 여러 건의 Merge Request가 동시에 올라올 경우, &lt;span style=&quot;color: #c9372c;&quot; data-text-custom-color=&quot;#ff5630&quot; data-renderer-mark=&quot;true&quot;&gt;리뷰에 충분한 시간을 할애하기 어렵다는 문제가 자주 발생&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;circle&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 한계를 보완하기 위해, &lt;b&gt;LLM을 활용하여 Merge Request의 변경 파일을 자동 분석하고, 주요 개선 포인트를 도출하여 GitLab의 Discussion에 코멘트로 남기는 시스템&lt;/b&gt;을 PoC로 개발&lt;/li&gt;
&lt;li&gt;이를 통해 리뷰어는 LLM이 미리 도출한 개선점과 잠재적 문제점을 참고하여 더욱 효율적이고 신뢰성 높은 코드 리뷰를 수행할 수 있으며, 궁극적으로 장애 발생 가능성을 줄이고 코드 품질을 향상하는 데 &lt;span style=&quot;background-color: #ffffff; color: #292a2e; text-align: left;&quot;&gt;기여하고자 함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;전체적인-Flow&quot; style=&quot;background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-renderer-start-pos=&quot;754&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;전체적인 Flow&lt;/b&gt;&lt;/h4&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;1716&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2Bp6N/btsOR9VAdGv/zOOY6lrUncS1GdHdGGfae1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2Bp6N/btsOR9VAdGv/zOOY6lrUncS1GdHdGGfae1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2Bp6N/btsOR9VAdGv/zOOY6lrUncS1GdHdGGfae1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2Bp6N%2FbtsOR9VAdGv%2FzOOY6lrUncS1GdHdGGfae1%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;1716&quot; height=&quot;956&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;FastAPI-애플리케이션-코드&quot; style=&quot;background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-renderer-start-pos=&quot;771&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;FastAPI 애플리케이션 코드&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;size18&quot;&gt;&lt;b&gt;app.py&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/8905a62c7c3b400f1caade248bd07669.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p id=&quot;gitlab_client.py&quot; style=&quot;background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-renderer-start-pos=&quot;2248&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;gitlab_client.py&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/bfa81535a2f78c0a3ced8e905645ac88.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ai_analyzer.py&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/ba70dfe92c67f756912bebc124802508.js&quot;&gt;&lt;/script&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;1088&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZ7mFK/btsOTsF9jxU/qonKPsn4JK7BXI2nc5YX90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZ7mFK/btsOTsF9jxU/qonKPsn4JK7BXI2nc5YX90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZ7mFK/btsOTsF9jxU/qonKPsn4JK7BXI2nc5YX90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZ7mFK%2FbtsOTsF9jxU%2FqonKPsn4JK7BXI2nc5YX90%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;1452&quot; height=&quot;1088&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;1088&quot;/&gt;&lt;/span&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;a href=&quot;https://github.com/jaimemin/gitlab-mr-llm-review-poc&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/jaimemin/gitlab-mr-llm-review-poc&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1750918522233&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - jaimemin/gitlab-mr-llm-review-poc&quot; data-og-description=&quot;Contribute to jaimemin/gitlab-mr-llm-review-poc development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/jaimemin/gitlab-mr-llm-review-poc&quot; data-og-url=&quot;https://github.com/jaimemin/gitlab-mr-llm-review-poc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SfZ7E/hyZbqrUBlq/mHVZYqjGBzU9SQREOxcuv0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/berWyV/hyZbyKhqwf/2N3vN43HtgUXJWsRUINfTK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/jaimemin/gitlab-mr-llm-review-poc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/jaimemin/gitlab-mr-llm-review-poc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SfZ7E/hyZbqrUBlq/mHVZYqjGBzU9SQREOxcuv0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/berWyV/hyZbyKhqwf/2N3vN43HtgUXJWsRUINfTK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - jaimemin/gitlab-mr-llm-review-poc&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to jaimemin/gitlab-mr-llm-review-poc development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;b&gt;적용 결과 샘플&lt;/b&gt;&lt;/h4&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-filename=&quot;image-20250625-062427.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;1672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdOpy1/btsOS8nFCrJ/yOhv1kfIAmyYQ5sw6zzv2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdOpy1/btsOS8nFCrJ/yOhv1kfIAmyYQ5sw6zzv2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdOpy1/btsOS8nFCrJ/yOhv1kfIAmyYQ5sw6zzv2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdOpy1%2FbtsOS8nFCrJ%2FyOhv1kfIAmyYQ5sw6zzv2k%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;1388&quot; height=&quot;1672&quot; data-filename=&quot;image-20250625-062427.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;1672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;LLM-리뷰의-장점&quot; style=&quot;background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-renderer-start-pos=&quot;5187&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;LLM 리뷰의 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LLM은 코드의 변경 내역이 주어지면 수초~수십 초 내에 리뷰 피드백을 자동으로 생성&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;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;LLM-리뷰의-한계&quot; style=&quot;background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-renderer-start-pos=&quot;5401&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #c9372c;&quot; data-text-custom-color=&quot;#ff5630&quot; data-renderer-mark=&quot;true&quot;&gt;LLM 리뷰의 한계&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로는 커밋된 파일/함수/클래스의 변경 내용만 파악할 수 있음&lt;/li&gt;
&lt;li&gt;커밋된 코드가 다른 파일&amp;middot;클래스&amp;middot;모듈과 어떻게 상호작용하는지, 즉 연관된 코드 컨텍스트을 충분히 제공받지 못하면, 사이드 이펙트(side effect), 인터페이스/상속 구조 위반, 전체적인 비즈니스 로직에 끼치는 영향 등 을 제대로 파악할 수 없음&lt;/li&gt;
&lt;li&gt;한 번에 변경된 코드가 너무 많을 경우, LLM의 Context Window를 초과하여 오류가 발생하거나 코드 일부만 리뷰되는 문제가 생길 수 있음
&lt;ul style=&quot;list-style-type: circle;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이로 인해 리뷰의 정확성과 일관성이 저하될 수 있으며, 실제로 LLM이 전체 변경사항을 모두 평가하지 못하는 상황이 발생할 수 있음&lt;/li&gt;
&lt;li&gt;이러한 한계를 보완하기 위해서는 단일 Merge Request 또는 커밋의 변경 범위를 가능한 한 작게 유지하는 개발 그라운드룰이 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커밋은 가능한 한 작게 유지하고, 하나의 기능 또는 변경 사항을 하나의 커밋으로 작성하는 것을 권장하며 이렇게 하면 코드 리뷰 및 추적이 용이해지고, 문제가 발생했을 때 롤백이 쉬워짐&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 id=&quot;추후-개선-포인트&quot; style=&quot;background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-renderer-start-pos=&quot;5950&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;추후 개선 포인트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 실무 코드 보안 및 LLM 배포 방식 개선&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 PoC는 오픈 API에 코드를 직접 전송해 리뷰를 받는 구조이므로, 실제 업무 소스코드를 외부 LLM 서비스에 그대로 넘기는 것은 &lt;span style=&quot;color: #c9372c;&quot; data-text-custom-color=&quot;#ff5630&quot; data-renderer-mark=&quot;true&quot;&gt;보안 및 기밀 유지 측면에서 적합하지 않을 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 및 사내 정책 준수가 필요한 경우에&lt;/b&gt;는
&lt;ul style=&quot;list-style-type: circle;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기업용(Enterprise) GPT 등 보안이 강화된 LLM 서비스를 이용하도록 전환하거나, 오픈소스 LLM(i.g. oLLama, DeepSeek 등)을 자체 EPC에 설치하여 내부적으로만 코드 리뷰가 이루어지도록 소스코드 수정 필요&lt;/li&gt;
&lt;li&gt;LLM 호출부를 추상화(interface, adapter 패턴 등)하여 나중에 다양한 LLM 엔진으로 쉽게 교체 가능하도록 구조화하는 것이 바람직함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 프롬프트 엔지니어링&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LLM의 리뷰 결과 품질을 높이기 위해 프롬프트에
&lt;ul style=&quot;list-style-type: circle;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;더 구체적인 리뷰 기준 (i.g. 테스트 코드 유무, 보안 이슈, 모듈화, SRP 위반 등)&lt;/li&gt;
&lt;li&gt;혹은 도입 배경, 업무 도메인 맥락, 사내 개발 문화 등을 입력받아 더 정밀한 피드백을 생성하도록 프롬프트를 개선할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. LLM Agent/Chain 방식 적용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 프롬프트로 LLM을 한 번만 호출하는 방식에서 벗어나, 각 단계를 여러 번의 LLM 호출로 연계하여 처리하는 Agent/Chain 구조를 도입할 수 있음
&lt;ul style=&quot;list-style-type: circle;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;변경 코드 파악&lt;/li&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&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;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 정적 분석 도구를 활용한 영향도 분석 결합&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #292a2e; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SonarQube, CodeQL, pyright, pylint 등과 같은 정적 분석 도구를 활용하면 커밋된 코드가 다른 클래스, 함수, 모듈에 미치는 영향도를 어느 정도 파악할 수 있음&lt;/li&gt;
&lt;li&gt;정적 분석 도구의 영향 분석 결과(예: &amp;ldquo;이 변경이 A, B, C 파일에 영향을 끼칠 수 있음&amp;rdquo;, &amp;ldquo;전역 변수 X가 바뀌었으니, Y, Z 함수에 사이드 이펙트 우려&amp;rdquo; 등)를 LLM 프롬프트와 함께 전달하면, LLM이 보다 정확하고 맥락 있는 리뷰를 제공할 수 있음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>리서치</category>
      <category>Git</category>
      <category>LLM</category>
      <category>Merge Request</category>
      <category>코드 리뷰</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2727</guid>
      <comments>https://jaimemin.tistory.com/2727#entry2727comment</comments>
      <pubDate>Thu, 26 Jun 2025 15:19:01 +0900</pubDate>
    </item>
    <item>
      <title>백준 2025 서강대학교 K512컵</title>
      <link>https://jaimemin.tistory.com/2725</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33990&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A. 백준 33990번 3대 512&lt;/a&gt;&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/216120235b1379cddef9c40b98b24cf7.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33991&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;B. 백준 33991번 전철 통학&lt;/a&gt;&lt;/b&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;에 걸어가서 도착하는 데 걸리는 시간은 맨해튼 거리 공식에 따라 |&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;X &amp;minus; X_i∣+ |Y &amp;minus;Y_i| 분&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;역&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;의 전철은&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;0,&amp;thinsp;Ti,&amp;thinsp;2Ti,&amp;thinsp;3Ti,&amp;hellip;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;분에 도착하므로, 민수가 도착 시간&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Ai&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;분에 가장 가까우면서도 그 이후 도착하는 전철 시각&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;K_i&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;는 &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lceil;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;T_i / &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;A_i&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;rceil; * T_i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;세 개의 역에 대해 각각 이 값을 계산한 뒤 &lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;min⁡{K1,&amp;thinsp;K2,&amp;thinsp;K3}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;이 가장 빠른 탑승 시간&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/d8a3f00804403e4bbe06b29abab430dc.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33992&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;C. 백준 33992번 사막 탐험&lt;/a&gt;&lt;/b&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;두 가지 방법 중 소모 체력이 더 작은 쪽이 답&lt;/span&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;직접 경로: &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;원과 선분이 교차한다면 &amp;ldquo;전체 거리 &amp;ndash; 원 내부 구간 길이&amp;rdquo;만큼 소모하고, 교차하지 않으면 전체 거리만큼 소모&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;b&gt; &lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;오아시스 우회 경로: &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;A에서 원 경계까지, B에서 원 경계까지 각각 최단 거리만큼 걸어서 오아시스 안으로 들어가고, 내부에서는 체력이 전혀 소모되지 않은 뒤 다시 나와 B로 이동하는 방식&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/664539401a617a36e6609c9eababea7f.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33993&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;D. 백준 33993번 지정좌석제&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/b&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;강의실을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&amp;times;C &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;크기의 2차원 그리드로 생각하고, 친구가 이미 앉은 좌표&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(x_i, y_i)&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;에는 1을, 그렇지 않은 빈 칸에는 0을 표시한 뒤 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;2차원 누적합 적용&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;2차원 누적합 S&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;j&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;는 그리드의 (1,1)부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(i,j)&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;까지 사각형 영역 내에 있는 1의 합&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;를 중심으로 한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;W * W &lt;/span&gt;&lt;/span&gt;영역은 &lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;x1 = max⁡(1,&amp;thinsp;x &amp;minus; k), x2 = min⁡(R,&amp;thinsp;x + k), y1 = max⁡(1,&amp;thinsp;y &amp;minus; k), y2=min⁡(C,&amp;thinsp;y + k)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;로 경계를 정할 수 있고, 이 영역 안의 친구 수는 &lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;S[x2][y2]&amp;minus;S[x1 &amp;minus; 1][y2]&amp;minus;S[x2][y1 &amp;minus; 1]+S[x1 &amp;minus; 1][y1&amp;minus;1]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/6edac020c2693851b15f5b47a9eb68f4.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33994&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;E. 백준 33994번 &lt;span&gt;Magical Trees&lt;/span&gt;&lt;/a&gt;&lt;/b&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;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;N이 홀수일 때만 가능하므로, 먼저 홀짝을 판별&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;홀수인 경우에는 &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;near-perfect matching &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;3개를 만든 뒤, 이들을 두 개씩 합쳐서 스패닝 트리를 구성하는 기법을 적용&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;정점 1부터 N까지 있고, 가상의 정점 (N + 1)을 하나 더 추가하여 전체를 짝수 개로 만든 뒤 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;원형 라운드로빈 방식의 1-factorization 알고리즘으로 &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;3라운드 실행&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;각 라운드에서 dummy 정점과 매칭된 간선을 제외하면, 남은 (N &amp;minus; 1) / 2개의 간선이 &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;near-perfect matching&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;이렇게 얻은 매칭을 M₀, M₁, M₂라 할 때, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; T_0 = M_1 &amp;cup; M_2, T_1 = M_0 &amp;cup; M_2, T_2 = M_0 &amp;cup; M_1로 정의하면, 각 T_i는 간선 개수 N &amp;minus; 1개로 스패닝 트리 조건 (연결+무사이클)을 만족하고 동일한 간선은 정확히 두 트리에 속하게 됨&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/bbe8ebed3661d43474b361eeb908c2b2.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/34000&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;F. 백준 34000번 취향 변화&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 수열에서 각 물건에 대해 좋아하면 +1, 싫어하면 &amp;ndash;1의 값을 부여하여 C_1, C_2, &amp;hellip;, C_n 이라는 +1, -1 시퀀스를 얻음&lt;/li&gt;
&lt;li&gt;dong_gas가 왼쪽에서부터 k개를 가져갈 때의 행복도 S(k) = C_1 + ... + C_k&lt;/li&gt;
&lt;li&gt;shandy5833은 나머지로 전체 - S(k)&lt;/li&gt;
&lt;li&gt;두 사람 행복도의 곱 &lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;f(k) = S(k)&amp;thinsp;* (전체 &amp;minus;S(k))로 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;S(k)가 T / 2에 가까울수록 커짐&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;C_i는 1 혹은 -1이고 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;0에서 출발해 T에 이르는 과정에서 중간의 모든 정수 값을 반드시 한 번 이상 통과한다는 성질에 따라 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;S(k) = &amp;lfloor;T / 2&amp;rfloor; 혹은 &amp;lceil;T / 2&amp;rceil;를 만족하는 k가 항상 존재함을 알 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;따라서 가능한 최대 행복도 곱은 s가 &amp;lfloor;T / 2&amp;rfloor;, &amp;lceil;T / 2&amp;rceil;일 때 T^2 / 4&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/1d79f669b506308f1a1d774f9b881b92.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33995&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;G. 백준 33995번 LCS Making&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;S에 빠진 글자가 하나라도 있을 경우 빠진 글자를 T의 글자로 마음껏 사용할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;S에 빠진 글자는 LCS에 기여 X&lt;/li&gt;
&lt;li&gt;따라서 원하는 K만큼만 S에 실제로 등장하는 어떤 문자로 매칭시키고 나머지 (N &amp;ndash; K) 자리를 모두 빠진 문자로 채우면 정확히 LCS 길이 K를 만들 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;S가 알파벳 26글자를 전부 포함하는 경우에는 빠진 글자가 존재하지 않음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;이때는 T에 어느 글자를 넣더라도 S에 해당 글짜가 최소 한 번 이상 나타나므로 LCS는 최소값&lt;/span&gt;&lt;span style=&quot;color: #232425; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #232425; text-align: start;&quot;&gt;&lt;span&gt;f_min &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;이상이 됨 (&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;여기서&lt;/span&gt;&lt;span style=&quot;color: #232425; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #232425; text-align: start;&quot;&gt;&lt;span&gt;f_min⁡&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;은 S에 등장하는 26개 문자 중 가장 적게 등장한 문자의 빈도)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-12&quot;&gt;최소 LCS 길이 =&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f_min&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-12&quot;&gt;최대 LCS 길이는 T = S일 때이므로 N&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-12&quot;&gt;최종 판정 조건은 다음과 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;17-17&quot;&gt;S가 26글자 전부를&lt;span&gt;&amp;nbsp;&lt;/span&gt;포함하지&lt;span&gt;&amp;nbsp;&lt;/span&gt;않는다면, K가 1 이상 N 이하일 때 항상 가능 &amp;rarr; 출력 1&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;18-19&quot;&gt;S가 26글자를&lt;span&gt;&amp;nbsp;&lt;/span&gt;전부 포함한다면, K가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f_min⁡ &amp;lt;= K &amp;lt;= N인&lt;/span&gt;&lt;/span&gt; 경우에만 가능 &amp;rarr; K &amp;gt;= &lt;span&gt;&lt;span&gt;f_min⁡&lt;/span&gt;&lt;/span&gt;이면 1, 그렇지 않으면 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/4bee1adc84381e1748385d2a478ec5fa.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33996&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;H. 백준 33996번 점진적인 수열&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;점진적인 수열이란 길이가 3 이상인 수열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A_1, A_2, &amp;hellip;, A_k에 &lt;/span&gt;&lt;/span&gt;대해 &lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;diff_j = A_(j+1) &amp;minus; A_j&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;라 할 때, 모든&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j = 1, 2, &amp;hellip;, k&amp;minus;2&lt;/span&gt;&lt;/span&gt;에 대하여 diff&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;_(j+1) &amp;isin; {&amp;thinsp;diff_j &amp;minus; 1,  diff_j,  diff_j + 1}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;를 만족하는 것&lt;/li&gt;
&lt;li&gt;각 위치&amp;nbsp;j에 대해, 앞선 모든 위치&amp;nbsp;k &amp;lt; j와의 차이 S_j - S_k를 계산하여 정렬된 리스트&amp;nbsp;diffList[j]에 저장
&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;/li&gt;
&lt;/ul&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;&amp;ldquo;끝나는 위치와 그전 위치 사이의 차이&amp;rdquo;를 기준으로 같은 종류의 부분 수열을 한데 모아 두고, &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;그 묶음에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;몇 개나 있는지&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;와 그들의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;길이를 모두 더한 값&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;을 기록&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-13&quot;&gt;&lt;b&gt;diffList[i]:&lt;/b&gt; k &amp;lt; i인&amp;nbsp;모든 k에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;S_i - S_k&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;를 모아 정렬해 둔 목록&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-25&quot;&gt;&lt;b&gt;cntList[i][idx]:&lt;/b&gt; 차이&lt;span&gt;&amp;nbsp;&lt;/span&gt;diffList[i][idx]를 가진 부분 수열의&lt;span&gt;&amp;nbsp;&lt;/span&gt;개수&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;26-28&quot;&gt;&lt;b&gt;lenList[i][idx]: &lt;/b&gt;위 부분 수열들의&lt;span&gt;&amp;nbsp;&lt;/span&gt;길이 합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;29-44&quot;&gt;각 쌍&lt;span&gt;&amp;nbsp;&lt;/span&gt;(i, j)에 대하여,
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;31-44&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;31-40&quot;&gt;&lt;span&gt;&lt;span&gt;(S_j &amp;minus; S_i)&lt;/span&gt;&lt;/span&gt;에 대해, diffList[i]에서&lt;span&gt; {S_j &amp;minus; S_i - 1&lt;/span&gt;&lt;span&gt;&lt;span&gt;,   S_j &amp;minus; S_i,  S_j &amp;minus; S_i + 1}&lt;/span&gt;&lt;/span&gt;을 이분 탐색으로 찾아 집계된&lt;span&gt;&amp;nbsp;&lt;/span&gt;(cnt, len)을 꺼내고 &lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;newCnt = 1 + &amp;sum;cnt, newLen = 2 + &amp;sum;(len + cnt)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;으로 갱신&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;41-42&quot;&gt;길이 3 이상이 된 부분 수열에서 늘어난 길이 합 &lt;span&gt;&lt;span&gt;&amp;sum;(len + cnt)&lt;/span&gt;&lt;/span&gt;을 정답에 누적&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;43-44&quot;&gt;마지막으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;cntList[j]와&lt;span&gt;&amp;nbsp;&lt;/span&gt;lenList[j]의&lt;span&gt; (S_j &amp;minus; S_i) 위치를&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;newCnt, newLen으로 업데이트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/e020fa4c72a48132da67511481c2320d.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33997&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;I. 백준 33997번 광부가 될 수 있다면&lt;/a&gt;&lt;/b&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;각 행 간 이동은 &amp;ldquo;한 칸만 아래로 내려간 후 그 행에서 좌우로 자유롭게 이동&amp;rdquo;하는 과정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;같은 행에서 열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;에서 열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;로 이동하며 얻는 값은 구간 합으로 간단히 표현할 수 있지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;모든 쌍을 직접 계산하면&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;O(N^2)&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;이 되어 시간 초과가 발생&lt;/span&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: start;&quot;&gt;구간 합을 최적화하기 위해 &amp;ldquo;구간 최소값&amp;rdquo;과 &amp;ldquo;구간 최대값&amp;rdquo;을 미리 구해 두고, DP를 활용하면 각 행을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;O(N)에 처리 가능&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/7e8b82b0fdb4330a340d442f320f4c27.js&quot;&gt;&lt;/script&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;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/33998&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;J. 백준 33998번 거의 같은 문자열&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디토리얼 해설 + gpt 합작품&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;모든 쿼리를 그 길이에 따라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;queriesByLength&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;맵에 저장&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;원본 문자열 S에 대해 26글자의 문자별 누적 빈도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;prefixCounts[i][c]&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;를 미리 계산&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;os&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;os&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;구간일 때, 각 문자&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;의 개수는&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;&lt;span&gt;prefixCounts[pos + L][c] &amp;minus; prefixCounts[pos][c]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;각 쿼리 문자열에 대해 26차원 벡터 형태의 서명을 만들고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;unordered_map&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;으로 고유 ID를 부여&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;S에서 길이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;인 모든 윈도우를 순회하며 앞서 만든 서명과 비교&lt;/span&gt; &lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;일치하는 서명이 존재하면 해당 ID의 카운터를 증가&lt;/span&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;각 쿼리에 대응하는 ID의 집계 값을 정답 배열에 채워 출력&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/84af4b88b1572d95b8dfb881bd1bfe45.js&quot;&gt;&lt;/script&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;개발환경:Visual Studio 2022&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;span&gt;지적, 조언, 질문 환영입니다! 댓글 남겨주세요~&lt;/span&gt;&lt;/p&gt;</description>
      <category>알고리즘/BOJ</category>
      <category>C++</category>
      <category>백준</category>
      <category>알고리즘</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2725</guid>
      <comments>https://jaimemin.tistory.com/2725#entry2725comment</comments>
      <pubDate>Sat, 21 Jun 2025 22:33:55 +0900</pubDate>
    </item>
    <item>
      <title>[Hibernate/JPA] 캐싱</title>
      <link>https://jaimemin.tistory.com/2724</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 데이터베이스 캐싱&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;size18&quot;&gt;&lt;b&gt;1.1 캐싱의 계층 구조&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;8-8&quot;&gt;DB &amp;rarr; OS &amp;rarr; 애플리케이션 &amp;rarr; (ORM) &amp;rarr; 2차 캐시 &amp;rarr; 1차 캐시 등 여러 계층에 걸쳐 존재&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-10&quot;&gt;디스크 접근을 최소화하고, DB/OS/애플리케이션 메모리에서 최대한 데이터를 제공하는 것이 핵심&lt;/li&gt;
&lt;/ul&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;1095&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsOuTg/btsOvWhojNI/z9venEy0VkEGKhPrhE97ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsOuTg/btsOvWhojNI/z9venEy0VkEGKhPrhE97ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsOuTg/btsOvWhojNI/z9venEy0VkEGKhPrhE97ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsOuTg%2FbtsOvWhojNI%2Fz9venEy0VkEGKhPrhE97ak%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;1095&quot; height=&quot;438&quot; data-origin-width=&quot;1095&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.2 캐시 동기화 전략&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;가. Cache-aside&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;16-17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;16-16&quot;&gt;애플리케이션이 캐시에서 먼저 데이터를 찾고, 없으면 DB에서 조회 후 캐시에 넣음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;17-17&quot;&gt;쓰기는 데이터베이스와 캐시를 모두 갱신해야 함 &lt;span style=&quot;color: #ee2323;&quot;&gt;(동기화 주의 필요)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;801&quot; data-origin-height=&quot;487&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WwcJd/btsOwaTTbdK/16C4fYahsYVK0Gm4cZSFy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WwcJd/btsOwaTTbdK/16C4fYahsYVK0Gm4cZSFy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WwcJd/btsOwaTTbdK/16C4fYahsYVK0Gm4cZSFy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWwcJd%2FbtsOwaTTbdK%2F16C4fYahsYVK0Gm4cZSFy0%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;801&quot; height=&quot;487&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;487&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. Read-through&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;19-20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;19-19&quot;&gt;캐시에 데이터가 없을 때, 캐시 시스템이 DB에서 자동으로 데이터 조회 및 캐시 삽입&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;20-20&quot;&gt;애플리케이션에서는 항상 캐시만 조회&lt;/li&gt;
&lt;/ul&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;1098&quot; data-origin-height=&quot;511&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAJju9/btsOwQOdPLi/miAcDsZsfD6xYO5l8Aa6b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAJju9/btsOwQOdPLi/miAcDsZsfD6xYO5l8Aa6b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAJju9/btsOwQOdPLi/miAcDsZsfD6xYO5l8Aa6b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAJju9%2FbtsOwQOdPLi%2FmiAcDsZsfD6xYO5l8Aa6b1%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;1098&quot; height=&quot;511&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;511&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다. Write-through&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;22-23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-22&quot;&gt;쓰기 작업이 캐시와 DB에 동시에 적용됨&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-23&quot;&gt;캐시 일관성 유지가 쉬움&lt;/li&gt;
&lt;/ul&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;1097&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cP7gAM/btsOuLAy9FG/qzTKvfIgNwkAcqzsU9rAn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cP7gAM/btsOuLAy9FG/qzTKvfIgNwkAcqzsU9rAn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cP7gAM/btsOuLAy9FG/qzTKvfIgNwkAcqzsU9rAn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcP7gAM%2FbtsOuLAy9FG%2FqzTKvfIgNwkAcqzsU9rAn0%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;1097&quot; height=&quot;208&quot; data-origin-width=&quot;1097&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라. Write-invalidate&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;25-25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-25&quot;&gt;쓰기 시 캐시에서 해당 데이터를 삭제만 하고, 다음 읽기 때만 최신 데이터로 채움&lt;/li&gt;
&lt;/ul&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;1090&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYIx0v/btsOuQICDYD/TRRyGRqp0tdNR169A5KxsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYIx0v/btsOuQICDYD/TRRyGRqp0tdNR169A5KxsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYIx0v/btsOuQICDYD/TRRyGRqp0tdNR169A5KxsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYIx0v%2FbtsOuQICDYD%2FTRRyGRqp0tdNR169A5KxsK%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;1090&quot; height=&quot;217&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;마. Write-behind&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;27-29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;27-27&quot;&gt;애플리케이션은 캐시에만 쓰고, 일정 주기/조건에 따라 DB에 배치로 반영 (flush)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;28-29&quot;&gt;쓰기 성능 극대화, 데이터 일관성 보장에 추가 로직 필요&lt;/li&gt;
&lt;/ul&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;1094&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cA2epd/btsOwjJ7Xdv/jtyva39txOpKNSO81otKF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cA2epd/btsOwjJ7Xdv/jtyva39txOpKNSO81otKF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cA2epd/btsOwjJ7Xdv/jtyva39txOpKNSO81otKF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcA2epd%2FbtsOwjJ7Xdv%2Fjtyva39txOpKNSO81otKF1%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;1094&quot; height=&quot;427&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.3 데이터베이스와 OS 캐싱&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; background-color: #ffffff; color: #232425; text-align: left;&quot; data-source-line=&quot;35-36&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;35-35&quot;&gt;대부분의 DBMS는&lt;span&gt;&amp;nbsp;&lt;/span&gt;메모리 내 버퍼 풀 (Buffer Pool),&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행 계획 캐시 (Shared Pool),&lt;span&gt;&amp;nbsp;&lt;/span&gt;Redo Log Buffer&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 다양한 캐시 구조 제공&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;36-36&quot;&gt;실제 데이터 페이지, 인덱스, 쿼리 결과, 실행 계획, 임시 작업 결과 등 다양한 객체가 캐싱됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. OS 캐시&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;34-41&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;38-38&quot;&gt;OS 레벨의 페이지 캐시, 파일 시스템 캐시 등&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;39-39&quot;&gt;일부 DB는 Double Buffering (같은 페이지가 OS와 DB buffer pool 모두에 중복 저장)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;40-41&quot;&gt;Direct I/O 지원 DB는 OS 캐시를 우회하여 중복 캐싱을 피함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.4 주요 DBMS별 캐시 구조&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;가. Oracle&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;47-55&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;47-48&quot;&gt;&lt;b&gt;SGA (System Global Area)&lt;/b&gt;: Buffer Pool (디스크 페이지 캐시, 8KB 등), Shared Pool (실행 계획, SQL, 메타데이터), Redo Log Buffer, Large Pool 등&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;49-50&quot;&gt;&lt;b&gt;PGA (Program Global Area)&lt;/b&gt;: 각 세션별 작업 메모리, ORDER BY/JOINS/커서 실행 시 사용&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;51-52&quot;&gt;&lt;b&gt;자동 메모리 관리 (AMM)&lt;/b&gt;: SGA, PGA 크기 자동 조절 지원 (메모리 제한 가능)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;53-55&quot;&gt;&lt;b&gt;Buffer Pool 사이즈 결정&lt;/b&gt;: V$DB_CACHE_ADVICE 뷰로 최적 크기 추정 (캐시 미스율, IO 감소 효과 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;56-56&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p id=&quot;sql-server&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;56-56&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. SQL Server&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;57-63&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;57-58&quot;&gt;&lt;b&gt;Buffer Pool&lt;/b&gt;: 8KB 페이지 단위, 테이블/인덱스 데이터를 RAM에 적재&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;59-61&quot;&gt;&lt;b&gt;메모리 자동 관리&lt;/b&gt;: 시스템의 여유 메모리를 최대한 사용, min/max server memory 설정으로 제한 가능&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;62-63&quot;&gt;&lt;b&gt;메모리 사용량/버퍼 풀 크기 조회 쿼리 제공&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;64-64&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p id=&quot;postgresql&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;64-64&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다. PostgreSQL&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;65-73&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;65-66&quot;&gt;&lt;b&gt;Shared Buffers&lt;/b&gt;: DBMS 내 캐시, 8KB 페이지, 전체 RAM의 15~25% 권장&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;67-68&quot;&gt;&lt;b&gt;OS 캐시 의존&lt;/b&gt;: Direct I/O 미지원, OS 파일 시스템 캐시와 Double Buffering 발생&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;69-70&quot;&gt;&lt;b&gt;Vacuum 프로세스&lt;/b&gt;: 오래된/삭제된 버전 페이지 정리, GC와 유사&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;71-73&quot;&gt;&lt;b&gt;effective_cache_size&lt;/b&gt;: OS 캐시 크기를 PostgreSQL 옵티마이저에 알려줌(쿼리 플랜 최적화)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;74-74&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p id=&quot;mysql(innodb)&quot; style=&quot;list-style-type: none; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;74-74&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라. MySQL(InnoDB)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;75-80&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;75-76&quot;&gt;&lt;b&gt;Buffer Pool&lt;/b&gt;: 16KB 페이지, 전체 RAM의 80~90%까지도 할당 권장 (특히 대용량 시스템)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;77-78&quot;&gt;&lt;b&gt;Direct I/O 지원&lt;/b&gt;: OS 캐시 우회 가능, Double Buffering 방지&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;79-80&quot;&gt;SHOW ENGINE INNODB STATUS로 상세 메모리/버퍼 풀 통계 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.5 캐시 크기, 정책과 성능의 상관관계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;85-92&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;85-86&quot;&gt;Buffer Pool/Shared Buffers 크기가 작으면 캐시 미스율 증가 &amp;rarr; 더 많은 디스크 IO &amp;rarr; 성능 저하&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;87-88&quot;&gt;반면, 너무 크게 설정하면 GC, vacuum 등 유지 보수 작업이 느려지고, OS/DB 메모리 경쟁 심화&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;89-92&quot;&gt;따라서 적정 크기로 설정하는 것이 중요
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;90-92&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;90-90&quot;&gt;&lt;b&gt;Oracle/SQL Server/MySQL:&lt;/b&gt; RAM의 70~90%&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;91-92&quot;&gt;&lt;b&gt;PostgreSQL:&lt;/b&gt; RAM의 15~25% (나머지는 OS 캐시)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.6 캐시 히트율과 최적화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;97-103&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;97-98&quot;&gt;캐시 히트율이 높을수록 즉, 캐시 미스가 적을수록&amp;nbsp;DB나 디스크 접근 없이 메모리에서 데이터 제공 &amp;rarr; 대폭적인 성능 향상&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;99-100&quot;&gt;캐시 미스 시에는 데이터베이스 또는 디스크에서 데이터를 읽어야 하므로 응답시간이 급격히 증가&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;101-103&quot;&gt;&lt;b&gt;따라서 히트율을 정기적으로 모니터링하고, 빈번히 사용되는 쿼리/테이블/인덱스가 캐시에 적재되도록 테이블 구조, 인덱스, 쿼리, 메모리 크기 등 조정하는 것을 권장&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;1.7 기타 운영체제 캐시, Direct I/O 등 주의사항&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;108-113&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;108-110&quot;&gt;Direct I/O 적용 시 OS 캐시를 우회, DB가 자체적으로 페이지 캐시 관리 (Oracle, MySQL 등)
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;109-110&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;110-110&quot;&gt;Double Buffering 방지, RAM 중복 사용 최소화하는 것을 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;108-113&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;111-113&quot;&gt;PostgreSQL은 OS 캐시와 Shared Buffers 모두 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;112-113&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;112-113&quot;&gt;shared_buffers는 15~25%로 제한, 나머지는 OS 페이지 캐시 할당하는 것을 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;2. 애플리케이션 레벨 캐싱&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.1 애플리케이션 레벨 캐시의 필요성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;7-13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;7-9&quot;&gt;DB 캐시 (버퍼 풀, 인메모리 캐시)는 I/O 최적화에 탁월함
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;8-9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;8-8&quot;&gt;디스크 읽기/쓰기 횟수 최소화, 읽기 성능 극대화&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-9&quot;&gt;DB 내부에서만 관리되므로 일관성이 매우 강력 (변경 즉시 반영, 캐시 미스 = DB 최신)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;7-13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;10-13&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;하지만 DB 캐시도 한계가 있음&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;11-13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;11-11&quot;&gt;대용량 JOIN, 정렬, 윈도우 함수, JSON/ARRAY 처리, Recursive 쿼리 등 메모리/CPU 집약 연산은 DB 캐시만으로 커버 불가&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-13&quot;&gt;실행계획이 아무리 최적이어도 대량 데이터/연산은 느릴 수밖에 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;18-20&quot;&gt;애플리케이션 레벨 캐시는 복잡한 다중 JOIN, 집계, 분석 쿼리 결과를 한 번 계산해서 애플리케이션 레벨 (분산 캐시 등)에 저장한 뒤 O(1)로 결과를 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-22&quot;&gt;조회 성능 극대화, DB 부하 감소&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-26&quot;&gt;데이터베이스와 분리된 확장성, 장애 격리, 트래픽 버퍼 역할 수행&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-24&quot;&gt;DB 장애/점검 시에도 읽기만 제공된다면 서비스 연속성 확보 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-24&quot;&gt;i.g. StackOverflow가 DB 정기점검 중에도 캐시 기반 읽기 서비스 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.2 대표적 애플리케이션 레벨 캐시 솔루션&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;31-36&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;31-31&quot;&gt;&lt;b&gt;Redis&lt;/b&gt;: 분산 인메모리 키-값 저장소, 데이터 구조 지원, pub/sub, TTL 등&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;32-32&quot;&gt;&lt;b&gt;Memcached&lt;/b&gt;: 단순 분산 메모리 캐시, 키-값, TTL&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;33-33&quot;&gt;&lt;b&gt;Hazelcast, Ehcache&lt;/b&gt;: JVM 내장/분산 캐시 (자바 친화적)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;34-34&quot;&gt;&lt;b&gt;Aerospike, Etcd&lt;/b&gt;: 분산 캐시/NoSQL DB, 고가용성/확장성&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;35-36&quot;&gt;&lt;b&gt;Kafka, Debezium 등&lt;/b&gt;: CDC (Change Data Capture) 이벤트 기반 캐시 동기화에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.3 캐싱 계층과 동기화 전략&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DB 캐시: &lt;/b&gt;버퍼 풀/OS 캐시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;애플리케이션 캐시: &lt;/b&gt;분산 캐시 i.g. Redis/Memcached&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ORM 2차 캐시: &lt;/b&gt;Hibernate, JPA 2nd-level cache&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1차 캐시: &lt;/b&gt;Persistence Context, 세션 단위&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;48-50&quot;&gt;&lt;b&gt;Cache-aside (Write/Read-through/Write-behind 등)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;49-50&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;49-49&quot;&gt;애플리케이션이 DB와 캐시를 모두 직접 갱신&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;50-50&quot;&gt;캐시 미스시 DB에서 읽고, 수정/삭제시 캐시 무효화 또는 비동기 업데이트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;50-50&quot;&gt;&lt;b&gt;Change Data Capture (CDC)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;52-54&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;52-52&quot;&gt;트리거나 Redo Log, Binlog, WAL 등 DB 변경 이벤트를 추출하여 캐시 동기화&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;53-54&quot;&gt;대표적인 오픈소스는 Debezium (다수 DB 지원)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;1045&quot; data-origin-height=&quot;461&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7Oq9H/btsOusO5BLu/AEqEkeapLXKvsdrAjDNfh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7Oq9H/btsOusO5BLu/AEqEkeapLXKvsdrAjDNfh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7Oq9H/btsOusO5BLu/AEqEkeapLXKvsdrAjDNfh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7Oq9H%2FbtsOusO5BLu%2FAEqEkeapLXKvsdrAjDNfh1%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;1045&quot; height=&quot;461&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;461&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;2.4 캐시 동기화 어려움과 일관성 이슈&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;59-70&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;59-60&quot;&gt;&lt;b&gt;DB가 단일 진실의 원본(Single Source of Truth): &lt;/b&gt;캐시와 DB가 반드시 일관되게 동기화되어야 함&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;61-62&quot;&gt;&lt;b&gt;XA 트랜잭션 미지원: &lt;/b&gt;분산 캐시는 XA/XID 트랜잭션을 지원하지 않는 것이 일반적이므로 동기화 실패 혹은 롤백 시 데이터 불일치 가능성 높음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;63-70&quot;&gt;동기화를 위해 다음 방식을 채택하는 것을 권장&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;64-70&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;64-66&quot;&gt;&lt;b&gt;Invalidate:&amp;nbsp; &lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;롤백되더라도 캐시 미스만 발생하도록&amp;nbsp;&lt;/span&gt;DB 변경 후 캐시 항목 삭제 (가장 안전하지만 &lt;span style=&quot;color: #ee2323;&quot;&gt;캐시를 자주 무효화하기 때문에 효율은 떨어짐&lt;/span&gt;)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;67-70&quot;&gt;&lt;b&gt;Async Update: &lt;/b&gt;DB 커밋 후 캐시 비동기 업데이트 (성능&amp;uarr;, 일관성&amp;darr;), &lt;span style=&quot;color: #ee2323;&quot;&gt;여러 트랜잭션이 짧은 시간에 구버전 캐시 데이터를 읽을 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.5 CDC (Change Data Capture)와 트리거/로그 활용&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; background-color: #ffffff; color: #232425; text-align: left;&quot; data-source-line=&quot;76-83&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;76-79&quot;&gt;&lt;b&gt;트리거 기반 감사 로그 테이블&lt;/b&gt;: INSERT/UPDATE/DELETE 시 트리거로 감사 로그에 기록하고 해당&amp;nbsp;로그를 기반으로 캐시 업데이트
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;77-79&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;79-79&quot;&gt;i.g. book_audit_log 테이블에 old/new row, DML 유형, 타임스탬프 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: left;&quot; data-source-line=&quot;76-83&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;80-83&quot;&gt;&lt;b&gt;Redo log/Binlog/WAL 기반 CDC&lt;/b&gt;: DB 트랜잭션의 커밋된 변경을 로그에서 추출 (비동기)
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;81-83&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;82-83&quot;&gt;Debezium, Kafka 등으로 실시간 이벤트 스트림 생성, 캐시 동기화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;2.6 대규모/대용량 데이터 캐시 관리의 어려움&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;계층적 (aggregate) 데이터 전체를 캐시에 저장할 경우 부모 엔티티 (i.g. 회사명, 태그명 등) 변경 시, 모든 관련 캐시 데이터를 일일이 업데이트/무효화해야 함 (갱신 ripple effect)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;91-92&quot;&gt;캐시 설계상 aggregate를 분해하여, 각 주요 파트 (게시물, 태그, 투표 등)를 키 단위로 별도로 캐싱하면 ripple effect를 완화할 수 있지만 키 수가 많아지고, 여러 번의 조회 및 저장이 필요함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.7 실무 적용 팁&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;99-108&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;99-100&quot;&gt;읽기 부하가 크거나, DB 장애 시 가용성 보장이 필요하다면 반드시 애플리케이션 레벨 캐시 (분산 인메모리 캐시) 적극 도입하는 것을 권장&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;101-102&quot;&gt;캐시 동기화는 비즈니스 상황에 맞게 적용 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;102-102&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;102-102&quot;&gt;동기(Invalidate), 비동기(CDC, 이벤트), TTL, 버전 관리 등 상황별로 조합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;99-108&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;103-103&quot;&gt;캐시 일관성과 효율성 트레이드오프를 항상 인지하고 설계해야 함&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;104-105&quot;&gt;CDC (Debezium 등) 활용 시 DB 트랜잭션과 캐시 동기화 파이프라인의 장애/지연/누락에 주의&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;106-108&quot;&gt;대규모 aggregate 캐시 설계 시 ripple effect를 고려해 분해 캐시, TTL, 대량 무효화 전략 등 다각적으로 대비하는 것을 권장&lt;/li&gt;
&lt;/ul&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;b&gt;3. Hibernate 2차 캐시&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.1 Hibernate 2차 캐시란?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;7-14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;7-9&quot;&gt;&lt;b&gt;1차 캐시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;8-9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;8-8&quot;&gt;Hibernate의 Persistence Context (Session, EntityManager) 단위&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-9&quot;&gt;트랜잭션/세션 범위 내에서만 엔티티 객체를 메모리에 저장 (즉, DB 한 번만 로드)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;7-14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;10-14&quot;&gt;&lt;b&gt;2차 캐시 (Second-level Cache)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;11-14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;11-11&quot;&gt;애플리케이션 전체 또는 EntityManagerFactory/SessionFactory 단위의 공유 캐시&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-12&quot;&gt;같은 엔티티 (또는 컬렉션, 쿼리 결과 등)를 여러 세션/트랜잭션에서 재사용 가능&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;13-14&quot;&gt;DB 접근 (읽기/쓰기) 부하를 효과적으로 감소시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.2 2차 캐시의 필요성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;20-21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;20-20&quot;&gt;Primary/Replica 구조에서 읽기 트래픽 (scale-out)은 Replica 노드 추가로 쉽게 확장 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;21-21&quot;&gt;쓰기 트래픽 (scale-up)은 Primary 노드 한 대에 집중하기 때문에 수직 확장 (scale-up)만 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;19-25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-25&quot;&gt;쓰기 부하를 분산하거나, Primary 부하를 줄이기 위해서는
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;23-25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-23&quot;&gt;Hibernate 2차 캐시를 활용하여 읽기 요청의 일부를 DB가 아닌 캐시에서 처리&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;24-25&quot;&gt;읽기-쓰기 트랜잭션에서 읽기 부하의 상당 부분을 캐시에 오프로딩&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.3 2차 캐시의 종류 및 옵션&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;30-34&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;30-30&quot;&gt;&lt;b&gt;Entity Cache&lt;/b&gt;: 엔티티 단위 캐싱&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;31-31&quot;&gt;&lt;b&gt;Collection Cache&lt;/b&gt;: 컬렉션 (List/Set) 관계 식별자 캐싱&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;32-32&quot;&gt;&lt;b&gt;Query Cache&lt;/b&gt;: 쿼리 결과 (식별자/프로젝션) 캐싱&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;33-34&quot;&gt;&lt;b&gt;Natural Id Cache&lt;/b&gt;: 비즈니스 키 기반 엔티티 식별자 캐싱&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.4 2차 캐시 동작 순서&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;엔티티 조회 시 1차 캐시 (Persistence Context) &amp;rarr; 2차 캐시 &amp;rarr; DB 쿼리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;43-44&quot;&gt;2차 캐시에 없는 경우, DB에서 로드 후 2차 캐시에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가. 1차 캐시 (PersistenceContext, Session/EntityManager)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;12-18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-12&quot;&gt;영속성 컨텍스트는 현재 트랜잭션/세션 범위 내에서만 유효한 엔티티 캐시&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;13-13&quot;&gt;JPA의&lt;span&gt;&amp;nbsp;&lt;/span&gt;EntityManager와 Hibernate의&lt;span&gt;&amp;nbsp;&lt;/span&gt;Session이 1차 캐시 역할을 수행&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;14-14&quot;&gt;엔티티를 조회하면 가장 먼저 1차 캐시에서 해당 엔티티의 인스턴스를 찾음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;15-18&quot;&gt;1차 캐시에 이미 관리되고 있는 엔티티가 있다면, 별도의 DB 쿼리나 2차 캐시 접근 없이 즉시 반환됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;15-18&quot;&gt;동일 트랜잭션/세션에서 여러 번 조회해도 DB 쿼리는 1번만 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. 2차 캐시(Second-Level Cache)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;20-26&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;20-20&quot;&gt;1차 캐시에 엔티티가 없고 2차 캐시가 활성화된 경우, 2차 캐시에서 해당 엔티티를 찾음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-22&quot;&gt;2차 캐시는 SessionFactory/EntityManagerFactory 단위로 여러 세션/트랜잭션에서 공유됨&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-24&quot;&gt;2차 캐시에서 엔티티를 찾으면(캐시 히트), DB 접근 없이 캐시 된 &amp;lsquo;로드 상태&amp;rsquo;로 엔티티를 복원해서 반환&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-26&quot;&gt;2차 캐시에 엔티티가 없다면(캐시 미스), 다음 단계로 넘어감&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다. DB 쿼리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;28-33&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;28-28&quot;&gt;1차/2차 캐시 모두에 엔티티가 없다면, Hibernate가 실제로 DB에 SELECT 쿼리를 실행하여 엔티티 데이터를 조회&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;30-33&quot;&gt;DB에서 엔티티를 가져온 뒤 1차 캐시에 엔티티를 등록하고 2차 캐시가 활성화되어 있다면, 엔티티의 &amp;lsquo;로드 상태&amp;rsquo;를 2차 캐시에 저장 (다음 세션/트랜잭션에서 재사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.5 Hibernate 2차 캐시 설정 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/938ae9cb957acb079b3fb0af267898c8.js&quot;&gt;&lt;/script&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.6 쿼리 캐시 설정 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/f956f730bf298b84cdce15697727ed9f.js&quot;&gt;&lt;/script&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.7 Natural Id (비즈니스 키) 캐시&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;105-108&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;105-105&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;Natural Id (비즈니스 키)는 데이터베이스에서 엔티티를 고유하게 식별할 수 있는 속성으로, &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;보통 비즈니스적으로도 유일성이 보장되는 값&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;105-105&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;Primary Key와는 별도로, &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;비즈니스 로직에서 자주 사용하는 자연키 기반 조회가 필요할 때가 많음&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;105-105&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;i.g. 책 테이블의 ISBN, 상품의 SKU 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;@NaturalId + @NaturalIdCache를 통해&amp;nbsp;비즈니스 키 기반 엔티티 캐싱
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;106-106&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;Hibernate API를 사용하면 Natural Id로 엔티티를 직접 조회 가능&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;106-106&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;DB round-trip을 최소화하여 매우 빠름&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;108-109&quot;&gt;엔티티가 수정/삭제/추가되면 자연키 캐시와 엔티티 캐시가 함께 무효화되어 최신 상태 유지&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;56-57&quot;&gt;JPA 표준에는 없고 Hibernate 고유 API&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;56-57&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단, &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;변경이 자주 발생하면 캐시 무효화와 동기화 비용이 증가하므로 Natural Id 값은 실제로는 거의 변하지 않아야 함&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;120-122&quot;&gt;&lt;b&gt;또한, 캐시 제공자 (RegionFactory)에 따라 설정과 성능이 달라질 수 있으므로 운영 환경에서 캐시 동작/효율을 반드시 모니터링 필요&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/4fd978cc22a5a9c8ecac8a23c5062f40.js&quot;&gt;&lt;/script&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;63-63&quot;&gt;slug 값으로 Natural Id 쿼리를 실행하면&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;64-64&quot;&gt;Hibernate는 먼저&lt;span&gt;&amp;nbsp;&lt;/span&gt;Natural Id 캐시에서 해당 slug &amp;rarr; id 매핑을 찾음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;65-65&quot;&gt;없으면 DB에서 SELECT id FROM post WHERE slug = 'slug' 실행 후 결과를 캐시에 저장&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;66-66&quot;&gt;id 값을 찾으면, 곧바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;엔티티 캐시 (2차 캐시)에서 id로 엔티티를 찾음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;67-68&quot;&gt;엔티티 캐시에도 없으면 DB에서 SELECT * FROM post WHERE id = ? 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;4. Hibernate 2차 캐시 동시성 전략&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hibernate 2차 캐시는 데이터 일관성과 동시성 요구에 따라 네 가지 캐시 동시성 전략을 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-9&quot;&gt;&lt;b&gt;READ_ONLY&lt;/b&gt;: 읽기 전용/불변 데이터에 적합 (immutable)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;10-10&quot;&gt;&lt;b&gt;NONSTRICT_READ_WRITE&lt;/b&gt;: 데이터 변경이 드물고, 약간의 일관성 손실을 허용할 수 있을 때 채택하는 전략&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;11-11&quot;&gt;&lt;b&gt;READ_WRITE&lt;/b&gt;: 강력한 일관성이 필요할 때 적용 (동시성 제어, 소프트락 사용)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;12-13&quot;&gt;&lt;b&gt;TRANSACTIONAL&lt;/b&gt;: JTA 트랜잭션 환경, XA 트랜잭션에 참여하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;가. READ_ONLY 전략&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;18-28&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;18-19&quot;&gt;변경 불가 능(immutable)한 엔티티 및 컬렉션 캐시에만 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;18-19&quot;&gt;i.g. 코드 테이블, 읽기 전용 참조 데이터)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;18-28&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;20-23&quot;&gt;해당 전략의 특징은 다음과 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;21-23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;21-21&quot;&gt;불변 엔티티/컬렉션에만 설정 가능 (@Immutable 강제)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-22&quot;&gt;캐시 동기화 필요 없음, 캐시에 저장된 값이 영원히 유효&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-23&quot;&gt;모든 CRUD 작업에서 데이터베이스-캐시 일관성 유지가 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 전략 채택 시 다음과 같이 동작&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;persist 시 write-through로 캐시에 저장&lt;/li&gt;
&lt;li&gt;읽기 시 캐시 hit/miss 카운트로 통계 확인 가능&lt;/li&gt;
&lt;li&gt;업데이트/삭제 시 예외 발생 또는 무시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;나. NONSTRICT_READ_WRITE 전략&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;33-43&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;33-33&quot;&gt;데이터 변경이 드물고, 복제된 환경이나 분산 캐시에서 '최종적 일관성 (eventual consistency)'만 보장해도 되는 경우 적용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;42-43&quot;&gt;변경이 자주 일어나지 않는 데이터, 완벽한 일관성이 필요 없는 환경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;33-43&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;34-37&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;해당 전략의 특징은 다음과 같음&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;35-37&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;35-35&quot;&gt;업데이트/삭제 시 캐시에 있는 항목 무효화&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;36-36&quot;&gt;캐시 무효화와 DB 업데이트 사이에 시간 차이 발생 가능 &lt;span style=&quot;color: #ee2323;&quot;&gt;(동시성 문제 가능성)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;37-37&quot;&gt;분산 환경 (여러 웹 노드, 복제본 등)에서 락 없이 작동 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;33-43&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;38-40&quot;&gt;해당 전략 채택 시 다음과 같이 동작&amp;nbsp;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;39-40&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;39-39&quot;&gt;persist 시에는 캐시에 저장되지 않음, 최초 조회 시에만 캐시 저장 (read-through)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;40-40&quot;&gt;업데이트/삭제 시 캐시 즉시 무효화, 이후 최초 조회 시에 다시 캐시 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;다. READ_WRITE 전략&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;48-60&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;48-48&quot;&gt;데이터 일관성이 매우 중요한 환경에서 적용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;48-48&quot;&gt;i.g. OLTP, 단일 노드/인스턴스와 같이 강력한 동시성 보장 필요한 환경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;48-60&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;49-52&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;해당 전략의 특징은 다음과 같음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;50-52&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;50-50&quot;&gt;캐시에 소프트락 객체를 사용, 트랜잭션 커밋 시까지 락 보유&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;51-51&quot;&gt;동시 수정 충돌 방지, 커밋 전까지 다른 트랜잭션이 캐시 된 값을 볼 수 없음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;52-52&quot;&gt;강력한 일관성 보장, 단일 노드 (혹은 분산 캐시에서 락 동기화 지원) 환경에서 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;48-60&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;53-56&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;해당 전략 채택 시 다음과 같이 동작&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;54-56&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;54-54&quot;&gt;persist/update/delete 시 캐시와 DB 모두 write-through&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;55-55&quot;&gt;update/delete 시 캐시에 소프트락이 생성, 커밋 후에만 실제 값으로 대체&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;56-56&quot;&gt;다른 트랜잭션이 락 상태를 만나면 DB에서 직접 로드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;라. TRANSACTIONAL 전략&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;65-72&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;65-65&quot;&gt;XA 트랜잭션 (JTA) 환경, 다수의 DB/캐시 시스템이 2단계 커밋(two-phase commit)에 참여할 때 적용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;70-70&quot;&gt;@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) 어노테이션 지정 필요&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;71-72&quot;&gt;XA 지원 DataSource, 트랜잭션 매니저, 캐시 프로바이더 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;65-72&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;66-68&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;해당 전략의 특징은 다음과 같음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;67-68&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;67-67&quot;&gt;JTA/XA 트랜잭션 매니저 필요 (Bitronix, Atomikos, Java EE JTA 등)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;68-68&quot;&gt;캐시와 데이터베이스 커밋/롤백이 완전히 동기화됨 (모두 성공/모두 실패)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4.1 실무 적용 팁&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;98-104&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;98-100&quot;&gt;쿼리 캐시는 별도 활성화 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;99-100&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;99-99&quot;&gt;쿼리 실행 결과 (식별자/프로젝션)만 캐시&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;100-100&quot;&gt;파라미터, 쿼리 문자열, 필터 등 모두가 캐시 키에 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;98-104&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;101-104&quot;&gt;엔티티/컬렉션이 변경되면 관련 쿼리 캐시도 무효화하는 것을 권장
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;102-104&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;30-32&quot;&gt;쿼리 캐시가 조회될 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;결과에 저장된 타임스탬프 &amp;lt; 현재 테이블 타임스탬프&lt;/b&gt;이면 해당 쿼리 결과가 더 이상 유효하지 않은 것으로 간주하고 무효화&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;45-48&quot;&gt;Native SQL을 사용할 때는 .addSynchronizedEntityClass(Entity.class) 또는 &lt;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;.addSynchronizedQuerySpace(&quot;table_name&quot;) &lt;/span&gt;메서드로 해당 쿼리가 어느 테이블/엔티티에 영향을 미치는지 Hibernate에 명시적으로 알려줌
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;49-51&quot;&gt;이렇게 적용하면 정확히 관련된 쿼리 캐시만 무효화되어, 나머지 쿼리 캐시는 계속 재사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/ed6621b7334d15acee206052fc689767.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;77-93&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;90-93&quot;&gt;컬렉션 캐시는 항상 read-through
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;91-93&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;91-91&quot;&gt;컬렉션은 데이터베이스에서 처음 읽을 때만 캐시에 저장&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;92-93&quot;&gt;자식 엔티티들도 반드시 캐시 되어야 N + 1 문제 회피&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프런 - &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;고성능 JPA &amp;amp; Hibernate (High-Performance Java Persistence)&lt;/span&gt;&lt;/p&gt;</description>
      <category>DB/JPA</category>
      <category>Hibernate</category>
      <category>JPA</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2724</guid>
      <comments>https://jaimemin.tistory.com/2724#entry2724comment</comments>
      <pubDate>Wed, 11 Jun 2025 14:39:03 +0900</pubDate>
    </item>
    <item>
      <title>[Hibernate/JPA] 트랜잭션과 동시성 제어 패턴</title>
      <link>https://jaimemin.tistory.com/2723</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&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;span style=&quot;color: #ee2323;&quot;&gt;동시성 결함이나 트랜잭션 제어 미비로 인해 막대한 금액의 해킹 피해&lt;/span&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;span style=&quot;background-color: #ffffff; color: #232425; text-align: left;&quot;&gt;i.g. FlexCoin, Poloniex 해킹 사례&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-9&quot;&gt;여러 건의 출금을 거의 동시에 요청 &amp;rarr; 음수 잔고 허용, 데이터베이스에 잘못된 레코드가 삽입되었고 이로 인해 시스템 무결성이 깨지고 공격자는 훨씬 더 많은 금액을 탈취함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;49-49&quot;&gt;구글 Spanner 등 신세대 DBMS조차&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;트랜잭션을 포기하는 것보다, 필요할 때 성능 병목을 해결하는 것이 현명하다&quot;라고&lt;/a&gt; 명시&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;50-50&quot;&gt;MongoDB 등도 결국 ACID 보장 기능을 추가 (4.0+ 버전부터 적용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;1. ACID와 트랜잭션 동시성 제어&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 DB 작업은 트랜잭션 내에서 진행됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;8-8&quot;&gt;&lt;b&gt;Auto-commit 모드:&lt;/b&gt; Statement마다 암묵적으로 트랜잭션 시작/커밋&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-10&quot;&gt;&lt;b&gt;명시적 트랜잭션:&lt;/b&gt; BEGIN~COMMIT/ROLLBACK으로 여러 Statement를 하나의 작업 단위로 묶음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.1 ACID 네 가지 속성&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;가. Atomicity (원자성)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;16-18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;16-16&quot;&gt;트랜잭션 내 모든 작업이 전부 성공하거나 전부 실패 (rollback)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;17-18&quot;&gt;실패 시 중간 변경은 모두 이전 상태로 복원 (undo log 등 활용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. Consistency (일관성)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;20-22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;20-20&quot;&gt;트랜잭션 전후로 데이터가 항상 유효한 상태 (모든 제약조건, 무결성 규칙 준수)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;21-22&quot;&gt;하나라도 위반되면 전체 트랜잭션 롤백&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다. Isolation (격리성)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;24-26&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;24-24&quot;&gt;여러 트랜잭션이 동시에 실행되어도, 각각은 다른 트랜잭션의 중간 상태를 볼 수 없음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-26&quot;&gt;Serializable이 가장 높은 격리 수준 (완전 직렬 실행과 동등)이지만 성능 저하 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라. Durability (내구성)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;28-30&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;28-28&quot;&gt;커밋된 트랜잭션의 결과는 서버 다운, 장애 후에도 항상 보존됨&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;29-30&quot;&gt;Redo log, Write-Ahead Log(WAL), 트랜잭션 로그 등 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.2 DBMS별 ACID 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;Atomicity와 Rollback&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;46-52&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;46-47&quot;&gt;모든 변경은 실제 데이터 구조(테이블, 인덱스 등)에 적용되지만, 커밋 전에는 언제든지 undo log 등으로 이전 상태로 롤백 가능해야 함.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;48-48&quot;&gt;&lt;b&gt;Oracle&lt;/b&gt;: undo tablespace에서 이전 데이터 버전을 관리&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;49-49&quot;&gt;&lt;b&gt;SQL Server&lt;/b&gt;: 트랜잭션 로그에 undo/redo 정보 모두 기록&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;50-50&quot;&gt;&lt;b&gt;PostgreSQL&lt;/b&gt;: 데이터 자체에 다중 버전 (MVCC)으로 이전 상태를 보관, VACUUM으로 공간 회수&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;51-52&quot;&gt;&lt;b&gt;MySQL(InnoDB)&lt;/b&gt;: undo 로그와 purge 프로세스로 이전 상태 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. Durability&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;64-69&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;64-64&quot;&gt;커밋 시점에 모든 변경이 Redo Log, WAL 등에 안전하게 기록되어야 함&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;65-65&quot;&gt;&lt;b&gt;Oracle&lt;/b&gt;: Redo 로그 버퍼를 Log Writer가 디스크로 flush&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;66-66&quot;&gt;&lt;b&gt;SQL Server&lt;/b&gt;: 트랜잭션 로그를 commit마다 디스크로 flush (2014+ 버전은 configurable durability)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;67-67&quot;&gt;&lt;b&gt;PostgreSQL&lt;/b&gt;: WAL을 commit마다 flush (비동기 가능)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;68-69&quot;&gt;&lt;b&gt;MySQL&lt;/b&gt;: Redo 로그 (innodb_flush_log_at_trx_commit=1이 권장)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다. Consistency&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: left;&quot; data-source-line=&quot;56-57&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;56-56&quot;&gt;모든 트랜잭션은 데이터베이스의 모든 제약조건을 만족시켜야 함&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;57-57&quot;&gt;하나라도 위반 시 전체 롤백, DB는 항상 유효한 상태 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라. Isolation&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;1.4에서 후술 할 내용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.3 Consistency의 두 의미&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;44-49&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;44-46&quot;&gt;&lt;b&gt;ACID에서의 Consistency (무결성)&lt;/b&gt;: 타입, 길이, null, unique, FK 등 제약조건 위반 없이 항상 유효한 DB 상태 유지&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;47-49&quot;&gt;&lt;b&gt;CAP 정리에서의 Consistency (선형화 가능성)&lt;/b&gt;: 분산 시스템에서 &quot;모든 노드가 같은 값을 본다&quot;는 의미
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;47-49&quot;&gt;ACID의 일관성과 다름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.4 표준 격리 수준 (Isolation) 및 DBMS별 격리 수준&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;가. SQL-92 표준 격리 수준&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;55-58&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;55-55&quot;&gt;&lt;b&gt;Read Uncommitted:&lt;/b&gt; Dirty Read, Non-Repeatable Read, Phantom Read 모두 허용&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;56-56&quot;&gt;&lt;b&gt;Read Committed:&lt;/b&gt; Dirty Read 금지, Non-Repeatable/Phantom Read 허용&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;57-57&quot;&gt;&lt;b&gt;Repeatable Read:&lt;/b&gt; Dirty/Non-Repeatable Read 금지, Phantom Read 허용&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;58-58&quot;&gt;&lt;b&gt;Serializable:&lt;/b&gt; 모든 현상 금지 (완전 직렬화 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. 각 DBMS별 격리 수준&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;60-64&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;60-60&quot;&gt;&lt;b&gt;Oracle:&lt;/b&gt; Read Committed, Serializable만 제공 (Snapshot Isolation 기반)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;61-61&quot;&gt;&lt;b&gt;SQL Server:&lt;/b&gt; 2PL 기본, Snapshot Isolation은 별도 설정 필요&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;62-62&quot;&gt;&lt;b&gt;PostgreSQL:&lt;/b&gt; 기본적으로 MVCC, Repeatable Read=Snapshot Isolation&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;63-64&quot;&gt;&lt;b&gt;MySQL:&lt;/b&gt; InnoDB는 기본 Repeatable Read (MVCC), Serializable은 락 기반&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.5 동시성 제어 방식&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;가. 2PL (Two-Phase Locking)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;70-71&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;70-70&quot;&gt;모든 트랜잭션이 확장 단계 (락 획득), 수축 단계 (락 해제) 구분&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;71-71&quot;&gt;순수 직렬화 보장, 성능 저하, 데드락 발생 가능&lt;/li&gt;
&lt;/ul&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;나. MVCC (Multi-Version Concurrency Control)&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;73-75&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;73-73&quot;&gt;읽기/쓰기 간 락 최소화, 트랜잭션별 snapshot/버전 활용&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;74-75&quot;&gt;writer끼리만 충돌, reader-writer/reader-reader는 충돌 없음&lt;/li&gt;
&lt;/ul&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;700&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4fMqk/btsOueu9hMY/yHPkgh9zC3JyPvCJaoJmo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4fMqk/btsOueu9hMY/yHPkgh9zC3JyPvCJaoJmo1/img.png&quot; data-alt=&quot;https://blog.stackademic.com/understanding-concurrency-control-2pl-vs-mvcc-in-database-systems-2e8af23f1668&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4fMqk/btsOueu9hMY/yHPkgh9zC3JyPvCJaoJmo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4fMqk%2FbtsOueu9hMY%2FyHPkgh9zC3JyPvCJaoJmo1%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;700&quot; height=&quot;449&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://blog.stackademic.com/understanding-concurrency-control-2pl-vs-mvcc-in-database-systems-2e8af23f1668&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.6 동시성 현상 (Phenomena)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;80-85&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;80-80&quot;&gt;&lt;b&gt;Dirty Write&lt;/b&gt;: 커밋 전 데이터가 다른 트랜잭션에 의해 덮어써짐&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;81-81&quot;&gt;&lt;b&gt;Dirty Read&lt;/b&gt;: 커밋되지 않은 데이터를 읽음&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;82-82&quot;&gt;&lt;b&gt;Non-Repeatable Read&lt;/b&gt;: 같은 레코드 두 번 읽었을 때 값이 다름&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;83-83&quot;&gt;&lt;b&gt;Phantom Read&lt;/b&gt;: WHERE 조건에 부합하는 레코드의 수가 트랜잭션 중간에 달라짐&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;84-85&quot;&gt;&lt;b&gt;Read Skew/Write Skew/Lost Update&lt;/b&gt;: MVCC에서만 발생, 여러 행/테이블의 변경이 동기화되지 않음&lt;/li&gt;
&lt;/ul&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://jaimemin.tistory.com/2694&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jaimemin.tistory.com/2694&lt;/a&gt;&amp;nbsp;참고&lt;/p&gt;
&lt;figure id=&quot;og_1749454906304&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[RDBMS] 트랜잭션&quot; data-og-description=&quot;1. 트랜잭션 개요트랜잭션은 데이터베이스에서 원자적 (Atomic)이고, 일관적 (Consistent)이며, 격리 (Isolated)되고, 영속적 (Durable)인 작업 단위실무에서는 동시 사용자 요청, 서버 장애, 네트워크 오류 &quot; data-og-host=&quot;jaimemin.tistory.com&quot; data-og-source-url=&quot;https://jaimemin.tistory.com/2694&quot; data-og-url=&quot;https://jaimemin.tistory.com/2694&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b00cDm/hyY4dsNvfS/CO0ekjYl6kZMrPNsvOH2Sk/img.png?width=800&amp;amp;height=461&amp;amp;face=0_0_800_461,https://scrap.kakaocdn.net/dn/TNIxw/hyY77dloLM/KjF7f1fdme3HpWzfubFCpk/img.png?width=800&amp;amp;height=461&amp;amp;face=0_0_800_461,https://scrap.kakaocdn.net/dn/3KJOy/hyY5aiaFgQ/bUK7jrocrNtavcLxWFKBuK/img.png?width=1604&amp;amp;height=510&amp;amp;face=0_0_1604_510&quot;&gt;&lt;a href=&quot;https://jaimemin.tistory.com/2694&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jaimemin.tistory.com/2694&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b00cDm/hyY4dsNvfS/CO0ekjYl6kZMrPNsvOH2Sk/img.png?width=800&amp;amp;height=461&amp;amp;face=0_0_800_461,https://scrap.kakaocdn.net/dn/TNIxw/hyY77dloLM/KjF7f1fdme3HpWzfubFCpk/img.png?width=800&amp;amp;height=461&amp;amp;face=0_0_800_461,https://scrap.kakaocdn.net/dn/3KJOy/hyY5aiaFgQ/bUK7jrocrNtavcLxWFKBuK/img.png?width=1604&amp;amp;height=510&amp;amp;face=0_0_1604_510');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[RDBMS] 트랜잭션&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. 트랜잭션 개요트랜잭션은 데이터베이스에서 원자적 (Atomic)이고, 일관적 (Consistent)이며, 격리 (Isolated)되고, 영속적 (Durable)인 작업 단위실무에서는 동시 사용자 요청, 서버 장애, 네트워크 오류&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jaimemin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;b&gt;2. 비관적 (Pessimistic) Locking&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.1 Locking의 종유와 개념&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;가. 비관적 락 (Pessimistic Lock)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;8-11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;8-8&quot;&gt;물리적 락&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;8-8&quot;&gt;실제 DB의 행(row), 페이지, 테이블 등 데이터에 대해 락을 걸어 동시성 충돌을 방지&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;9-9&quot;&gt;트랜잭션 격리 수준에 따라 자동 발생&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;10-11&quot;&gt;&lt;b&gt;명시적으로 사용하는 방법&lt;/b&gt;: 쿼리에서 직접 FOR UPDATE, FOR SHARE 등으로 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. 낙관적 락 (Optimistic Lock)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;13-16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;13-13&quot;&gt;논리적 락&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;13-13&quot;&gt;실제 DB 락을 쓰지 않고, 버전 (@Version 필드)이나 타임스탬프 등으로 충돌 감지&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;14-14&quot;&gt;@Version 등 기본기능으로 제공&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;15-16&quot;&gt;&lt;b&gt;명시적으로 사용하는 방법&lt;/b&gt;: LockModeType.OPTIMISTIC_FORCE_INCREMENT 등 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.2 DBMS별 명시적 락 SQL&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;가. 공유 락 (Shared/Read)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;22-27&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-22&quot;&gt;&lt;b&gt;Oracle:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;FOR UPDATE&lt;span&gt;&amp;nbsp;&lt;/span&gt;(실제로는 배타적 락만 지원)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-23&quot;&gt;&lt;b&gt;MySQL:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;LOCK IN SHARE MODE&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;24-24&quot;&gt;&lt;b&gt;SQL Server:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;WITH (HOLDLOCK, ROWLOCK)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-25&quot;&gt;&lt;b&gt;PostgreSQL:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;FOR SHARE&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;26-27&quot;&gt;&lt;b&gt;DB2:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;FOR READ ONLY WITH RS&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/e977d4cb7a5752dbd5bbaf0f545b4ccf.js&quot;&gt;&lt;/script&gt;
&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. 배타적 락 (Exclusive/Write)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;29-31&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;29-29&quot;&gt;&lt;b&gt;Oracle/MySQL/PostgreSQL/DB2:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;FOR UPDATE&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;30-31&quot;&gt;&lt;b&gt;SQL Server:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;WITH (UPDLOCK, HOLDLOCK, ROWLOCK)&lt;/li&gt;
&lt;/ul&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;script src=&quot;https://gist.github.com/jaimemin/42adbb1c7a87d00da9483f730e223b17.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.3 Hibernate/JPA 락 모드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;36-42&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;36-36&quot;&gt;&lt;b&gt;NONE&lt;/b&gt;: 락 없음 (default 값)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;37-37&quot;&gt;&lt;b&gt;OPTIMISTIC/READ&lt;/b&gt;: 버전 체크, 낙관적&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;38-38&quot;&gt;&lt;b&gt;OPTIMISTIC_FORCE_INCREMENT/WRITE&lt;/b&gt;: 버전 증가 + 체크&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;39-39&quot;&gt;&lt;b&gt;PESSIMISTIC_READ&lt;/b&gt;: 공유 락 (다른 트랜잭션의 배타적 락, 쓰기 막음)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;40-40&quot;&gt;&lt;b&gt;PESSIMISTIC_WRITE&lt;/b&gt;: 배타적 락 (다른 모든 읽기/쓰기 막음)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;41-42&quot;&gt;&lt;b&gt;PESSIMISTIC_FORCE_INCREMENT&lt;/b&gt;: 배타적 락 + 버전 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/9133341611ce49f447c34a2fd971caf5.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.4 Predicate Locking과 Table Locking&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;가. Predicate Locking&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;61-61&quot;&gt;MySQL(REPEATABLE READ), SQL Server, PostgreSQL 등 일부 DB에서 지원&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;62-62&quot;&gt;MySQL은 REPEATABLE READ에서 갭 락 (Gap Lock)까지 적용, INSERT 차단 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. Table Locking&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;일부 DB (Oracle 등)에서 predicate lock 미지원 시 전체 테이블 락
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;64-65&quot;&gt;i.g. LOCK TABLE ... IN SHARE MODE&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.5 FOR UPDATE (NO WAIT/SKIP LOCKED)&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;가. NO WAIT&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;82-85&quot;&gt;락 이미 잡혀 있으면 즉시 예외 발생 (대기하지 않음)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;83-83&quot;&gt;&lt;b&gt;지원하는 DB:&lt;/b&gt; Oracle, PostgreSQL, SQL Server, MySQL(8.0+)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;84-85&quot;&gt;&lt;b&gt;Hibernate/JPA:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;setLockTimeout(LockOptions.NO_WAIT)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. SKIP LOCKED&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;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;87-87&quot;&gt;&lt;b&gt;지원하는 DB:&lt;/b&gt; Oracle, PostgreSQL, SQL Server, MySQL(8.0+)&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;88-89&quot;&gt;&lt;b&gt;사용 예시:&lt;/b&gt; 여러 워커가 동시에 작업 큐에서 할당받을 때 프로세스/쓰레드 충돌 없이 동시에 안전하게 작업을 분배할 수 있음&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;35-35&quot;&gt;현재 트랜잭션에서 아직 락이 걸리지 않은 (=다른 워커가 처리 중이 아닌) 행만 읽어서 락을 획득&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;36-36&quot;&gt;이미 다른 워커가 락을 잡은 행은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;건너뛰고&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;다음 행을 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/34c44b8d28bf9383623263ec002ad37f.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.6 PostgreSQL Advisory Lock&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 style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;105-107&quot;&gt;세션/트랜잭션 단위의 임의 key 기반 소프트 락
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;106-107&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;106-106&quot;&gt;실제 행/테이블과 무관, 애플리케이션 레벨의 동시성 제어&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;107-107&quot;&gt;i.g. 특정 리소스별로 임계구역 동기화, 분산 환경에서 다중 노드 동기화 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/5d57a133e221f8d6da3f4b047f2d4870.js&quot;&gt;&lt;/script&gt;
&lt;/p&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;b&gt;3. 낙관적 (Optimistic) Locking&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.1 낙관적 Locking 원리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;7-16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;7-9&quot;&gt;실제 데이터베이스 락을 잡지 않고, 엔티티에 버전 혹은 타임스탬프 컬럼을 사용하여 동시성 충돌을 감지하는 방식&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;10-13&quot;&gt;@Version&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드를 활용하면, 엔티티를 읽을 때 버전값을 함께 읽고, UPDATE/DELETE 시점에 WHERE 절에 버전값까지 명시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;10-13&quot;&gt;&quot;id=... AND version=...&quot; 조건&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;7-16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;14-16&quot;&gt;누군가 이미 버전을 변경했다면, 해당 쿼리는 업데이트되지 않고 애플리케이션에서는 OptimisticLockException 예외가 발생함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/jaimemin/d69181a81754d9938746c920bc91b5da.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.2 @Version vs Timestamp&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-source-line=&quot;22-23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;22-22&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;DB/시스템 시간 동기화 문제 (동기화, NTP, time zone, leap second 등)로 인해 실무에서는 추천하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;23-23&quot;&gt;각 DBMS별로 정밀도/동작 차이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나. int/short 기반 버전 필드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-source-line=&quot;25-29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;25-25&quot;&gt;&lt;b&gt;대부분의 엔터프라이즈 환경에서 권장하는 방식&lt;/b&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;26-27&quot;&gt;@Version 필드에&lt;span&gt;&amp;nbsp;&lt;/span&gt;int(4바이트) 대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;short(2바이트)도 사용 가능, 대용량 테이블에서 스토리지 절약 효과&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;28-29&quot;&gt;트랜잭션이 짧다면 short도 충분
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;28-29&quot;&gt;하나의 레코드가 64,000번 이상 연속 변경되는 경우는 드묾&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.3 Bulk Update 시 유의사항&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;66-72&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;66-66&quot;&gt;대량 UPDATE/DELETE 쿼리는 WHERE 절에 반드시 버전 조건을 포함하여야 함&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;67-67&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그렇지 않으면 동시성 충돌 (lost update)이 방지되지 않음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1749457869708&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE post SET status=?, version=version+1 WHERE status=? AND version=?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.4 Versionless Optimistic Locking&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;77-81&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;77-81&quot;&gt;&lt;b&gt;Hibernate&lt;/b&gt;는 @Version 필드 없이도 @DynamicUpdate와 @OptimisticLocking(type = DIRTY)로 변경된 컬럼만 WHERE 조건에 포함하여 동시성 제어 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;77-81&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;단, 일반적인 상황에서는 버전 필드를 쓰는 것이 더 명확하고 안전함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3.5 실무 적용 팁 및 한계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #232425; text-align: start;&quot; data-source-line=&quot;99-104&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;99-99&quot;&gt;낙관적 락킹은 단일 트랜잭션 내 Lost Update 방지에는 유용한 방식&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;100-100&quot;&gt;논리적 트랜잭션 (여러 HTTP 요청/폼 제출 등)에도 버전 필드만 잘 사용하면 안전하게 동시성 충돌 감지 가능&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;101-101&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그러나 대량 업데이트/삭제, 복잡한 집계(aggregate) 변경, 버전 컬럼 없는 엔티티 등은 별도 설계 및 조치 필요&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot; data-source-line=&quot;102-104&quot;&gt;Aggregate 내부의 모든 변경을 부모 버전에 반영하려면 Hibernate 커스텀 이벤트 리스너, @OptimisticLocking(type = ALL/Dirty), Force Increment 등 고급 기능을 활용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;참고&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프런 - &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;고성능 JPA &amp;amp; Hibernate (High-Performance Java Persistence)&lt;/span&gt;&lt;/p&gt;</description>
      <category>DB/JPA</category>
      <category>Hibernate</category>
      <category>JPA</category>
      <author>꾸준함.</author>
      <guid isPermaLink="true">https://jaimemin.tistory.com/2723</guid>
      <comments>https://jaimemin.tistory.com/2723#entry2723comment</comments>
      <pubDate>Mon, 9 Jun 2025 17:35:18 +0900</pubDate>
    </item>
  </channel>
</rss>