<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>minOS</title>
    <link>https://onepunchprogram.tistory.com/</link>
    <description> Who r u ? 너 누구야</description>
    <language>ko</language>
    <pubDate>Fri, 21 Aug 2026 14:52:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>minOE</managingEditor>
    <image>
      <title>minOS</title>
      <url>https://tistory1.daumcdn.net/tistory/6741024/attach/e5a64d091c644df88cc47fcb40a76122</url>
      <link>https://onepunchprogram.tistory.com</link>
    </image>
    <item>
      <title>백준 3184 양</title>
      <link>https://onepunchprogram.tistory.com/201</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/3184&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/3184&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;타임라인 &amp;amp; 사고 과정&lt;br /&gt;&lt;br /&gt;&lt;b&gt;7:09 AM &amp;mdash; 초기 아이디어&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;BFS로 먼저 같은 영역을 구한다. 울타리 #를 기준으로 연결된 칸들을 하나의 영역으로 본다. visited 배열로 중복 탐색을 막는다. 영역을 구한 뒤, 그 영역 안에서 양/늑대 수를 센다. 영역 탐색이 끝난 다음에 한 번 더 훑어서 o/v 개수를 세려 했다. 두 일을 동시에 할 수 있나? 처음엔 &amp;ldquo;영역 &amp;rarr; 카운트&amp;rdquo;를 분리해서 생각했는데, BFS가 어차피 모든 칸을 큐에서 꺼낼 때 다 방문하니, 그 순간에 바로 카운트하면 한 번에 끝낼 수 있을 듯. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;8:01 AM &amp;mdash; 수정된 결론&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;동시에 해야 했음. 같은 영역을 BFS로 확장해 나갈 때, 그때그때 o와 v를 함께 누적하는 게 맞다. 다만, 이렇게 바꾸다 보니 코드가 길고 분기(조건문) 중복이 생김 &amp;rarr; 리팩토링 필요. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;왜 &amp;ldquo;동시에 세기&amp;rdquo;가 맞나? (논리 근거)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;BFS는 한 영역을 정확히 한 번씩 방문한다. &amp;ldquo;영역을 다 돈 뒤 다시 세기&amp;rdquo;는 한 영역을 사실상 두 번 훑는 셈이라 비효율. 큐에서 꺼낸 시점에 o/v를 더하면, 영역 탐색과 카운트를 O(R&amp;times;C) 단일 패스로 끝낼 수 있다. 또한 &amp;ldquo;영역 내 비교(양 &amp;gt; 늑대면 늑대 0, 아니면 양 0)&amp;rdquo;는 그 영역의 BFS가 끝나는 시점에만 하면 된다.&lt;br /&gt;
&lt;pre id=&quot;code_1759573933108&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque
r,c = map(int,input().split())
graph = [input()for _ in range(r)]
visited = [[0 for _ in range(c)] for _ in range(r)]
q= deque()


def bfs():
    global o,v
    direction = [(1,0),(0,-1),(0,1),(-1,0)]
    while q:
        x,y = q.popleft()
        for dx, dy in direction:
            nx = x+ dx
            ny = y+ dy
            
            if 0&amp;lt;=nx&amp;lt;r and 0&amp;lt;=ny&amp;lt;c and not visited[nx][ny] and graph[nx][ny] != &quot;#&quot;:
                if graph[nx][ny] == &quot;v&quot;:
                    v+=1
                if graph[nx][ny] ==&quot;o&quot;:
                    o+=1
                q.append((nx,ny))
                visited[nx][ny]=1
    if o&amp;gt; v: 
        v=0
    else:
        o=0
    return (o,v)

ans_o =0
ans_v=0

for i in range(r):
    for j in range(c):
        o=0
        v=0
        if graph[i][j] == &quot;v&quot; and not visited[i][j]:
            v+=1
            q.append((i,j))
            visited[i][j] =1
            a,b=bfs()
            ans_o+=a
            ans_v+=b
          
        if graph[i][j] == &quot;o&quot; and not visited[i][j]:
            o+=1
            q.append((i,j))
            visited[i][j] =1
            a,b=bfs()
            ans_o+=a
            ans_v+=b
          
           
        if graph[i][j] == &quot;.&quot; and not visited[i][j]:
            q.append((i,j))
            visited[i][j] =1
            a,b=bfs()
            ans_o+=a
            ans_v+=b
          
        
print(ans_o,ans_v)​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2030&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjXucF/btsQ4A9Op9J/knKUc15VnL5jrjEWvN9k51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjXucF/btsQ4A9Op9J/knKUc15VnL5jrjEWvN9k51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjXucF/btsQ4A9Op9J/knKUc15VnL5jrjEWvN9k51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjXucF%2FbtsQ4A9Op9J%2FknKUc15VnL5jrjEWvN9k51%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;2030&quot; height=&quot;204&quot; data-origin-width=&quot;2030&quot; data-origin-height=&quot;204&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;</description>
      <category>Problem Solving/백준</category>
      <category>3184</category>
      <category>백준</category>
      <category>백준 양</category>
      <category>양</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/201</guid>
      <comments>https://onepunchprogram.tistory.com/201#entry201comment</comments>
      <pubDate>Sat, 4 Oct 2025 19:33:43 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 단속카메라</title>
      <link>https://onepunchprogram.tistory.com/200</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래머스 탐욕법 문제 중 하나인 '단속카메라'를 풀면서 겪었던 시행착오와, 그 과정에서 얻게 된 깨달음을 정리하려고 합니다.&lt;/p&gt;
