<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>YataNox</title>
    <link>https://yatanox.tistory.com/</link>
    <description>꿈을 키워가는 초보 개발자입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 17 Apr 2026 02:53:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>에이디/김우진</managingEditor>
    <item>
      <title>[My_SQL] Lv.3 있었는데요 없었습니다</title>
      <link>https://yatanox.tistory.com/192</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&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;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkSTCy/btsLCHzLmYA/L1Ed7kZ1xvcXKOKDos5jGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkSTCy/btsLCHzLmYA/L1Ed7kZ1xvcXKOKDos5jGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkSTCy/btsLCHzLmYA/L1Ed7kZ1xvcXKOKDos5jGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkSTCy%2FbtsLCHzLmYA%2FL1Ed7kZ1xvcXKOKDos5jGK%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;740&quot; height=&quot;423&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmZEVk/btsLCoABShi/1FQZNThkFkXtt9wdHJTbSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmZEVk/btsLCoABShi/1FQZNThkFkXtt9wdHJTbSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmZEVk/btsLCoABShi/1FQZNThkFkXtt9wdHJTbSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmZEVk%2FbtsLCoABShi%2F1FQZNThkFkXtt9wdHJTbSK%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;738&quot; height=&quot;427&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;427&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;DATEDIFF로 비교하면 될 것같지만 시/분/초 단위로 입양일이 더 빠를 땐 구분할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TIMESTAMPDIFF로 SECOND 단위로 비교한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TKK7q/btsLAcnVzJV/rJVJvJigzpG04n2kp6jhT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TKK7q/btsLAcnVzJV/rJVJvJigzpG04n2kp6jhT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TKK7q/btsLAcnVzJV/rJVJvJigzpG04n2kp6jhT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTKK7q%2FbtsLAcnVzJV%2FrJVJvJigzpG04n2kp6jhT0%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;715&quot; height=&quot;95&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ai.ANIMAL_ID, ai.NAME
FROM ANIMAL_INS ai JOIN ANIMAL_OUTS ao ON ai.ANIMAL_ID = ao.ANIMAL_ID
WHERE TIMESTAMPDIFF(SECOND, ao.DATETIME, ai.DATETIME) &amp;gt; 0
ORDER BY ai.DATETIME;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DB/Programmers SQL</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/192</guid>
      <comments>https://yatanox.tistory.com/192#entry192comment</comments>
      <pubDate>Tue, 31 Dec 2024 15:43:27 +0900</pubDate>
    </item>
    <item>
      <title>[My_SQL] Lv3 카테고리 별 도서 판매량 집계하기</title>
      <link>https://yatanox.tistory.com/191</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;719&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKiuq/btsLAcuLXaY/xrCjCqNtqqYi79T4bwyXq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKiuq/btsLAcuLXaY/xrCjCqNtqqYi79T4bwyXq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKiuq/btsLAcuLXaY/xrCjCqNtqqYi79T4bwyXq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKiuq%2FbtsLAcuLXaY%2FxrCjCqNtqqYi79T4bwyXq1%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;739&quot; height=&quot;719&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;719&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;WHERE절 에 2022년 1월 데이터만 조회하게 걸러내고 카테고리별로 Grouping 하고 SUM함수를 사용하여 수를 집계했다.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7OibX/btsLAtKbeCL/A52Cakkbh44gkkc5Fh2Ta1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7OibX/btsLAtKbeCL/A52Cakkbh44gkkc5Fh2Ta1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7OibX/btsLAtKbeCL/A52Cakkbh44gkkc5Fh2Ta1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7OibX%2FbtsLAtKbeCL%2FA52Cakkbh44gkkc5Fh2Ta1%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;610&quot; height=&quot;133&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT b.CATEGORY, SUM(bs.SALES) AS TOTAL_SALES