&lt;p data-end=&quot;420&quot; data-start=&quot;280&quot; data-ke-size=&quot;size16&quot;&gt;처음 문제를 접했을 때 저는 '탐욕법'이라는 키워드를 보고, 자연스럽게 정렬을 떠올렸습니다.&lt;br /&gt;그동안 풀었던 탐욕 문제들 대부분이 정렬 기준만 잘 잡으면 쉽게 풀리는 구조였기 때문입니다.&lt;br /&gt;그래서 별다른 의심 없이 이번 문제도 정렬로 접근했습니다.&lt;/p&gt;
&lt;p data-end=&quot;514&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;진입 시점을 기준으로 오름차순 정렬해보고,&lt;br /&gt;내림차순 정렬도 해보고,진출 시점을 기준으로도 바꿔보면서,정렬 기준만 계속 바꿔가며 답을 찾으려고 했습니다.&lt;/p&gt;
&lt;p data-end=&quot;616&quot; data-start=&quot;516&quot; data-ke-size=&quot;size16&quot;&gt;그런데 반례가 생기고, 정확한 기준을 잡기가 어려웠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;def solution(routes):
    routes.sort(key=lambda x: x[1])  
    check = [0] * len(routes)
    ans = 0

    for i in range(len(routes)):
        if check[i]:
            continue
        camera = routes[i][1]
        ans += 1
        check[i] = 1

        for j in range(i+1, len(routes)):
            if routes[j][0] &amp;lt;= camera &amp;lt;= routes[j][1]:
                check[j] = 1

    return ans&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 차량 정렬&lt;/h3&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;routes.sort(key=lambda x: x[1])
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 차량을 &lt;b&gt;진출 시점 기준 오름차순&lt;/b&gt;으로 정렬합니다.&lt;br /&gt;이 정렬이 핵심입니다. 이유는 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;진출 지점이 빠른 차량을 먼저 처리하면, 해당 차량을 기준으로 &lt;b&gt;가장 많은 차량을 하나의 카메라로 커버&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;즉, &lt;b&gt;공통 구간의 끝 지점부터 카메라를 설치&lt;/b&gt;해 나가면, 중복 없이 최소 카메라 개수로 커버할 수 있게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 방문 여부 배열&lt;/h3&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;check = [0] * len(routes)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 차량이 이미 카메라에 찍혔는지 확인하기 위한 배열입니다.&lt;br /&gt;중복 체크를 방지하기 위해 사용됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 차량 반복 처리&lt;/h3&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;for i in range(len(routes)):
    if check[i]:
        continue
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 찍힌 차량이라면 넘어갑니다.&lt;br /&gt;찍히지 않은 차량이라면, &lt;b&gt;그 차량을 기준으로 새 카메라를 설치&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 카메라 설치 및 범위 체크&lt;/h3&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;camera = routes[i][1]
ans += 1
check[i] = 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 차량의 &lt;b&gt;진출 시점에 카메라를 설치&lt;/b&gt;합니다.&lt;br /&gt;그 지점은 가장 늦게 차량이 나가는 위치이기 때문에,&lt;br /&gt;다음 차량들이 &lt;b&gt;진입 시점 &amp;le; 카메라 위치 &amp;le; 진출 시점&lt;/b&gt;인 경우 함께 찍힙니다.&lt;/p&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;for j in range(i+1, len(routes)):
    if routes[j][0] &amp;lt;= camera &amp;lt;= routes[j][1]:
        check[j] = 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 카메라에 찍히는 차량들을 체크 배열로 표시해둡니다.&lt;br /&gt;이후 다시 돌아왔을 때 이 차량은 건너뛰게 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 반환&lt;/h3&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;return ans
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 설치한 카메라 개수를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;진출 시점 기준 오름차순 정렬&lt;/b&gt;: 가능한 가장 이른 시점에 카메라를 설치해, 최대한 많은 차량을 한 번에 커버하기 위함입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방문 체크 방식&lt;/b&gt;: 중복 카메라 설치를 방지하기 위해 check 배열을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐욕적으로 선택&lt;/b&gt;: 지금 설치한 카메라로 커버할 수 있는 차량은 모두 커버하고, 다음 안 찍힌 차량부터 다시 새로운 카메라 설치를 시도합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;6. 핵심 아이디어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;차량을 &lt;b&gt;진출 시점 기준 오름차순으로 정렬&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;가장 먼저 나가는 차량의 &lt;b&gt;진출 지점에 카메라를 설치&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;이후 이 카메라에 찍히는 차량들을 미리 체크해둡니다.&lt;/li&gt;
&lt;li&gt;다음 루프에서는 &lt;b&gt;아직 카메라에 안 찍힌 차량&lt;/b&gt;만 골라 새로운 카메라를 설치합니다.&lt;/li&gt;
&lt;li&gt;이 과정을 반복하면 &lt;b&gt;최소 개수의 카메라로 모든 차량을 커버&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;7. 입출력 예시&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1753390928685&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(solution([[-20, 15], [-14, -5], [-18, -13], [-5, -3]]))  # 2
print(solution([[-2, -1], [1, 2], [-3, 0]]))  # 2
print(solution([[0, 0]]))  # 1
print(solution([[0, 1], [0, 1], [1, 2]]))  # 1 
print(solution([[0, 1], [2, 3], [4, 5], [6, 7]]))  # 4
print(solution([[-20, -15], [-14, -5], [-18, -13], [-5, -3]]))  # 2
print(solution([[-20, 15], [-20, -15], [-14, -5], [-18, -13], [-5, -3]]))  # 2 
print(solution([[2, 2], [0, 1], [-10, 9]]))  # 2
print(solution([[-7, 0], [-6, -4], [-5, -3], [-3, -1], [-1, 4], [1, 2], [3, 4]]))  # 4
print(solution([[-5, -3], [-4, 0], [-4, -2], [-1, 2], [0, 3], [1, 5], [2, 4]]))  # 2 
print(solution([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7],[7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15]]))  # 8
print(solution([[0, 12], [1, 12], [2, 12], [3, 12], [5, 6], [6, 12], [10, 12]]))  # 2 
print(solution([[-191, -107], [-184, -151], [-150, -102], [-171, -124], [-120, -114]]))  # 2&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0W2O7/btsPxW8FNyp/kZYzIGdqVeG66W1sqtoIk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0W2O7/btsPxW8FNyp/kZYzIGdqVeG66W1sqtoIk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0W2O7/btsPxW8FNyp/kZYzIGdqVeG66W1sqtoIk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0W2O7%2FbtsPxW8FNyp%2FkZYzIGdqVeG66W1sqtoIk1%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;1110&quot; height=&quot;312&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;312&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;</description>
      <category>Problem Solving/프로그래머스</category>
      <category>단속카메라</category>
      <category>프로그래머스</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/200</guid>
      <comments>https://onepunchprogram.tistory.com/200#entry200comment</comments>
      <pubDate>Fri, 25 Jul 2025 06:03:35 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 카펫</title>
      <link>https://onepunchprogram.tistory.com/199</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42842&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42842&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753344643134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42842&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chlWl5/hyZqRBnhLZ/0krY1x1KWgqykMBrSlpWbK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/xoKi0/hyZm76Xi2W/cRbGu7bctg63YIFhSFH0GK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42842&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42842&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chlWl5/hyZqRBnhLZ/0krY1x1KWgqykMBrSlpWbK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/xoKi0/hyZm76Xi2W/cRbGu7bctg63YIFhSFH0GK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 해당 문제를 보고 입출력 예시를 보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0I7YB/btsPx2gaH5X/m5o3M26D4ZkxRPeRD3lia0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0I7YB/btsPx2gaH5X/m5o3M26D4ZkxRPeRD3lia0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0I7YB/btsPx2gaH5X/m5o3M26D4ZkxRPeRD3lia0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0I7YB%2FbtsPx2gaH5X%2Fm5o3M26D4ZkxRPeRD3lia0%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;522&quot; height=&quot;404&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 떠오른 생각은 &lt;b&gt;brown과 yellow의 합을 기준으로 그 약수들을 구하고&lt;/b&gt;,&lt;br /&gt;그 중에서 &lt;b&gt;(가로, 세로) 쌍의 곱이 brown + yellow가 되면서&lt;/b&gt; 조건을 만족하는 &lt;b&gt;가장 작은 가로 값을 찾는 것&lt;/b&gt;이 답이 아닐까 하는 것이었습니다.&lt;/p&gt;
&lt;p data-end=&quot;364&quot; data-start=&quot;263&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, brown이 10이고 yellow가 2라면 합은 12이고,&lt;br /&gt;12의 약수 쌍은 (1,12), (2,6), (3,4)와 같습니다.&lt;br /&gt;이런 가정하에 문제를 접근했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1753344931784&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(brown, yellow):
    temp = brown + yellow
    ans = 1e9
    result = []
    for i in range(1,brown+1) :
        if temp % i == 0 :
            row = i 
            col = temp //i
        else:
            continue
        if ans &amp;gt; row + col:
            ans = row + col  
            result = [row,col]
    result.sort(reverse=True)
    return result&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;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;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lN1ym/btsPwDPu9nE/odXIeFvDtCrUjVUxbwbsH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lN1ym/btsPwDPu9nE/odXIeFvDtCrUjVUxbwbsH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lN1ym/btsPwDPu9nE/odXIeFvDtCrUjVUxbwbsH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlN1ym%2FbtsPwDPu9nE%2FodXIeFvDtCrUjVUxbwbsH0%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;152&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;152&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;반례를 찾았는데&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753345468478&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;solution( 26, 10) # [12, 3]&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;기대값과 다르게 [6,6]이 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그림을 그렸는데 ..&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3yCuT/btsPxUQyzo6/sEGARon0K4Bu7LSkcA4iKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3yCuT/btsPxUQyzo6/sEGARon0K4Bu7LSkcA4iKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3yCuT/btsPxUQyzo6/sEGARon0K4Bu7LSkcA4iKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3yCuT%2FbtsPxUQyzo6%2FsEGARon0K4Bu7LSkcA4iKk%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;1223&quot; height=&quot;400&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 수식으로 일반화 할 수 있었습니다 !&lt;/p&gt;
&lt;pre id=&quot;code_1753349886076&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(brown, yellow):
    ans =[]
    for x in range(1,yellow+1):
        if yellow % x == 0:
            y = yellow//x
            if  x*y + 2*x + 2*y + 4 == yellow+ brown:
                ans = [y+2, x+2]
                break
    return ans&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;1014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MVYan/btsPxIvJqNZ/2Su26SfLDfhyRW0iev00W1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MVYan/btsPxIvJqNZ/2Su26SfLDfhyRW0iev00W1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MVYan/btsPxIvJqNZ/2Su26SfLDfhyRW0iev00W1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMVYan%2FbtsPxIvJqNZ%2F2Su26SfLDfhyRW0iev00W1%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;900&quot; height=&quot;1014&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;1014&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Problem Solving/프로그래머스</category>
      <category>카펫</category>
      <category>프로그래머스</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/199</guid>
      <comments>https://onepunchprogram.tistory.com/199#entry199comment</comments>
      <pubDate>Thu, 24 Jul 2025 18:42:51 +0900</pubDate>
    </item>
    <item>
      <title>백준 2670 연속부분최대곱</title>
      <link>https://onepunchprogram.tistory.com/198</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2670&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2670&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752567151580&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = int(input())
arr = [float(input()) for _ in range(n)]

dp = arr[0]
ans = arr[0]

for i in range(1, n):
    if dp == 0.0:
        dp = arr[i]
    else:
        dp *= arr[i]
        dp = max(dp, arr[i])
    ans = max(ans, dp)