FROM BOOK b JOIN BOOK_SALES bs ON b.BOOK_ID = bs.BOOK_ID
WHERE DATE_FORMAT(bs.SALES_DATE, '%Y-%m') = '2022-01'
GROUP BY CATEGORY
ORDER BY 1 ASC;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB/Programmers SQL</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/191</guid>
      <comments>https://yatanox.tistory.com/191#entry191comment</comments>
      <pubDate>Tue, 31 Dec 2024 15:32:40 +0900</pubDate>
    </item>
    <item>
      <title>[My_SQL] Lv.3 오랜 기간 보호한 동물(1)</title>
      <link>https://yatanox.tistory.com/190</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;775&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blYml7/btsLBy4yoZD/UoEtjJcFPjZXs4V7VkV5hK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blYml7/btsLBy4yoZD/UoEtjJcFPjZXs4V7VkV5hK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blYml7/btsLBy4yoZD/UoEtjJcFPjZXs4V7VkV5hK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYml7%2FbtsLBy4yoZD%2FUoEtjJcFPjZXs4V7VkV5hK%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;748&quot; height=&quot;775&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;775&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;85&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RJrZf/btsLAwzDg5D/NKKcI5kywwyc8xIZz3cQEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RJrZf/btsLAwzDg5D/NKKcI5kywwyc8xIZz3cQEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RJrZf/btsLAwzDg5D/NKKcI5kywwyc8xIZz3cQEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRJrZf%2FbtsLAwzDg5D%2FNKKcI5kywwyc8xIZz3cQEK%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;738&quot; height=&quot;85&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;85&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;두 테이블의 ID를 기준으로 병합한 뒤 입양 테이블이 NULL인 행 중에 날짜가 가장 오래된 것 3개만 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckXTIO/btsLCFhKRcW/LKXn49yhGjpoorhbV6zCI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckXTIO/btsLCFhKRcW/LKXn49yhGjpoorhbV6zCI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckXTIO/btsLCFhKRcW/LKXn49yhGjpoorhbV6zCI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckXTIO%2FbtsLCFhKRcW%2FLKXn49yhGjpoorhbV6zCI1%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;807&quot; height=&quot;231&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WITH temp AS (
    SELECT ai.NAME, ai.DATETIME
    FROM ANIMAL_INS ai LEFT JOIN ANIMAL_OUTS ao on ai.ANIMAL_ID = ao.ANIMAL_ID
    WHERE ao.DATETIME IS NULL
    ORDER BY 2
    limit 3
)
SELECT NAME, DATETIME
FROM temp
ORDER BY 2 ASC;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DB/Programmers SQL</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/190</guid>
      <comments>https://yatanox.tistory.com/190#entry190comment</comments>
      <pubDate>Tue, 31 Dec 2024 13:34:07 +0900</pubDate>
    </item>
    <item>
      <title>1. SQL 처리 과정과 I/O [3/3]</title>
      <link>https://yatanox.tistory.com/188</link>
      <description>&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;1.3 데이터 저장 구조 및 I/O 메커니즘&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3.1 SQL이 느린 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분은 I/O 문제이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2292&quot; data-origin-height=&quot;1247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CIHQY/btsLvUM8PXS/tsk47kDDTqUYJXHL0k74qK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CIHQY/btsLvUM8PXS/tsk47kDDTqUYJXHL0k74qK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CIHQY/btsLvUM8PXS/tsk47kDDTqUYJXHL0k74qK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCIHQY%2FbtsLvUM8PXS%2Ftsk47kDDTqUYJXHL0k74qK%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;2292&quot; height=&quot;1247&quot; data-origin-width=&quot;2292&quot; data-origin-height=&quot;1247&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;blockquote data-ke-style=&quot;style3&quot;&gt;I/O란 입출력을 뜻하는 말로 입출력 동안에는 프로세스가 잠을 잔다.&lt;br /&gt;프로세스가 일하지 않고 자는 이유는 여러가지가 있지만 가장 대표적인 이유는 I/O다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2021&quot; data-origin-height=&quot;1488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pvrvW/btsLtKkWX38/BpkiV1zr54S8LolQ6SHYp0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pvrvW/btsLtKkWX38/BpkiV1zr54S8LolQ6SHYp0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pvrvW/btsLtKkWX38/BpkiV1zr54S8LolQ6SHYp0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpvrvW%2FbtsLtKkWX38%2FBpkiV1zr54S8LolQ6SHYp0%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;2021&quot; height=&quot;1488&quot; data-origin-width=&quot;2021&quot; data-origin-height=&quot;1488&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2320&quot; data-origin-height=&quot;1163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhA3Bx/btsLvJEVDbZ/7UWIwIEXPqcVGKU8zKzy21/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhA3Bx/btsLvJEVDbZ/7UWIwIEXPqcVGKU8zKzy21/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhA3Bx/btsLvJEVDbZ/7UWIwIEXPqcVGKU8zKzy21/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhA3Bx%2FbtsLvJEVDbZ%2F7UWIwIEXPqcVGKU8zKzy21%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;2320&quot; height=&quot;1163&quot; data-origin-width=&quot;2320&quot; data-origin-height=&quot;1163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성 이후로 종료 전까지 준비와 실행, 대기 상태를 반복한다. 실행 중인 프로세스는 수시로 인터럽트로 인해 준비 상태로 전환 했다가 다시 실행 상태로 전환되고는 한다. 여러 프로세스가 한 CPU를 공유할 수는 있지만 특정 순간에는 한 프로세스만 사용할 수 있기 때문에 해당 메커니즘이 필요하다.&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;인터럽트가 없었던, 열심히 일하던 프로세스도 디스크에서 데이터를 잃어야 할 땐 CPU를 OS에 반환하고 잠시 대기 상태에서 I/O가 완료되길 기다린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정해진 OS 함수를 호출해 CPU를 반환한 채 대기 큐에서 잠을 자는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O가 많으면 필연적으로&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;2879&quot; data-origin-height=&quot;1135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAxZqo/btsLwtatd3k/RkK2fXcRiErJ0m7kl6C5K0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAxZqo/btsLwtatd3k/RkK2fXcRiErJ0m7kl6C5K0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAxZqo/btsLwtatd3k/RkK2fXcRiErJ0m7kl6C5K0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAxZqo%2FbtsLwtatd3k%2FRkK2fXcRiErJ0m7kl6C5K0%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;2879&quot; height=&quot;1135&quot; data-origin-width=&quot;2879&quot; data-origin-height=&quot;1135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O Call의 속도는 Single Block을 기준으로 평균 10ms 정도 된다. 초당 100 블록을 읽는 셈이다. (큰 캐시 스토리지는 좀 더 빠르다.) 스토리지 성능은 계속 빨라지고 있지만 아직 우리 기대에는 못 미친다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O 메커니즘을 알기전에 데이터베이스 저장 구조부터 확인해보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3.2 데이터베이스 저장 구조&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2701&quot; data-origin-height=&quot;1919&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKlMts/btsLttKgfLk/fFbj7H9HKm2FPZF7SLLFc1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKlMts/btsLttKgfLk/fFbj7H9HKm2FPZF7SLLFc1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKlMts/btsLttKgfLk/fFbj7H9HKm2FPZF7SLLFc1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKlMts%2FbtsLttKgfLk%2FfFbj7H9HKm2FPZF7SLLFc1%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;2701&quot; height=&quot;1919&quot; data-origin-width=&quot;2701&quot; data-origin-height=&quot;1919&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터를 저장하기 위해서는 먼저 테이블 스페이스를 생성해야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 스페이스는 세그먼트를 담는 콘테이너로서, 여러 개의 데이터파일(디스크 상 물리적인 OS파일)로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 테이블 스페이스를 생성했으면, 세그먼트를 생성한다. 세그먼트는 테이블이나 인덱스처럼 데이터 저장공간이 필요한 오브제그로 테이블, 인덱스를 생성할 때 데이터를 어떤 테이블스페이스에 저장할지를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 세그먼트는 여러 익스텐트로 구성되며, 파티션 구조가 아닌 이상 테이블도 하나의 세그먼트요, 인덱스도 하나의 세그먼트다. 파티션 구조라면 각 파티션이 하나의 세그먼트가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스텐트는 공간을 확장하는 단위로, 데이터를 입력하다가 공간이 부족해지면 오브젝트가 속한 테이블 스페이스로부터 익스텐트를 추가로 할당받는다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세그먼트와 익스텐트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세그먼트는 데이터베이스에서 논리적인 구조를 나타낸다. 이는 테이블이나 인덱스 등을 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 하나의 테이블은 하나의 세그먼트로 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스텐트는 데이터베이스 세그먼트의 물리적인 공간을 의미한다. 하나의 익스텐트는 여러 블록으로 구성될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세그먼트에 데이터를 추가할 때 익스텐트를 할당하고 추가적인 공간이 필요할 때 익스텐트를 추가 할당하여 데이터 공간이 확장하는 식.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세그먼트는&amp;nbsp;데이터베이스의&amp;nbsp;논리적&amp;nbsp;구조를&amp;nbsp;나타내며,&amp;nbsp;특정&amp;nbsp;객체(예:&amp;nbsp;테이블,&amp;nbsp;인덱스&amp;nbsp;등)를&amp;nbsp;포함합니다.&lt;br /&gt;익스텐트는&amp;nbsp;세그먼트의&amp;nbsp;물리적&amp;nbsp;저장소&amp;nbsp;단위로,&amp;nbsp;연속된&amp;nbsp;블록의&amp;nbsp;집합입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스텐트 단위로 공간을 확장하게 되지만, 사용자가 입력한 레코드를 실제로 저장하는 공간은 데이터 블록 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;특정 DBMS에서는 블록 대신 페이지라는 용어를 사용하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 블록은 하나의 테이블이 독점한다. 즉 한 블록의 레코드들은 모두 같은 테이블의 레코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 익스텐트도 하나의 테이블이 독점한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세그먼트 공간이 부족해지면 테이블 스페이스로부터 익스텐트를 추가 할당받는데 한 세그먼트의 모든 익스텐트가 같은 데이터 파일에 위치하지 않을 수 있다. 하나의 테이블 스페이스를 여러 데이터파일로 구성하면, &lt;b&gt;파일 경합&lt;/b&gt;을 줄이기 위해&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;DBMS가 데이터를 가능한 여러 데이터파일로 분산 저장하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;2954&quot; data-origin-height=&quot;1586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djSbw2/btsLvzWWg1Q/8P5Jn8Q7KUbBZyX4EMLmnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djSbw2/btsLvzWWg1Q/8P5Jn8Q7KUbBZyX4EMLmnK/img.jpg&quot; data-alt=&quot;익스텐트 내 블록은 인접한 연속 공간이지만, 익스텐트 끼리는 연속된 공간이 아니라는 걸 알 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djSbw2/btsLvzWWg1Q/8P5Jn8Q7KUbBZyX4EMLmnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjSbw2%2FbtsLvzWWg1Q%2F8P5Jn8Q7KUbBZyX4EMLmnK%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;2954&quot; height=&quot;1586&quot; data-origin-width=&quot;2954&quot; data-origin-height=&quot;1586&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;익스텐트 내 블록은 인접한 연속 공간이지만, 익스텐트 끼리는 연속된 공간이 아니라는 걸 알 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오라클 상의 세그먼트에 할당된 익스텐트 목록 조회.&lt;/p&gt;
&lt;pre id=&quot;code_1735019083075&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT segment_type, tablespace_name, extent_id, file_id, block_id, blocks
FROM dba_extents
WHERE owner = USER AND segment_name = 'MY_SEGMENT'
ORDER BY extent_id;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;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;익스텐트 : 공간을 확장하는 단위, 연속된 블록의 집합&lt;/li&gt;
&lt;li&gt;세그먼트 : 데이터 저장 공간이 필요한 오브젝트&amp;nbsp;&lt;/li&gt;
&lt;li&gt;테이블스페이스 : 세그먼트를 담는 컨테이너&lt;/li&gt;
&lt;li&gt;데이터파일 : 디스크 상의 물리적인 OS 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들 간 관계 ERD&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2819&quot; data-origin-height=&quot;961&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXmlrc/btsLwnVPX7j/BYkZTcqeD7xhWfTFqQc9g1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXmlrc/btsLwnVPX7j/BYkZTcqeD7xhWfTFqQc9g1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXmlrc/btsLwnVPX7j/BYkZTcqeD7xhWfTFqQc9g1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXmlrc%2FbtsLwnVPX7j%2FBYkZTcqeD7xhWfTFqQc9g1%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;2819&quot; height=&quot;961&quot; data-origin-width=&quot;2819&quot; data-origin-height=&quot;961&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;h4 data-ke-size=&quot;size20&quot;&gt;1.3.3. 블록 단위 I/0&lt;/h4&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;2255&quot; data-origin-height=&quot;774&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q3gaN/btsLu2SH6TT/viiWZ58kOsaebd2uI7bmC0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q3gaN/btsLu2SH6TT/viiWZ58kOsaebd2uI7bmC0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q3gaN/btsLu2SH6TT/viiWZ58kOsaebd2uI7bmC0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ3gaN%2FbtsLu2SH6TT%2FviiWZ58kOsaebd2uI7bmC0%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;2255&quot; height=&quot;774&quot; data-origin-width=&quot;2255&quot; data-origin-height=&quot;774&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;2049&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IS1vV/btsLuJy4gUV/KdyhZV91otHlUAE22wmWm0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IS1vV/btsLuJy4gUV/KdyhZV91otHlUAE22wmWm0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IS1vV/btsLuJy4gUV/KdyhZV91otHlUAE22wmWm0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIS1vV%2FbtsLuJy4gUV%2FKdyhZV91otHlUAE22wmWm0%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;2049&quot; height=&quot;649&quot; data-origin-width=&quot;2049&quot; data-origin-height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 단위나 테이블 세그먼트 단위로 읽는건 상상하기 어렵다. 데이터 I/O 단위가 블록이므로 블록이 바로 DBMS가 데이터를 읽고 쓰는 단위이다. 특정 레코드 하나를 읽으려 해도 블록을 통째로 읽는다. 심지어 1바이트짜리를 컬럼 하나만 읽으려해도 블록을 통째로 읽는다.&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;아래의 사진은 EMP 테이블에 데이터가 저장된 모습을 표현한다.&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;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be53Jf/btsLuwmwQfO/uye5z6uR1mIxItGOKNldHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be53Jf/btsLuwmwQfO/uye5z6uR1mIxItGOKNldHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be53Jf/btsLuwmwQfO/uye5z6uR1mIxItGOKNldHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe53Jf%2FbtsLuwmwQfO%2Fuye5z6uR1mIxItGOKNldHk%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;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&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;오라클 기준으로 1바이트를 읽기 위해 8KB를 읽는 셈이다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;1624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BeOw0/btsLuI739Os/61QKnBKkI7KAOkcoAjCF9K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BeOw0/btsLuI739Os/61QKnBKkI7KAOkcoAjCF9K/img.jpg&quot; data-alt=&quot;인덱스 구조에 대한 설명은 2장에서 다시 설명한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BeOw0/btsLuI739Os/61QKnBKkI7KAOkcoAjCF9K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBeOw0%2FbtsLuI739Os%2F61QKnBKkI7KAOkcoAjCF9K%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;2252&quot; height=&quot;1624&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;1624&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인덱스 구조에 대한 설명은 2장에서 다시 설명한다.&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;1.3.4 시퀀셜 엑세스 VS 랜덤 엑세스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 혹은 인덱스 블록을 액세스하는 방식은 시퀀셜 엑세스와 랜덤 엑세스로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 시퀀셜 엑세스&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;2452&quot; data-origin-height=&quot;1712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deqIBH/btsLuNarRWt/2kyrm64YT7GgEcJ6aftk41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deqIBH/btsLuNarRWt/2kyrm64YT7GgEcJ6aftk41/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deqIBH/btsLuNarRWt/2kyrm64YT7GgEcJ6aftk41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeqIBH%2FbtsLuNarRWt%2F2kyrm64YT7GgEcJ6aftk41%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;2452&quot; height=&quot;1712&quot; data-origin-width=&quot;2452&quot; data-origin-height=&quot;1712&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;/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 data-ke-size=&quot;size16&quot;&gt;즉, 읽어야할 익스텐트 목록을 익스텐트 맵에서 얻고 각 익스텐트 첫 블록 뒤에 연속해서 저정된 블록을 읽으면 그것이 &lt;b&gt;Full Table Scan&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 랜덤 엑세스&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;h4 data-ke-size=&quot;size20&quot;&gt;1.3.5 논리적 I/O VS 물리적 I/O&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DB 버퍼 캐시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강조하자면, 디스크 I/O가 SQL의 성능을 결정한다. 자주 읽는 블록을 매번 디스크에서 읽는 건 매우 비효율적이다. DBMS에 데이터 캐싱 메커니즘이 필수인 이유이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2684&quot; data-origin-height=&quot;1180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IvI0D/btsLuXjEawF/48FCYtPhutohk46uzkCtmk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IvI0D/btsLuXjEawF/48FCYtPhutohk46uzkCtmk/img.jpg&quot; data-alt=&quot;데이터 버퍼 캐시로 SGA의 중요 구성요소 중 하나이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IvI0D/btsLuXjEawF/48FCYtPhutohk46uzkCtmk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIvI0D%2FbtsLuXjEawF%2F48FCYtPhutohk46uzkCtmk%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;2684&quot; height=&quot;1180&quot; data-origin-width=&quot;2684&quot; data-origin-height=&quot;1180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데이터 버퍼 캐시로 SGA의 중요 구성요소 중 하나이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크에서 어렵게 읽은 데이터 블록을 캐싱해 둠으로서 같은 블록에 대한 반복적인 I/O를 줄이는 목적을 가진 것이 DB 버퍼 캐시 되시겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3013&quot; data-origin-height=&quot;1293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clIGZm/btsLvzW3FHm/6nFs4ZKbH503AaIRuME9Nk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clIGZm/btsLvzW3FHm/6nFs4ZKbH503AaIRuME9Nk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clIGZm/btsLvzW3FHm/6nFs4ZKbH503AaIRuME9Nk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclIGZm%2FbtsLvzW3FHm%2F6nFs4ZKbH503AaIRuME9Nk%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;3013&quot; height=&quot;1293&quot; data-origin-width=&quot;3013&quot; data-origin-height=&quot;1293&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;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오라클 SQL*PLUS 상에서 버퍼캐시 사이즈를 확인하는 쉬운 방법&lt;/p&gt;
&lt;pre id=&quot;code_1735020475642&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW sga&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;논리적 I/O vs 물리적 I/O&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 블록 I/O는 SQL을 처리하는 과정에서 발생한 총 블록 I/O를 말한다. 메모리상의 버퍼 캐시를 경유하므로 메모리 I/O 가 곧 논리적 I/O 라고 해도 무방하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물리적 I/O는 디스크에서 발생한 총 블록 I/O를 말한다. SQL 처리 중 버퍼 캐시에서 읽어야할 블록을 못찾았을 때만 디스크 액세스하므로 논리적 블록 I/O 중 일부를 물리적 I/O 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2631&quot; data-origin-height=&quot;1219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zwY70/btsLuFXK1hF/Zv7UsiKM0ix6qnuFHrLS1k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zwY70/btsLuFXK1hF/Zv7UsiKM0ix6qnuFHrLS1k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zwY70/btsLuFXK1hF/Zv7UsiKM0ix6qnuFHrLS1k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzwY70%2FbtsLuFXK1hF%2FZv7UsiKM0ix6qnuFHrLS1k%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;2631&quot; height=&quot;1219&quot; data-origin-width=&quot;2631&quot; data-origin-height=&quot;1219&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;b&gt;왜 논리적 I/O인가?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 베이스 세계에서 논리적 일량과 물리적 일량을 정의해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL을 수행하려면 데이터가 담긴 블록을 읽어야한다. 데이터를 입력하거나 삭제하지 않는다면 같은 상황에서 아무리 여러 번 실행해도 매번 읽는 블록 수는 같다. SQL을 수행하면서 읽은 총 블록 I/O가 논리적 I/O이다.&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;Direct Path Read 방식으로 읽는 경우가 아니면 모든 블록은 DB 버퍼 캐시를 경유한다. 따라서 대부분 논리적 I/O 횟수는 DB 버퍼캐시에서 블록을 읽는 횟수와 일치한다.&amp;nbsp; 같은 개념은 아니지만 결과적으로 수치는 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 버퍼캐시에서 블록을 못찾아 디스크에서 읽은 블록 I/O가 물리적 I/O이다. 이는 입력이나 삭제가 없더라도 SQL을 실행할 때마다 다르다. 연속 실행 시 DB 버퍼 캐시의 데이터 블록 점유율이 높아지기 때문이다. 반대로 한참 뒤에 실행하면 점유율은 내려간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;버퍼캐시 히트율&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 많이 사용하는 지표는 BCHR이다. (Buffer Cache Hit Ratio)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BCHR = 전체 블록 중 물리적인 디스크 I/O를 수반하지 않은, 메모리에서 찾은 비율.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;= (캐시에서 곧바로 찾은 블록 수 / 총 읽은 블록 수) * 100&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;= ((논리적 I/O - 물리적 I/O0 / 논리적 I/O) * 100)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;= (1 - (물리적 I/O / 논리적 I/O) * 100)&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;b&gt;실제 SQL 성능을 향상하려면 물리적 I/O가 아닌 논리적 I/O를 줄여야함을 알 수 있다.&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;그렇다면 논리적 I/O는 어떻게 줄일 수 있을까? SQL 튜닝을 통해 읽는 블록 자체를 줄이면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 I/O를 줄임으로 물리적 I/O를 줄이는 것이 곧 SQL 튜닝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;BHCR에는 주의해야할 함정이 있다. BHCR이 SQL 성능을 좌우하지만 높다고 해서 효율적인 SQL을 의미하진 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;같은 블록을 비효율적으로 반복해서 읽으면 BHCR이 높아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3.6 Single Block I/O VS Multi Block I/O&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 캐시가 클수록 좋지만, 모든 데이터를 캐시에 적재할 순 없다. 여러 한계 때문에 일부만 캐시에 적재해서 읽을 수 있다. 캐시에서 못 찾은 블록은 I/O CALL을 통해 디스크에서 버퍼캐시에 적재하고 읽는다. 한 번에 한 블록만 요청하기도 하고 여러 블록을 요청하기도 한다. &lt;b&gt;한 번에 한 블록만 요청해서 적재하는 방식을 Single Block I/O&lt;/b&gt;라고 한다. 반대로 &lt;b&gt;여러 블록을 요청해서 적재하는 방식을 Multi Block I/O&lt;/b&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;1853&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezPqje/btsLvyqpl2U/MPQyeIutLOJJY6ZlwNWiIk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezPqje/btsLvyqpl2U/MPQyeIutLOJJY6ZlwNWiIk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezPqje/btsLvyqpl2U/MPQyeIutLOJJY6ZlwNWiIk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezPqje%2FbtsLvyqpl2U%2FMPQyeIutLOJJY6ZlwNWiIk%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;1853&quot; height=&quot;756&quot; data-origin-width=&quot;1853&quot; data-origin-height=&quot;756&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 이용할 땐 보통 인덱스와 테이블 블록 모두 Single Block 방식을 이용한다.&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;li&gt;인덱스 리프 블록에서 얻은 주소 정보로 테이블 블록을 읽을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1693&quot; data-origin-height=&quot;1417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyqBQ/btsLwKDlNh7/QVYNlTYJWovO6qy1zrQhH0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyqBQ/btsLwKDlNh7/QVYNlTYJWovO6qy1zrQhH0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyqBQ/btsLwKDlNh7/QVYNlTYJWovO6qy1zrQhH0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyqBQ%2FbtsLwKDlNh7%2FQVYNlTYJWovO6qy1zrQhH0%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;1693&quot; height=&quot;1417&quot; data-origin-width=&quot;1693&quot; data-origin-height=&quot;1417&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;반대로 많은 데이터 블록을 읽을 땐 Multi Block I/O 방식이 효율적이다. 그래서 인덱스를 이용하지 않고 테이블 전체를 스캔할 때 이 방식이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽고자 하는 블록을 DB 버퍼 캐시에서 찾지 못하면 해당 블록을 디스크에서 읽기 위해 I/O Call한다. 그 동안 프로세스는 대기 큐에서 잠을 잔다. 대용량이라면 수많은 블록을 읽는 동안 여러 번 잠을 잘텐데, 기왕에 대기 상태가 된다면 한 번에 많은 양을 요청해야 성능을 높일 수 있다.&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;정리하면 Multi Block I/O는 캐시에서 찾지 못한 특정 블록을 읽으려 I/O Call 할 때 디스크 상에서 그 블록과 인접한 블록들을 한꺼번에 읽어 캐시에 미리 적재하는 기능이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;오라클 상에서 Multi Blcok I/O 설정량은 show db_file_multiblock_read_count 파라미터로 정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀더 부연하자면 인접한 블록이란 같은 익스텐트에 속한 블록을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3.7 Table Full Scan VS Index Range Scan&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방식은 테이블에 저장된 데이터를 읽는 방식이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 전체를 스캔해서 읽는 방식이 Table Full Scan, 인덱스를 이용해서 읽는 방식이 Index Range Scan이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말그대로 테이블에 속한 블록 전체를 읽어 데이터를 찾는 방식과 인덱스에서 일정량 스캔해서 얻은 ROWID로 테이블 레코드를 찾아가는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;ROWID는 테이블 레코드가 디스크 상에서 어디 저장됐는지 가리키는 위치 정보.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;많은 개발자가 실행 계획 분석시 Table Full Scan 찾기를 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Table Full Scan 찾기식 실행 계획 분석은 실제 SQL 성능을 향상하는데 큰 도움이되지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 이용해하는 상황에 Table Full Scan을 해서 해결해야하는 상황도 있어 의미가 없다고는 못하지만 인덱스가 SQL 성능을 떨어뜨리는 경우도 많다.(집계용 SQL과 배치 프로그램 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 사용하는데 왜 성능이 더 느릴까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Table Full Scan은 시퀀셜 액세스와 Multi Block I/O 방식으로 디스크 블록을 읽는다. 한 블록에 속한 모든 레코드를 한 번에 읽고 캐시에서 못 찾으면 한 번의 I/O Call을 통해 인접한 수많은 블록을 한꺼번에 I/O한다. 이 방식을 사용하는 SQL은 스토리지 스캔 성능이 좋아지는 만큼 성능도 좋아진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKrvIW/btsLw2jA0w1/Q6jKZznjxyrUZjZ1PRfs4K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKrvIW/btsLw2jA0w1/Q6jKZznjxyrUZjZ1PRfs4K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKrvIW/btsLw2jA0w1/Q6jKZznjxyrUZjZ1PRfs4K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKrvIW%2FbtsLw2jA0w1%2FQ6jKZznjxyrUZjZ1PRfs4K%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;2420&quot; height=&quot;1402&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1402&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;시퀀셜 액세스와 Multi Block가 아무리 좋아도 소량 데이터를 찾을 때 스캔하는건 비효율적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 테이블에서 소량 데이터를 검색할 땐 인덱스를 활용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index Range Scan을 통한 테이블 액세스는 랜덤 액세스와 Single Block I/O 방식으로 디스크 블록을 읽는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시에서 못 찾으면 레코드 하나를 읽기 위해 매번 잠을 자는 I/O 매커니즘이다. 즉, 많은 데이터를 읽을 때는 Table Full Scan보다 불리하다. 또한 읽은 블록을 반복 읽기하는 비효율도 있다.&amp;nbsp;&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;1.3.8 캐시 탐색 메커니즘&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Direct Path I/O를 제외한 모든 블록 I/O는 메모리 버퍼 캐시를 경유한다 했다.&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;/li&gt;
&lt;li&gt;인덱스 루트 블록에서 얻은 주소 정보로 브랜치 블록을 읽을 때&lt;/li&gt;
&lt;li&gt;인덱스 브랜치 블록에서 얻은 주소 정보로 리프 블록을 읽을 때&lt;/li&gt;
&lt;li&gt;인덱스 리프 블록에서 얻은 주소 정보로 테이블 블록을 읽을 때&lt;/li&gt;
&lt;li&gt;테이블 블록을 Full Scan 할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2452&quot; data-origin-height=&quot;1798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuqdgs/btsLvxrJj1s/ePr3mclakYGrfMhmUHvbaK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuqdgs/btsLvxrJj1s/ePr3mclakYGrfMhmUHvbaK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuqdgs/btsLvxrJj1s/ePr3mclakYGrfMhmUHvbaK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcuqdgs%2FbtsLvxrJj1s%2FePr3mclakYGrfMhmUHvbaK%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;2452&quot; height=&quot;1798&quot; data-origin-width=&quot;2452&quot; data-origin-height=&quot;1798&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버커 캐시 구조부터 보자. DBMS는 버퍼캐시를 위 그럼처럼 해시 구조로 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 해시 함수로 모듈러 함수를 사용하는 경우를 예로하고 있다. 만약 20번 블록을 찾고자한다면&amp;nbsp; 블록번호를 5로 나누면 나머지가 0이다. 이 블록이 캐싱되어 있다면 버퍼 헤더가 첫 번째 헤시 체인에 연결되어 있을 것이고 찾을 때 첫 해시 체인만 탐색하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 버퍼 캐시에서 블록을 찾을 때 해시 알고리즘으로 버퍼 헤더를 찾고 거기서 얻은 포인터로 버퍼 블록을 액세스한다.&lt;/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 공유자원에 대한 액세스 직렬화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼 캐시는 SGA 구성요소이므로 캐싱된 버퍼블록은 모두 공유자원이다. 즉, 누구나 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 하나의 버퍼블록을 두 개 이상의 프로세스가 '동시에' 접근할 때이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시 접근 시 블록 정합성에 문제가 생길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 자원을 공유하더라도 한 프로세스씩 순차 접근하도록 구현해야하며, 직렬화 메커니즘이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유캐시의 특정 자원이 두 개 이상의 프로세스가 같이 사용할 수 있나? 같이 사용하는 것처럼 보이지만, 특정 순간에는 한 프로세스만 사용할 수 있다. 그 순간 다른 프로세스는 기다려야한다. 이런 줄서기가 가능하게 지원하는 메커니즘이 래치(Latch)이다.&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;간단하게 위 사진에서 0부터 4까지 다섯 체인 앞쪽에 자물쇠가 있다고 생각하면 된다.&amp;nbsp; 키를 가진 프로세스만 체인으로 진입할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SGA를 구성하는 서브 캐시마다 별도의 래치를 가지는데, 버퍼캐시엔 캐시버퍼 체인 래치, 캐시버퍼 LRU 체인 래치 등이 작동한다. 캐시버퍼 체인뿐 아니라 버퍼블록 자체에도 버퍼 Lock이라는 직렬화 메커니즘이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이런 직렬화 메커니즘에 의한 캐시 경합을 줄이려면 튜닝을 통한 쿼리 일량 자체를 줄여야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB/SQL 튜닝</category>
      <category>sqlp 준비 학습</category>
      <category>친절한 SQL 튜닝</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/188</guid>
      <comments>https://yatanox.tistory.com/188#entry188comment</comments>
      <pubDate>Mon, 23 Dec 2024 16:22:23 +0900</pubDate>
    </item>
    <item>
      <title>1. SQL 처리 과정과 I/O [2/3]</title>
      <link>https://yatanox.tistory.com/187</link>
      <description>&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;1.2 SQL 공유 및 재사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트 파싱과 하드 파싱의 차이점을 알아보고, 동시성이 높은 온라인 트랙잭션 처리 시스템에서 바인드 변수가 왜 중요한지 이해해보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2.1 소프트 파싱 vs 하드 파싱&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 파싱, 최적화, 로우 소스 코드 생성 과정을 거쳐 생성한 내부 프로시저를 반복 재사용할 수 있게 캐싱해 두는 메모리 공간을 라이브러리 캐시라고 한다. (SGA 구성요소)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1985&quot; data-origin-height=&quot;1051&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H1uvw/btsLt5uqPqq/Wg3zH0qxdGQYC4AanpOyzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H1uvw/btsLt5uqPqq/Wg3zH0qxdGQYC4AanpOyzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H1uvw/btsLt5uqPqq/Wg3zH0qxdGQYC4AanpOyzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH1uvw%2FbtsLt5uqPqq%2FWg3zH0qxdGQYC4AanpOyzK%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;1985&quot; height=&quot;1051&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1985&quot; data-origin-height=&quot;1051&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;사용자가 SQL문을 전달하면 DBMS는 SQL을 파싱 후 해당 SQL 라이브러리 캐시에 존재하는 지 확인한다. 캐시를 찾으면 바로 실행 단계로 넘어가지만, 찾지 못하면 최적한 단계를 거친다. 캐시를 찾아 바로 실행하는 것을 소프트 파싱&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-filename=&quot;blob&quot; data-origin-width=&quot;2447&quot; data-origin-height=&quot;916&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhQbaI/btsLtt97IE7/SNvUHqP3Y0Udj9k4OTNlKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhQbaI/btsLtt97IE7/SNvUHqP3Y0Udj9k4OTNlKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhQbaI/btsLtt97IE7/SNvUHqP3Y0Udj9k4OTNlKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhQbaI%2FbtsLtt97IE7%2FSNvUHqP3Y0Udj9k4OTNlKK%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;2447&quot; height=&quot;916&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2447&quot; data-origin-height=&quot;916&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;h4 data-ke-size=&quot;size20&quot;&gt;1.2.2 바인드 변수의 중요성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 이름없는 SQL 문제&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 정의 함수/프로시저, 트리거 등은 생성할 때 부터 이름을 갖는다. 컴파일 상태로 딕셔너리에 저장되며 사용자가 제거하지 않는 이상 영구적 보관된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 SQL은 이름이 따로 없다. SQL 전체 텍스트가 이름 역할을 한다. 딕셔너리에 저장도 않는다. 첫 실행 때 최적화 과정에서 동적으로 생성한 내부 프로시저를 라이브러리 캐시에 적재함으로 공유하고 재사용한다. 공간이 부족할 경우 제거했다가 다음 실행 때 다시 최적화 과정을 거쳐 캐시에 적재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 SQL을 영구 저장하지 않을까? IBM DB2 같은 DBMS는 영구 저장하고 있다. 왜 오라클, SQL Server 같은 DBMS는 그렇게 하지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하자면, SQL은 자체가 이름이기 때문에 작은 부분이라도 수정되면 다른 객체가 새로 탄생하는 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS에서 수행되는 SQL이 모두 완성된 SQL은 아니며, 개발 과정에서는 수시로 변경이 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일회성 쿼리도 많다. 그 모두를 저장하려면 많은 공간이 필요하며, 그만큼 속도도 느려진다. 오라클 등의 DBMS가 영구 저장을 하지 않는 쪽을 선택한 이유이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 의미적으로는 모두 같지만, 실행 시 각각 최적화를 진행하고 라이브러리 캐시에 별도 공간을 차지하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1734937938924&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM emp WHERE empno = 7900;
select * from EMP where EMPNO = 7900;
select * from emp where empno = 7900;
select * FROM emp WHERE empno = 7900;
select * FROM emp where empno = 7900   ;
select * FROM scott.emp WHERE empno = 7900;&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 data-ke-size=&quot;size16&quot;&gt;또한 이렇게 직성하면, 조회를 진행할 때마다 내부 프로시저를 하나씩만들어서 적재하는 셈이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1734938203229&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM emp WHERE empno = 7900;
SELECT * FROM emp WHERE empno = 7500;
SELECT * FROM emp WHERE empno = 7400;
SELECT * FROM emp WHERE empno = 7680;
SELECT * FROM emp WHERE empno = 7980;
SELECT * FROM emp WHERE empno = 4400;&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;위 SQL의 프로시저 내부 처리 루틴은 모두 같다. 그렇다면 프로시저를 여러 개 생성할 것이 아니라 empno을 파라미터로 받는 프로시저 하나를 공유하면서 재사용하는 것이 더 마땅하다.&lt;/p&gt;
&lt;pre id=&quot;code_1734938378272&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create proceduce Search (empno in int) {****}&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;위 처럼 파라미터 Driven 방식으로 SQL을 작성하는 방법이 바인드 변수이다.&lt;/p&gt;</description>
      <category>DB/SQL 튜닝</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/187</guid>
      <comments>https://yatanox.tistory.com/187#entry187comment</comments>
      <pubDate>Mon, 23 Dec 2024 15:32:37 +0900</pubDate>
    </item>
    <item>
      <title>1. SQL 처리 과정과 I/O [1/3]</title>
      <link>https://yatanox.tistory.com/186</link>
      <description>&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;1.1 SQL 파싱과 최적화&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1.1&amp;nbsp; 구조적, 집합적, 선언적 질의 언어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL은 Structured Query Language 의 줄임말이다. 그대로 구조적 질의 언어라 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL is designed for a specific purpose : to query data contained in a relational database.&lt;/li&gt;
&lt;li&gt;SQL is set-based, declarative query language, not an imperative language such as C or BASIC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오라클 PL/SQL, SQL Server T-SQL 처럼 절차적인 프로그래밍 기능을 구현 할 수 있는 확장 언어도 제공하지만, SQL은 기본적으로 구조적이고, 집합적이며, 선언적인 질의 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그러나 그 결과 집합을 만드는 과정은 절차적일 수 밖에 없다. 즉, ※&lt;b&gt;프로시저&lt;/b&gt;가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;DB&lt;/span&gt;에 대한 일련의 작업을 정리한 절차를 관계형 데이터베이스 관리 시스템에 저장한 것&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;넓은 의미로 어떠한 업무를 수행하기 위한&lt;u&gt;절차&lt;/u&gt;를 뜻한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿼리문을 하나의 메서드 형식으로 만들고 어떤 동작을 일괄적으로 처리하는 용도로 쓰인다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 인용&lt;/p&gt;
&lt;figure id=&quot;og_1734932137822&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;[IT지식] 프로시저(PROCEDURE)란?&quot; data-og-description=&quot; 프로시저란 - DB 에 대한 일련의 작업을 정리한 절차를 관계형 데이터베이스 관리 시스템에 저장한 것이다. - 넓은 의미로 어떠한 업무를 수행하기 위한 절차를 뜻한다. - 쿼리문을 하나의 메&quot; data-og-host=&quot;seohee-ha.tistory.com&quot; data-og-source-url=&quot;https://seohee-ha.tistory.com/125&quot; data-og-url=&quot;https://seohee-ha.tistory.com/125&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b6U9pa/hyXSwFCfDM/EJ2Rfck0qa0XmkkxKXk3N0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/qy7Ft/hyXSyDrw9B/LZjvpem1l21d8vGAV8euw1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Agjm3/hyXOdubjzt/zsNerfh3fyvnk8JZnoLd80/img.jpg?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080&quot;&gt;&lt;a href=&quot;https://seohee-ha.tistory.com/125&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://seohee-ha.tistory.com/125&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b6U9pa/hyXSwFCfDM/EJ2Rfck0qa0XmkkxKXk3N0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/qy7Ft/hyXSyDrw9B/LZjvpem1l21d8vGAV8euw1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Agjm3/hyXOdubjzt/zsNerfh3fyvnk8JZnoLd80/img.jpg?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080');&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;[IT지식] 프로시저(PROCEDURE)란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; 프로시저란 - DB 에 대한 일련의 작업을 정리한 절차를 관계형 데이터베이스 관리 시스템에 저장한 것이다. - 넓은 의미로 어떠한 업무를 수행하기 위한 절차를 뜻한다. - 쿼리문을 하나의 메&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;seohee-ha.tistory.com&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;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 프로시저를 만들어 내는 DBMS 내부 엔진이 바로 SQL 옵티마이저이다. 프로그래밍을 대신해 주는 셈이다.&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;1318&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ptmc7/btsLrKrpXGN/aKKfYsSfzdKLbkw8dUWank/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ptmc7/btsLrKrpXGN/aKKfYsSfzdKLbkw8dUWank/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ptmc7/btsLrKrpXGN/aKKfYsSfzdKLbkw8dUWank/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fptmc7%2FbtsLrKrpXGN%2FaKKfYsSfzdKLbkw8dUWank%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;1318&quot; height=&quot;439&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;439&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;DBMS 내부에서 프로시저를 작성하고 컴파일하여 실행 가능한 상태로 만드는 모든 과정을 'SQL 최적화'라 한다.&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;1.1.2 SQL 최적화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 실행 전 최적화 과정을 세분화 하면 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;SQL 파싱
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자로부터 SQL을 전달받으면 가장 먼저 SQL Parser가 파싱을 진행한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;파싱 트리 생성 : SQL문을 개별 구성요소로 분석해서 파싱 트리를 생성&lt;/li&gt;
&lt;li&gt;Syntax 체크 : 문법적인 오류가 없는지 확인.&lt;/li&gt;
&lt;li&gt;Semantic 체크 : 의미상 오류가 없는지 확인.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL 최적화&lt;br /&gt;이 역할을 옵티마이저(Optimizer)가 맡는다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;옵티마이저는 미리 수집한 시스템 및 오브젝트 통계정보를 바탕으로 실행경로를 생성해서 비교한 후 가장 효율적인 1개를 선택한다. Database의 성능을 결정하는 가장 핵심적인 엔진.&lt;/li&gt;
&lt;/ul&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;SQL 옵티마이저가 선택한 실행경로를 실제 실행 가능한 코드나 프로시저 형태로 포맷팅하는 단계.&lt;/li&gt;
&lt;li&gt;로우 소스 생성기(Row-Source Generator)가 그 역할을 맡는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1.3 SQL 옵티마이저&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 옵티마이저는 사용자가 원하는 작업을 가장 효율적으로 수행할 수 있는 데이터 액세스 경로를 선택해주는 DBMS 핵심 엔진이다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;옵티마이저는 백그라운드 프로세스로 이해하기 쉽지만, 별도 프로세스가 아닌 서버 프로세스가 가진 기능일 뿐이다. SQL 파서나 로우 소스 생성기로 마찬가지이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵티마이저의 최적화 단계를 요약하면 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자로부터 전달받은 쿼리를 수행하는 데 후보군이 될만한 실행 계획들을 찾아낸다.&lt;/li&gt;
&lt;li&gt;데이터 딕셔너리에 미리 수집해둔 오브젝트 통계 및 시스템 통계정보를 통해 각 실행 계획의 예상 비용을 산정한다.&lt;/li&gt;
&lt;li&gt;최저 비용을 나타내는 실행 계획을 선택한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2434&quot; data-origin-height=&quot;1124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/APZhC/btsLrvnOuTl/2TntmaRqODUBDrPKrhXqk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/APZhC/btsLrvnOuTl/2TntmaRqODUBDrPKrhXqk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/APZhC/btsLrvnOuTl/2TntmaRqODUBDrPKrhXqk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAPZhC%2FbtsLrvnOuTl%2F2TntmaRqODUBDrPKrhXqk1%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;2434&quot; height=&quot;1124&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2434&quot; data-origin-height=&quot;1124&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;h4 data-ke-size=&quot;size20&quot;&gt;1.1.4 실행 계획과 비용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 옵티 마이저를 생각할 때 자동차 네비게이션을 생각하면 여러모로 흡사하다. 경로를 검색하고 미리 확인하며, 경우에 따라서 검색모드를 변경하거나 경유지를 추가하는 등 유저가 원하는 경로를 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS에도 SQL 실행 경로 미리보기 기능이 있다. '실행 계획'이 그것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵티마이저가 생성한 처리 절차를 사용자가 확인할 수 있도록 트리 구조를 활용해 표현한 것이 실행 계획이다.&lt;/p&gt;
&lt;pre id=&quot;code_1734934311629&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT STATEMENT Optimizer=ALL_ROWS (Cost=209 Card=5 Bytes=175)
	TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=2 Card=5 Bytes=85)
		NESTED LOOPS (Cost=209 Card=5 Bytes=175)
			TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' (Cost=207 Card=1 Bytes=18)
				INDEX (RANGE SCAN) OF 'DEPT_LOC_IDX' (NON-UNIQUE) (Cost=7 Card=1)
			INDEX (RANGE SCAN) OF 'EMP_DEPTNO_IDX' (NON-UNIQUE) (Cost=1 Card=5)&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;이 미리보기를 통해 작성한 SQL이 테이블을 스캔하는지 인덱스를 스캔하는지, 어떤 인덱스를 활용하는지, 예상과 다르게 처리되는지 등을 확인하고 원한다면 변경할 수 있다.&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;1.1.5 옵티마이저 힌트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네비게이션이 보편적으로 좋은 선택을 하지만 항상 그렇진 않 듯. SQL 옵티마이저도 완벽하지는 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순 통계 정보에는 담을 수 없는 데이터나 특정 업무 특성을 활용해 개발자가 더욱 나은 액세스 경로를 찾아낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 땐 옵티마이저 힌트를 통해 데이터 엑세스 경로를 바꿀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힌트 사용법은 주석 기호에 +를 붙이는 식으로 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1734934862840&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT /*+ INDEX(A 고객_PK)*/
	고객명, 연락처, 주소, 가입일시