print('%.3f' % ans)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Problem Solving/백준</category>
      <category>2670</category>
      <category>연속부분최대곱</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/198</guid>
      <comments>https://onepunchprogram.tistory.com/198#entry198comment</comments>
      <pubDate>Tue, 15 Jul 2025 17:12:48 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 거리두기 확인하기</title>
      <link>https://onepunchprogram.tistory.com/197</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81302&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/81302&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752184681204&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81302&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chlea8/hyZjBMN6rC/MlKwVDr24Lw3FurN8xrKj0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/fYxTP/hyZjizCBN3/lrWrayHE0lgoyQcikLEvak/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81302&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81302&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chlea8/hyZjBMN6rC/MlKwVDr24Lw3FurN8xrKj0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/fYxTP/hyZjizCBN3/lrWrayHE0lgoyQcikLEvak/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752184692543&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque

def bfs(q,graph):
    x,y =  q.popleft()
    for dx,dy in {(1,0),(0,1),(-1,0),(0,-1),(-1,1),(1,-1),(1,1),(-1,-1),(0,2),(0,-2),(-2,0),(2,0)} :
        nx = x + dx
        ny = y + dy
        if 0&amp;lt;=nx &amp;lt; 5 and 0&amp;lt;= ny &amp;lt; 5 and not visited[nx][ny] and  graph[nx][ny] == &quot;P&quot; :
            q.append((nx,ny))
            visited[nx][ny]=1
            while q:
                nnx,nny = q.popleft()
                for kx,ky in {(1,0),(0,1),(-1,0),(0,-1),}:
                    nkx = nnx+kx
                    nky = nny+ky
                    if 0&amp;lt;=nkx &amp;lt; 5 and 0&amp;lt;= nky &amp;lt; 5 and (abs(nx-nnx) + abs(ny-nny)) &amp;lt;2 and not visited[nkx][nky] and graph[nkx][nky]== &quot;O&quot;: 
                        q.append((nkx,nky))
                        visited[nkx][nky] =1
                    if 0&amp;lt;=nkx &amp;lt; 5 and 0&amp;lt;= nky &amp;lt; 5 and (abs(nx-nnx) + abs(ny-nny)) &amp;lt;2  and not visited[nkx][nky] and graph[nkx][nky]== &quot;P&quot;:
                        visited[nkx][nky] =1
                        return False
    return True
    
    

def fun(graph):
    global visited
    visited = [[0 for _ in range(5)] for _ in range(5)]
    flag = True
    q = deque()
    for i in range(5):
        for j in range(5):
            if graph[i][j] == &quot;X&quot;:
                visited[i][j] =1
    for i in range(5):
        for j in range(5):
            if graph[i][j] == &quot;P&quot;:
                q.append((i,j))
                if not bfs(q,graph):
                    flag = False
                    break
    if not flag:
        return 0
    return 1
    
                
def solution(places):
    ans =[]
    for i in range(len(places)):
        ans.append(fun(places[i]))
    return ans&lt;/code&gt;&lt;/pre&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;1110&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqP5R0/btsPc8ofLJZ/Az33MysBptUSXvWTExu87K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqP5R0/btsPc8ofLJZ/Az33MysBptUSXvWTExu87K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqP5R0/btsPc8ofLJZ/Az33MysBptUSXvWTExu87K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqP5R0%2FbtsPc8ofLJZ%2FAz33MysBptUSXvWTExu87K%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;1110&quot; height=&quot;1208&quot; data-origin-width=&quot;1110&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 머리를 좀 썼다 ..&lt;/p&gt;</description>
      <category>Problem Solving/프로그래머스</category>
      <category>거리두기 확인하기</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/197</guid>
      <comments>https://onepunchprogram.tistory.com/197#entry197comment</comments>
      <pubDate>Fri, 11 Jul 2025 07:01:04 +0900</pubDate>
    </item>
    <item>
      <title>객체지향 쿼리 언어 - 벌크 연산</title>
      <link>https://onepunchprogram.tistory.com/196</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;벌크 연산&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;div id=&quot;code_1752140858207&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;pre&amp;gt;
&amp;bull; 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?

    &amp;bull; JPA 변경 감지 기능으로 처리할 경우, 다음과 같은 방식으로 동작함

        1. 재고가 10개 미만인 상품을 리스트로 조회한다.
        2. 조회된 상품 각각의 가격을 10% 증가시킨다.
        3. 트랜잭션 커밋 시점에 JPA의 변경 감지(Dirty Checking)가 동작하여
           변경된 각 상품에 대해 UPDATE SQL을 실행한다.

    &amp;rarr; 만약 변경된 상품이 100건이라면, UPDATE SQL이 100번 실행됨
      (비효율적이며 성능 저하 우려 있음)
&amp;lt;/pre&amp;gt;&quot;&gt;
&lt;pre&gt;&amp;bull; 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?

    &amp;bull; JPA 변경 감지 기능으로 처리할 경우, 다음과 같은 방식으로 동작함

        1. 재고가 10개 미만인 상품을 리스트로 조회한다.
        2. 조회된 상품 각각의 가격을 10% 증가시킨다.
        3. 트랜잭션 커밋 시점에 JPA의 변경 감지(Dirty Checking)가 동작하여
           변경된 각 상품에 대해 UPDATE SQL을 실행한다.

    &amp;rarr; 만약 변경된 상품이 100건이라면, UPDATE SQL이 100번 실행됨
      (비효율적이며 성능 저하 우려 있음)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;벌크 연산 예제&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;div id=&quot;code_1752140993967&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;p&amp;gt;&amp;bull; 쿼리 한 번으로 여러 테이블 로우를 변경할 수 있다 (&amp;rarr; 엔티티를 일일이 변경하지 않음)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;bull; JPA에서는 JPQL의 벌크 연산(Bulk Operation)을 통해 실행&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;bull; 예: UPDATE, DELETE 쿼리&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;- UPDATE: 조건에 맞는 여러 엔티티의 값을 한 번에 변경&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;- DELETE: 조건에 맞는 여러 엔티티를 한 번에 삭제&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;- INSERT: JPQL 자체는 지원하지 않지만, Hibernate는 아래처럼 지원함&amp;lt;br&amp;gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;(insert into ... select ... 구문)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;bull; &amp;lt;code&amp;gt;executeUpdate()&amp;lt;/code&amp;gt; 메서드 사용 시, 영향 받은 row 수(int)를 반환&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;rarr; 예: 20개의 row가 수정되었다면 &amp;lt;code&amp;gt;executeUpdate()&amp;lt;/code&amp;gt;는 &amp;lt;code&amp;gt;20&amp;lt;/code&amp;gt; 반환&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;bull; 단, 벌크 연산은 영속성 컨텍스트를 무시하므로 &amp;lt;strong&amp;gt;1차 캐시와 동기화 되지 않음&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;rarr; 이후 &amp;lt;code&amp;gt;em.clear()&amp;lt;/code&amp;gt; 등으로 캐시 초기화 권장&amp;lt;/p&amp;gt;
&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 쿼리 한 번으로 여러 테이블 로우를 변경할 수 있다 (&amp;rarr; 엔티티를 일일이 변경하지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;bull; JPA에서는 JPQL의 벌크 연산(Bulk Operation)을 통해 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;bull; 예: UPDATE, DELETE 쿼리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- UPDATE: 조건에 맞는 여러 엔티티의 값을 한 번에 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- DELETE: 조건에 맞는 여러 엔티티를 한 번에 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- INSERT: JPQL 자체는 지원하지 않지만, Hibernate는 아래처럼 지원함&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(insert into ... select ... 구문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;bull; &lt;code&gt;executeUpdate()&lt;/code&gt; 메서드 사용 시, 영향 받은 row 수(int)를 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr; 예: 20개의 row가 수정되었다면 &lt;code&gt;executeUpdate()&lt;/code&gt;는 &lt;code&gt;20&lt;/code&gt; 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;bull; 단, 벌크 연산은 영속성 컨텍스트를 무시하므로 &lt;b&gt;1차 캐시와 동기화 되지 않음&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr; 이후 &lt;code&gt;em.clear()&lt;/code&gt; 등으로 캐시 초기화 권장&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752141020859&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;       // 벌크 연산
            int resultCount = em.createQuery(&quot;update Member m set m.age = 20&quot;)
                .executeUpdate();

            System.out.println(&quot;resultCount = &quot; + resultCount);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck2LUQ/btsPb4mnylz/lyOWbJXd6wnzDOezDdTEgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck2LUQ/btsPb4mnylz/lyOWbJXd6wnzDOezDdTEgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck2LUQ/btsPb4mnylz/lyOWbJXd6wnzDOezDdTEgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck2LUQ%2FbtsPb4mnylz%2FlyOWbJXd6wnzDOezDdTEgk%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;710&quot; height=&quot;668&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;벌크&lt;span&gt; &lt;/span&gt;연산&lt;span&gt; &lt;/span&gt;주의&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;div id=&quot;code_1752142160710&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;p&amp;gt;&amp;bull; 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리 실행&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;rarr; 즉, 1차 캐시나 스냅샷을 거치지 않고 DB에 바로 반영됨&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;bull; 벌크 연산은 가능한 한 &amp;lt;strong&amp;gt;트랜잭션 내에서 가장 먼저 실행&amp;lt;/strong&amp;gt;하는 것이 안전함&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;bull; 벌크 연산 수행 후에는 반드시 &amp;lt;code&amp;gt;em.clear()&amp;lt;/code&amp;gt; 또는 &amp;lt;code&amp;gt;flush + clear&amp;lt;/code&amp;gt;로&amp;lt;br&amp;gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;strong&amp;gt;영속성 컨텍스트를 초기화&amp;lt;/strong&amp;gt;해야 데이터 불일치 문제를 방지할 수 있음&amp;lt;/p&amp;gt;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr; 즉, 1차 캐시나 스냅샷을 거치지 않고 DB에 바로 반영됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 벌크 연산은 가능한 한 &lt;b&gt;트랜잭션 내에서 가장 먼저 실행&lt;/b&gt;하는 것이 안전함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 벌크 연산 수행 후에는 반드시 &lt;code&gt;em.clear()&lt;/code&gt; 또는 &lt;code&gt;flush + clear&lt;/code&gt;로&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;영속성 컨텍스트를 초기화&lt;/b&gt;해야 데이터 불일치 문제를 방지할 수 있음&lt;/p&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1752141430691&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.hellojpa;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
import org.hellojpa.jpql.Member;
import org.hellojpa.jpql.Team;

public class JpaMain {
    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;hello&quot;);
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {

            Team teamA = new Team();
            teamA.setName(&quot;팀A&quot;);
            em.persist(teamA);

            Team teamB = new Team();
            teamB.setName(&quot;팀B&quot;);
            em.persist(teamB);

            Member member1 = new Member();
            member1.setUsername(&quot;회원1&quot;);
            member1.setTeam(teamA);
            em.persist(member1);

            Member member2 = new Member();
            member2.setUsername(&quot;회원2&quot;);
            member2.setTeam(teamB);
            em.persist(member2);

            Member member3 = new Member();
            member3.setUsername(&quot;회원3&quot;);
            member3.setTeam(teamB);
            em.persist(member3);


            
            // 벌크 연산
            int resultCount = em.createQuery(&quot;update Member m set m.age = 20&quot;)
                .executeUpdate();

            System.out.println(&quot;resultCount = &quot; + resultCount);

            Member findMember = em.find(Member.class, member1.getId());
            System.out.println(&quot;findMember = &quot; + findMember.getAge());


            tx.commit();
        } catch (Exception e) {
            tx.rollback();
            e.printStackTrace();
        } finally {
            em.close();
        }
        emf.close();

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FjzoM/btsPdf1uRz4/pgxhA4otaHZwjmNKq1lWnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FjzoM/btsPdf1uRz4/pgxhA4otaHZwjmNKq1lWnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FjzoM/btsPdf1uRz4/pgxhA4otaHZwjmNKq1lWnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFjzoM%2FbtsPdf1uRz4%2FpgxhA4otaHZwjmNKq1lWnK%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;788&quot; height=&quot;416&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;✅&lt;b&gt; 결과가 0으로 나오는 이유 요약&lt;br /&gt;&lt;/b&gt;- 벌크 연산은 &lt;b&gt;영속성 컨텍스트를 무시하고 DB에 직접 쿼리를 실행&lt;/b&gt;합니다.&lt;br /&gt;- 즉, em.find()로 가져오는 member1은 이미 &lt;b&gt;영속성 컨텍스트에 존재하는 캐시된 엔티티&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1752141670013&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member findMember = em.find(Member.class, member1.getId());
System.out.println(&quot;findMember = &quot; + findMember.getAge());  // &amp;rarr; 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;- findMember는&lt;b&gt; DB가 아닌 1차 캐시(영속성 컨텍스트)에서 조회됨&lt;/b&gt;&lt;br /&gt;- 이 캐시에는 age = 0인 원래 값이 남아 있음&lt;br /&gt;- 벌크 업데이트 결과가 &lt;b&gt;영속성 컨텍스트에 반영되지 않음&lt;/b&gt; &amp;rarr; 그래서 0으로 보이는 것&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;✅ &lt;b&gt;JPA&amp;nbsp;벌크&amp;nbsp;연산&amp;nbsp;주의사항&amp;nbsp;실습&amp;nbsp;예제&amp;nbsp;(1차&amp;nbsp;캐시&amp;nbsp;동기화&amp;nbsp;문제)&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752141872283&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.hellojpa;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
import org.hellojpa.jpql.Member;
import org.hellojpa.jpql.Team;

public class JpaMain {
    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;hello&quot;);
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {

            Team teamA = new Team();
            teamA.setName(&quot;팀A&quot;);
            em.persist(teamA);

            Team teamB = new Team();
            teamB.setName(&quot;팀B&quot;);
            em.persist(teamB);

            Member member1 = new Member();
            member1.setUsername(&quot;회원1&quot;);
            member1.setTeam(teamA);
            em.persist(member1);

            Member member2 = new Member();
            member2.setUsername(&quot;회원2&quot;);
            member2.setTeam(teamB);
            em.persist(member2);

            Member member3 = new Member();
            member3.setUsername(&quot;회원3&quot;);
            member3.setTeam(teamB);
            em.persist(member3);



            // 벌크 연산
            int resultCount = em.createQuery(&quot;update Member m set m.age = 20&quot;)
                .executeUpdate();

            em.clear(); // 영속성 컨텍스트 초기화

            System.out.println(&quot;resultCount = &quot; + resultCount);

            Member findMember = em.find(Member.class, member1.getId());
            System.out.println(&quot;findMember = &quot; + findMember.getAge());


            tx.commit();
        } catch (Exception e) {
            tx.rollback();
            e.printStackTrace();
        } finally {
            em.close();
        }
        emf.close();

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDy9Md/btsPb5lc0eN/DcJyfkDIBMKXxKeJO0FJjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDy9Md/btsPb5lc0eN/DcJyfkDIBMKXxKeJO0FJjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDy9Md/btsPb5lc0eN/DcJyfkDIBMKXxKeJO0FJjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDy9Md%2FbtsPb5lc0eN%2FDcJyfkDIBMKXxKeJO0FJjK%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;386&quot; height=&quot;494&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/김영한의 자바 ORM 표준 JPA 프로그래밍 - 기본편</category>
      <category>1차캐시 동기화</category>
      <category>벌크 연산</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/196</guid>
      <comments>https://onepunchprogram.tistory.com/196#entry196comment</comments>
      <pubDate>Thu, 10 Jul 2025 18:47:42 +0900</pubDate>
    </item>
    <item>
      <title>객체지향 쿼리 언어 - 페치 조인</title>
      <link>https://onepunchprogram.tistory.com/195</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;페치&lt;/span&gt; &lt;span&gt;조인&lt;/span&gt;(fetch join)&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- SQL 조인 종류 X&lt;br /&gt;- JPQL에서 성능 최적화를 위해 제공하는 기능&lt;br /&gt;- 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능&lt;br /&gt;- join fetch 명령어 사용&lt;br /&gt;- 페치 조인 ::= [ LEFT [OUTER] | INNER ] JOIN FETCH 조인경로&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;엔티티&lt;span&gt; &lt;/span&gt;페치&lt;span&gt; &lt;/span&gt;조인&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- 회원을 조회하면서 연관된 팀도 함께 조회(SQL 한 번에)&lt;br /&gt;- 다음 JPQL은 Hibernate 6에서 실행 시 아래와 같은 SQL로 변환됩니다&lt;br /&gt;
&lt;pre id=&quot;code_1752124598647&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- JPQL
select m from Member m join fetch m.team

-- Hibernate 6에서 변환된 SQL (로깅 기준)
select
    m1_0.id,
    m1_0.age,
    t1_0.id,
    t1_0.name,
    m1_0.username 
from
    Member m1_0 
join
    Team t1_0 on t1_0.id = m1_0.TEAM_ID​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;컬렉션 &lt;span&gt;&lt;/span&gt;&lt;span&gt;페치&lt;/span&gt; &lt;span&gt;조인과&lt;/span&gt; DISTINCT&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- 일대다 관계, 컬렉션 페치 조인&lt;br /&gt;- 다음 JPQL은 Hibernate 6에서 실행 시 아래와 같은 SQL로 변환됩니다&lt;br /&gt;
&lt;pre id=&quot;code_1752124987361&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- JPQL
select distinct t 
from Team t 
join fetch t.members 
where t.name = '팀A'

-- Hibernate 6 SQL (로그 출력 기준)
select
    distinct t1_0.id,
    m1_0.TEAM_ID,
    m1_0.id,
    m1_0.age,
    m1_0.username,
    t1_0.name 
from
    Team t1_0 
join
    Member m1_0 
    on t1_0.id = m1_0.TEAM_ID 
where
    t1_0.name = '팀A'​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;- SQL&lt;span&gt;의&lt;/span&gt; DISTINCT&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;br /&gt;- &lt;/span&gt;JPQL&lt;span&gt;의&lt;/span&gt; DISTINCT 2&lt;span&gt;가지&lt;/span&gt; &lt;span&gt;기능&lt;/span&gt; &lt;span&gt;제공&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1) &lt;/span&gt;SQL&lt;span&gt;에&lt;/span&gt; DISTINCT&lt;span&gt;를&lt;/span&gt; &lt;span&gt;추가&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2) &lt;/span&gt;애플리케이션에서&lt;span&gt; &lt;/span&gt;엔티티&lt;span&gt; &lt;/span&gt;중복&lt;span&gt; &lt;/span&gt;제거&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&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;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;br /&gt;&lt;b&gt;1. 일반 조인 (join)&lt;/b&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1752125613572&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- JPQL