FROM 고객 A
WHERE 고객ID = '000000008'&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;힌트 안에 인자를 나열할 땐 ,(콤마)를 사용할 수 있지만, 힌트와 힌트 사이에는 사용하면 안된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1734935024739&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*+ INDEX(A A_X01) INDEX(B, B_XO3)*/ -&amp;gt; 모두 유효
/*+ INDEX(C), FULL(D)*/ -&amp;gt; 첫 번째만 유효&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블을 지정할 땐 스키마명까지 명시하면 안된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1734935087313&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT /*+ FULL(SCOTT.EMP)*/ -&amp;gt; 무효&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FROM 절에서 ALIAS를 지정했다면 힌트에도 반드시 사용해야한다. ALIAS를 사용했는데 힌트에 테이블 명을 입력하면 무효 처리 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2226&quot; data-origin-height=&quot;2266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo1TPC/btsLu0eNNgo/t2EQsnSHmRbD5KfqwhnCOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo1TPC/btsLu0eNNgo/t2EQsnSHmRbD5KfqwhnCOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo1TPC/btsLu0eNNgo/t2EQsnSHmRbD5KfqwhnCOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo1TPC%2FbtsLu0eNNgo%2Ft2EQsnSHmRbD5KfqwhnCOK%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;2226&quot; height=&quot;2266&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2226&quot; data-origin-height=&quot;2266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2664&quot; data-origin-height=&quot;2156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MK6ak/btsLt4bd62M/1g9INYtJkudZLilpLvHOP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MK6ak/btsLt4bd62M/1g9INYtJkudZLilpLvHOP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MK6ak/btsLt4bd62M/1g9INYtJkudZLilpLvHOP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMK6ak%2FbtsLt4bd62M%2F1g9INYtJkudZLilpLvHOP0%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;2664&quot; height=&quot;2156&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2664&quot; data-origin-height=&quot;2156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>DB/SQL 튜닝</category>
      <category>sqlp 준비</category>
      <category>친철한 sql 튜닝</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/186</guid>
      <comments>https://yatanox.tistory.com/186#entry186comment</comments>
      <pubDate>Mon, 23 Dec 2024 14:18:20 +0900</pubDate>
    </item>
    <item>
      <title>[My_SQL] Lv.2 연도별 대장균 크기의 편차 구하기</title>
      <link>https://yatanox.tistory.com/185</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIKa9i/btsKUeTpvJA/CO52kEfy4eOIvGd2PvtZLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIKa9i/btsKUeTpvJA/CO52kEfy4eOIvGd2PvtZLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIKa9i/btsKUeTpvJA/CO52kEfy4eOIvGd2PvtZLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIKa9i%2FbtsKUeTpvJA%2FCO52kEfy4eOIvGd2PvtZLk%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;747&quot; height=&quot;679&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;679&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://school.programmers.co.kr/learn/courses/30/lessons/299310&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/299310&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732347936803&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/299310&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cAplZ3/hyXDbhF5xf/ltHjWlzhd4IdFdg0E4NPR0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/eOo6kv/hyXDkyVa8F/NbuY8RteaWgVbuh6oiLuoK/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/299310&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/299310&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cAplZ3/hyXDbhF5xf/ltHjWlzhd4IdFdg0E4NPR0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/eOo6kv/hyXDkyVa8F/NbuY8RteaWgVbuh6oiLuoK/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;s&gt;역시 프로그래머스는 LV이 믿을게 못된다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;편차를 구하는게 핵심인 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 날짜에서 년도만 뽑아낸 서브컬럼을 가진 테이블(e)을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 년도별 최고 크기 값의 서브컬럼을 가진 테이블(s)을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 두 테이블을 조인하여 s 테이블의 최고 크기 값 - e테이블의 각 크기를 연산하여 편차값을 구한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WITH YEAR_T AS(
    SELECT *, YEAR(DIFFERENTIATION_DATE) AS 'YEAR'
    FROM ECOLI_DATA
),
MAX_SIZE AS (
    SELECT YEAR(DIFFERENTIATION_DATE) AS 'YEAR', MAX(SIZE_OF_COLONY) AS 'MAX_SIZE_OF_COLONY'
    FROM ECOLI_DATA 
    GROUP BY YEAR
)
SELECT E.YEAR, (S.MAX_SIZE_OF_COLONY - E.SIZE_OF_COLONY) AS YEAR_DEV, E.ID
FROM YEAR_T E JOIN MAX_SIZE S ON E.YEAR = S.YEAR
ORDER BY 1 ASC, 2 ASC;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DB/Programmers SQL</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/185</guid>
      <comments>https://yatanox.tistory.com/185#entry185comment</comments>
      <pubDate>Sat, 23 Nov 2024 17:12:15 +0900</pubDate>
    </item>
    <item>
      <title>[My_SQL] Lv.2 노선별 평균 역 사이 거리 조회하기</title>
      <link>https://yatanox.tistory.com/184</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lokOf/btsKTpgQeXz/MVmuCgwoDGaLk7MDwneReK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lokOf/btsKTpgQeXz/MVmuCgwoDGaLk7MDwneReK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lokOf/btsKTpgQeXz/MVmuCgwoDGaLk7MDwneReK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlokOf%2FbtsKTpgQeXz%2FMVmuCgwoDGaLk7MDwneReK%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;735&quot; height=&quot;715&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;715&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://school.programmers.co.kr/learn/courses/30/lessons/284531&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/284531&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732345380485&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/284531&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bnDM3s/hyXzHvEusC/ZZ6Xqxfgs7XaHak4K3dhUk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bWI0Tb/hyXDbBZkCQ/jkr8lEnng8MNZtQ043J1x0/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/284531&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/284531&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bnDM3s/hyXzHvEusC/ZZ6Xqxfgs7XaHak4K3dhUk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bWI0Tb/hyXDbBZkCQ/jkr8lEnng8MNZtQ043J1x0/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;호선 별로 그룹화하고 역간의 거리를 기준으로 합치면(sum) 총 누계거리,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균내면(avg) 평균 거리가 나온다. 각각 2,3자리번째의 수에서 반올림 해주고 concat을 이용해서 km단위를 붙여준다.&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;ps. 처음에 order by할 때 2 desc를 했다가 틀렸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반올림 처리 되는 값 때문에 원하는 대로 정렬이 안될 수 있으니 반올림한 부분을 제외하고 정렬처리하자&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ROUTE, CONCAT(ROUND(SUM(D_BETWEEN_DIST), 1), 'km') AS 'TOTAL_DISTANCE', 
CONCAT(ROUND(AVG(D_BETWEEN_DIST), 2), 'km') AS 'AVERAGE_DISTANCE'
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY SUM(D_BETWEEN_DIST) DESC;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DB/Programmers SQL</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/184</guid>
      <comments>https://yatanox.tistory.com/184#entry184comment</comments>
      <pubDate>Sat, 23 Nov 2024 16:44:53 +0900</pubDate>
    </item>
    <item>
      <title>[My_SQL] Lv.2 자동차 평균 대여 기간 구하기</title>
      <link>https://yatanox.tistory.com/183</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GG85u/btsKU9jwKLd/4oL5FZRaTJjclyusq1wn9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GG85u/btsKU9jwKLd/4oL5FZRaTJjclyusq1wn9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GG85u/btsKU9jwKLd/4oL5FZRaTJjclyusq1wn9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGG85u%2FbtsKU9jwKLd%2F4oL5FZRaTJjclyusq1wn9K%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;746&quot; height=&quot;576&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;576&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://school.programmers.co.kr/learn/courses/30/lessons/157342&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/157342&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732345247434&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/157342&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UOQD6/hyXC9RGjna/XE8bDaf2gbfceIFR6XtJx0/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/157342&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/157342&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UOQD6/hyXC9RGjna/XE8bDaf2gbfceIFR6XtJx0/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;1. 두 날짜의 차이 값을 구한 뒤 (datediff)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 평균을 내고(avg)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 2번째 자리에서 반올림을 해주어야한다.(round)&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;car_id로 그룹화하고 그룹화 한 값 중 평균 대여기간이 7일 이상이 것만 Having 절로 걸러낸다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT CAR_ID, ROUND(AVG(DATEDIFF(END_DATE, START_DATE)) + 1, 1) AS AVERAGE_DURATION
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
HAVING AVERAGE_DURATION &amp;gt;= 7
ORDER BY 2 DESC, 1 DESC;&lt;/code&gt;&lt;/pre&gt;</description>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/183</guid>
      <comments>https://yatanox.tistory.com/183#entry183comment</comments>
      <pubDate>Sat, 23 Nov 2024 16:02:08 +0900</pubDate>
    </item>
    <item>
      <title>[My_SQL] Lv.2 조건에 부합하는 중고거래 상태 조회하기</title>
      <link>https://yatanox.tistory.com/182</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;646&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq40zo/btsKTUAORmz/FGTnLRtvRX5kO7z3lDJKm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq40zo/btsKTUAORmz/FGTnLRtvRX5kO7z3lDJKm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq40zo/btsKTUAORmz/FGTnLRtvRX5kO7z3lDJKm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq40zo%2FbtsKTUAORmz%2FFGTnLRtvRX5kO7z3lDJKm1%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;748&quot; height=&quot;646&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/164672&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/164672&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732342837138&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/164672&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DioPa/hyXzRkSrC2/2inMb3J7ImlJMZtvbt4tg1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bcnJg7/hyXzVAPefs/FCvCyQni3bbJAM4NFCgmq1/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/164672&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/164672&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DioPa/hyXzRkSrC2/2inMb3J7ImlJMZtvbt4tg1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bcnJg7/hyXzVAPefs/FCvCyQni3bbJAM4NFCgmq1/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;1. 2022년 10월 05일 게시판 정보를 찾을 것 (str_to_date 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. status를 확인하여 판매중, 예약중, 거래완료를 분류할 것. (case문 사용.)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드&lt;/h4&gt;
&lt;pre id=&quot;code_1718596012146&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT BOARD_ID, WRITER_ID, TITLE, PRICE,
CASE
    WHEN STATUS = 'SALE' THEN '판매중'
    WHEN STATUS = 'RESERVED' THEN '예약중'
    ELSE '거래완료'
END AS STATUS
FROM USED_GOODS_BOARD
WHERE CREATED_DATE = STR_TO_DATE('2022-10-05', '%Y-%m-%d')
ORDER BY 1 DESC;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DB/Programmers SQL</category>
      <author>에이디/김우진</author>
      <guid isPermaLink="true">https://yatanox.tistory.com/182</guid>
      <comments>https://yatanox.tistory.com/182#entry182comment</comments>
      <pubDate>Sat, 23 Nov 2024 15:26:43 +0900</pubDate>
    </item>
  </channel>
</rss>