select distinct t 
from Team t join t.members m 
where t.name = '팀B'



-- Hibernate 실행 SQL (쿼리 1)
select
    distinct t1_0.id,
    t1_0.name 
from
    Team t1_0 
join
    Member m1_0 on t1_0.id = m1_0.TEAM_ID 
where
    t1_0.name = '팀B'

-- 추가 SQL (getMembers() 호출 시 지연 로딩 발생)
select
    m1_0.TEAM_ID,
    m1_0.id,
    m1_0.age,
    m1_0.username 
from
    Member m1_0 
where
    m1_0.TEAM_ID = ?&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;- Team만 select 대상이므로, members는 로딩되지 않음&lt;br /&gt;- team.getMembers() 호출 시점에 추가 SQL 실행됨 (지연 로딩, Lazy)&lt;br /&gt;- 쿼리 2번 실행됨 (N+1 가능성 있음) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. 페치 조인 (join fetch)&lt;/b&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1752126499000&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- JPQL
select distinct t 
from Team t join fetch t.members m 
where t.name = '팀B'

-- Hibernate 실행 SQL (쿼리 1회)
select
    distinct t1_0.id,
    m1_0.TEAM_ID,
    m1_0.id,
    m1_0.age,
    m1_0.username,
    t1_0.name 
from
    Team t1_0 
join
    Member m1_0 on t1_0.id = m1_0.TEAM_ID 
where
    t1_0.name = '팀B'​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;- Team과 연관된 Member를 한 번의 SQL로 모두 로딩&lt;br /&gt;- getMembers() 호출해도 추가 쿼리 발생하지 않음&lt;br /&gt;- 성능 효율적 , N+1 방지&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;✅&amp;nbsp; 정리 비교&lt;br /&gt;페치 조인은 연관 엔티티까지 한 번에 가져와 N+1 문제를 해결하고 성능을 최적화할 수 있습니다.&lt;br /&gt;일반 조인은 연관 객체를 즉시 로딩하지 않기 때문에, 연관 데이터를 사용할 경우추가 쿼리가 발생할 수 있습니다.&lt;br /&gt;출력은 같아 보여도 쿼리 수와 성능은 다릅니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;</description>
      <category>TIL/김영한의 자바 ORM 표준 JPA 프로그래밍 - 기본편</category>
      <category>페치 조인</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/195</guid>
      <comments>https://onepunchprogram.tistory.com/195#entry195comment</comments>
      <pubDate>Thu, 10 Jul 2025 14:51:05 +0900</pubDate>
    </item>
    <item>
      <title>객체지향 쿼리 언어 - 경로 표현식</title>
      <link>https://onepunchprogram.tistory.com/194</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;경로&lt;span&gt; &lt;/span&gt;표현식&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- .(점)을 찍어 객체 그래프를 탐색하는 것&lt;br /&gt;
&lt;pre id=&quot;code_1752055106040&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select m.username -&amp;gt; 상태 필드
from Member m
join m.team t -&amp;gt; 단일 값 연관 필드
join m.orders o -&amp;gt; 컬렉션 값 연관 필드
where t.name = '팀A'​&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;경로&lt;span&gt; &lt;/span&gt;표현식&lt;span&gt; &lt;/span&gt;용어&lt;span&gt; &lt;/span&gt;정리&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;br /&gt;- &lt;b&gt;상태 필드&lt;/b&gt;(state field): 단순히 값을 저장하기 위한 필드&lt;b&gt;&lt;b&gt; (ex: m.username)&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;-&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;연관&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;필드&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;(association field): &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;연관관계를&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;위한&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;필드&lt;br /&gt;&amp;nbsp; &amp;nbsp;1) &lt;b&gt;단일&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;b&gt;값&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;b&gt;연관&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;b&gt;필드&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;: &lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;@ManyToOne, @OneToOne, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;대상이&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;엔티티&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt;(ex: m.team)&lt;br /&gt;&lt;/b&gt;&amp;nbsp; &amp;nbsp;2) &lt;b&gt;컬렉션&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;b&gt;값&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;b&gt;연관&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;b&gt;필드&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;: &lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;@OneToMany, @ManyToMany, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;대상이&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;컬렉션&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;(ex: m.orders)&lt;/span&gt;&lt;/b&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;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;경로&lt;span&gt; &lt;/span&gt;표현식&lt;span&gt; &lt;/span&gt;특징&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- &lt;b&gt;상태 필드&lt;/b&gt;(state field): 경로 탐색의 끝, 탐색X&lt;br /&gt;&amp;nbsp; ex) JPQL: select m.username, m.age from Member m&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;SQL: select m.username, m.age from Member m&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;단일 값 연관 경로&lt;/b&gt;: 묵시적 내부 조인(inner join) 발생, 탐색O&lt;br /&gt;&amp;nbsp; &amp;nbsp;ex) JPQL: select o.member from Order o&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; SQL:
&lt;pre id=&quot;code_1752055706419&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select m.*
from Orders o
inner join Member m on o.member_id = m.id​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;&lt;b&gt;컬렉션 값 연관 경로&lt;/b&gt;&lt;/b&gt;: &lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;묵시적&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;내부&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;조인&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;발생&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;탐색&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;X&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&amp;bull; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;FROM &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;절에서&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;명시적&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;&lt;b&gt;조인&lt;/b&gt;을&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;통해&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;별칭을&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;얻으면&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;별칭을&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;통&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;해&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;탐색&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;가능&lt;/span&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1752055810407&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select m.username from Team t join t.members m&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;명시적&lt;span&gt;&amp;nbsp;&lt;/span&gt;조인&lt;span&gt;, &lt;/span&gt;묵시적&lt;span&gt; &lt;/span&gt;조인&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- &lt;b&gt;명시적 조인&lt;/b&gt;: join 키워드 직접 사용&lt;br /&gt;
&lt;pre id=&quot;code_1752055946900&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select m from Member m join m.team t​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;- &lt;b&gt;묵시적 조인&lt;/b&gt;: 경로 표현식에 의해 묵시적으로 SQL 조인 발생 (내부 조인만 가능)&lt;br /&gt;
&lt;pre id=&quot;code_1752056001357&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select m.team from Member m​&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&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;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- 항상 내부 조인&lt;br /&gt;- &lt;b&gt;컬렉션은 경로 탐색의 끝, 명시적 조인을 통해 별칭을 얻어야함&lt;/b&gt;&lt;br /&gt;- 경로 탐색은 주로 SELECT, WHERE 절에서 사용하지만 묵시적 조인으로 인해 SQL의 FROM (JOIN) 절에 영향을 줌&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;실무&lt;span&gt; &lt;/span&gt;조언&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- &lt;b&gt;가급적 묵시적 조인 대신에 명시적 조인 사용&lt;/b&gt;&lt;br /&gt;- 조인은 SQL 튜닝에 중요 포인트&lt;br /&gt;- 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어려움&lt;/blockquote&gt;</description>
      <category>TIL/김영한의 자바 ORM 표준 JPA 프로그래밍 - 기본편</category>
      <category>JPQL</category>
      <category>경로 표현식</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/194</guid>
      <comments>https://onepunchprogram.tistory.com/194#entry194comment</comments>
      <pubDate>Wed, 9 Jul 2025 19:16:44 +0900</pubDate>
    </item>
    <item>
      <title>백준 2578 빙고</title>
      <link>https://onepunchprogram.tistory.com/193</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2578&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2578&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751933917480&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def check_line(cnt):
 
    
    for i in range(5):
        if sum(check[i]) == 5:
            cnt+=1
   
    
    for i in range(5):
        temp =0
        for j in range(5):
            temp += check[j][i]
        if temp == 5:
            cnt+=1
 
    
    temp =0
    for i in range(5):
        for j in range(5):
            if i== j :
                temp += check[i][j]
    if temp ==5 :
        cnt+=1
    
   
    
    temp = 0
    for i in range(5):
        for j in range(5):
            if i+ j ==4:
                temp += check[i][j]
    
    if temp ==5:
        cnt+=1
    
    return cnt &amp;gt;=3





matrix = [list(map(int,input().split())) for _ in range(5)]
elems  = [list(map(int,input().split())) for _ in range(5)]
check = [[0 for _ in range(5)] for _ in range(5)]
d= dict()
for i in range(5):
    for j in range(5):
        d[matrix[i][j]] = (i,j)
ans =0
for i in range(5):
    for j in range(5):
        x,y =d[elems[i][j]]
        check[x][y] =1
        ans +=1
        flag = check_line(0)
        if flag:
            print(ans)
            break
    if flag:
        break&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 깨끗하게 짤 수 있을 것 같다 .. 추후에 다시 리팩토링 해봐야겠다&lt;/p&gt;</description>
      <category>Problem Solving/백준</category>
      <category>백준</category>
      <category>빙고</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/193</guid>
      <comments>https://onepunchprogram.tistory.com/193#entry193comment</comments>
      <pubDate>Tue, 8 Jul 2025 09:20:12 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 야근 지수</title>
      <link>https://onepunchprogram.tistory.com/192</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12927&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12927&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1751854073569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12927&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/y84f4/hyZjAft0eB/4OKp5Mg7L3zW2YSKgeMp41/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/dEX1TA/hyZjrW9NG2/W5KnIRbbxa4V84SOkFxFRK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12927&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12927&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/y84f4/hyZjAft0eB/4OKp5Mg7L3zW2YSKgeMp41/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/dEX1TA/hyZjrW9NG2/W5KnIRbbxa4V84SOkFxFRK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751854097969&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
def solution(n, works):
    ans = 0
    if sum(works) &amp;lt;= n:
        return ans

    pq = []
    for work in works:
        heapq.heappush(pq,(-work,work))

    while n &amp;gt; 0:
        negative, positive = heapq.heappop(pq)
        if positive &amp;gt; 0:
            negative += 1
            positive -= 1
            n -= 1
            heapq.heappush(pq,(negative,positive))
        else:
            heapq.heappush(pq,(negative,positive))

    for _, elem in pq:
        ans += elem ** 2
    return ans&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Problem Solving/프로그래머스</category>
      <category>야근 지수</category>
      <category>프로그래머스</category>
      <author>minOE</author>
      <guid isPermaLink="true">https://onepunchprogram.tistory.com/192</guid>
      <comments>https://onepunchprogram.tistory.com/192#entry192comment</comments>
      <pubDate>Mon, 7 Jul 2025 11:08:46 +0900</pubDate>
    </item>
  </channel>
</rss>