<?xml version="1.0" encoding="UTF-8" ?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
	<channel>
		<title>데이터베이스 개발자 Tip &amp; 강좌</title>
		<link>https://www.sqler.com/board_Column</link>
		<description>SQLER.com - 데이터베이스, 클라우드, 머신러닝, 오픈소스 개발자 커뮤니티</description>
		<atom:link href="https://www.sqler.com/board_Column/rss" rel="self" type="application/rss+xml" />
		<language>en</language>
		<pubDate>Tue, 12 May 2026 17:47:01 +0900</pubDate>
		<generator>Rhymix</generator>
				<image>
			<url>https://www.sqler.com/files/attach/images/rss/feed_image.jpg</url>
			<title>SQLER.com - 데이터베이스, 클라우드, 머신러닝, 오픈소스 개발자 커뮤니티</title>
			<link>https://www.sqler.com/</link>
		</image>		<item>
			<title>SQL강좌: 14-7. 트랜잭션과 잠금처리 - 교착상태(데드락-DeadLock) 관리</title>
			<link>https://www.sqler.com/board_Column/1124861</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-7. 트랜잭션과 잠금처리 - 교착상태(데드락-DeadLock) 관리를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 교착상태(데드락 - DeadLock) 관리입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/OO2Hgr74vbg?si=7fcjdZHTQobhCx8U&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;교착상태의 정의와 발생 이유를 설명하며, 교착상태를 유발하는 예제로 통해 실제 상황을 살펴봅니다. 또한, 교착상태를 예방하고 관리하는 방법을 소개하며, 해결책을 제시합니다.&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; &lt;br /&gt; 교착상태 쿼리 수행&lt;/h2&gt; &lt;p&gt;교착상태는 무엇이고 어떻게 발생하나요? SQL 구문으로 확인해 보겠습니다. 간단한 2개 테이블이고, 데이터가 1개씩 존재합니다. 여기까지만 봐도 교착상태 쿼리 느낌이 올 겁니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;2개&amp;nbsp;테이블&amp;nbsp;생성&amp;nbsp;후&amp;nbsp;샘플&amp;nbsp;데이터&amp;nbsp;추가&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;deadlock_test1(&lt;br /&gt; idx&amp;nbsp;INT,&lt;br /&gt; cust_num&amp;nbsp;INT&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;deadlock_test2(&lt;br /&gt; idx&amp;nbsp;INT,&lt;br /&gt; cust_num&amp;nbsp;INT&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;deadlock_test1&amp;nbsp;VALUES(1,1);&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;deadlock_test2&amp;nbsp;VALUES(2,2);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;deadlock_test1;&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;deadlock_test2;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&lt;br /&gt; SSMS에서 새 쿼리로 2개 세션을 새로 열고 각각 다음 단계를 실행합니다.&lt;br /&gt; &amp;nbsp;&lt;br /&gt; 1번 세션에서 실행&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;세션&amp;nbsp;1-1&amp;nbsp;실행&lt;br /&gt; BEGIN&amp;nbsp;TRANSACTION;&amp;nbsp;&lt;br /&gt; UPDATE&amp;nbsp;deadlock_test1&amp;nbsp;SET&amp;nbsp;cust_num&amp;nbsp;=&amp;nbsp;cust_num&amp;nbsp;*&amp;nbsp;2;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;2번 세션에서 실행&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;세션&amp;nbsp;2-1&amp;nbsp;실행&lt;br /&gt; BEGIN&amp;nbsp;TRANSACTION;&amp;nbsp;&lt;br /&gt; UPDATE&amp;nbsp;deadlock_test2&amp;nbsp;SET&amp;nbsp;cust_num&amp;nbsp;=&amp;nbsp;cust_num&amp;nbsp;*&amp;nbsp;2;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;1번 세션에서 실행&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;세션&amp;nbsp;1-2&amp;nbsp;실행&amp;nbsp;-&amp;nbsp;블로킹&amp;nbsp;발생&lt;br /&gt; UPDATE&amp;nbsp;deadlock_test2&amp;nbsp;SET&amp;nbsp;cust_num&amp;nbsp;=&amp;nbsp;cust_num&amp;nbsp;*&amp;nbsp;2;&lt;br /&gt; &amp;nbsp;&lt;/div&gt; &lt;p&gt;&lt;br /&gt; 2번 세션에서 실행&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;세션&amp;nbsp;2-2&amp;nbsp;실행&amp;nbsp;-&amp;nbsp;블로킹&amp;nbsp;발생&lt;br /&gt; UPDATE&amp;nbsp;deadlock_test1&amp;nbsp;SET&amp;nbsp;cust_num&amp;nbsp;=&amp;nbsp;cust_num&amp;nbsp;*&amp;nbsp;2;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;두 개의 세션이 서로 다른 테이블을 노려보면서 사용 가능해지기를 기다리고 있습니다.&lt;/p&gt; &lt;p&gt;잠시 후, 아래와 같은 deadlock 오류 메시지가 발생하고 둘 중 하나의 세션이 종료됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt; &lt;p&gt;메시지 1205, 수준 13, 상태 45, 줄 9&lt;br /&gt; Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.&lt;/p&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;1205 교착상태 오류입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;교착상태가 발생하는 이유&lt;/h2&gt; &lt;p&gt;SQL 구문에서 보신 그대로입니다. 하나의 애플리케이션에 함수 루틴 1과 함수 루틴 2가 있다고 가정합니다. 그리고, 테이블 A와 테이블 B가 있다고 가정해 보지요..&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;함수 1은 트랜잭션 처리를&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;테이블 A -&amp;gt; 테이블 B -&amp;gt; 작업 후 완료&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 함수 2는 트랜잭션 처리를&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;테이블 B -&amp;gt; 테이블 A -&amp;gt; 작업 후 완료&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;로 처리합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;애플리케이션 로직이 위와 같을 경우, 함수 1이 테이블 A를 잡을 때, 동시에 함수 2가 테이블 B를 잡았다고 가정하면, 함수는 모두 다음 리소스를 사용하려고 서로 노려만 보고 있는 것입니다. 이런 상황이 교착상태입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 교착상태가 발생하면 SQL Server가 중재를 해서 하나의 프로세스를 Victim(희생양)으로 처리합니다. 한번 1205 교착상태 오류가 발생했다면, 이제 시작입니다. 사용자가 많아지고 동시성이 높아질수록, 교착상태 오류는 더 빈번하게 자주 발생하게 됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;블로킹이나 교착상태를 해결하는 근본적인 방법&lt;/h2&gt; &lt;p&gt;블로킹이나 교착상태를 피하는 방법은 잘 구성된 애플리케이션 개발 계획입니다. 예를 들어, 애플리케이션 내부에 사용자 데이터 삭제나 제품 삭제 루틴 프로세스가 있다면 이런 패턴입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;제품 삭제 루틴&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;&lt;span style=&quot;color:#c0392b;&quot;&gt;1. A테이블 수정&lt;br /&gt; 2. B테이블 수정&lt;br /&gt; 3. C테이블에서 삭제&lt;/span&gt;&lt;br /&gt; 4. 제품 삭제&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 사용자 삭제 루틴&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;1. Y테이블 삭제&lt;br /&gt; 2. X테이블 삭제&lt;br /&gt; &lt;span style=&quot;color:#c0392b;&quot;&gt;3. C테이블 삭제&lt;br /&gt; 4. B테이블 삭제&lt;br /&gt; 5. A테이블 삭제&lt;/span&gt;&lt;br /&gt; 6. 사용자 삭제&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 당연한 루틴이며, 늘 해왔던(사용자가 많지 않을 때부터) 패턴입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 하지만, 위와 같이 프로세스 흐름이 서로 엇갈리는, 블로킹이나 교착상태 발생 가능성이 높은 프로세스 흐름이 있습니다. 이럴 경우, 프로세스 플로우를 변경하면 됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;예를 들어, 사용자 삭제 루틴을 이렇게 변경합니다. 삭제할 데이터는 하위 쿼리나 임시 테이블을 이용해 흐름을 잘 제어하고, X 잠금(Exclusive Lock)을 가능한 짧게 가져갑니다.&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;1. A테이블삭제&lt;br /&gt; 2. B테이블 삭제&lt;br /&gt; 3. C테이블 삭제&lt;br /&gt; 4. X테이블 삭제&lt;br /&gt; 5. Y테이블 삭제&lt;br /&gt; 6. 사용자 삭제&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 이렇게 순서를 바꾼다면? 해당 루틴을 수행하면서 블로킹이나 교착상태가 발생될 가능성이 낮아집니다. 이렇게 루틴을 보완하는 과정을 현업에서는 리소스 처리를 시리얼(Serialize)하게 바꾼다라고 이야기합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 해보신 분은 아실 겁니다. 이렇게 프로세스 흐름을 바꾸기란 절대 쉬운 일이 아닙니다. 기술적인 어려움도 있지만, 소위 어른들의 사정으로, 오류로 인한 비즈니스 임팩트에 대한 책임 소재 등 여러 어려움이 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 말 그대로, 모든 프로세스에서 다 참조하는 member 테이블의 한 계정을 지우려면 이곳저곳에 참조하는 리소스들을 먼저 삭제하고 member 테이블을 지워야 합니다. 개인적으로 30개 정도의 참조하는 테이블에서 삭제 후 member 테이블 로우를 지우던 기억이 납니다. 로직을 변경하고 코드로 적용하기 어렵습니다. 하지만, 블로킹이나 데드락이 한번 발생했을 때 빠르게 이슈를 해결하지 않으면 더 큰 장애가 따라오게 되니, 이 강좌를 참고하셔서 잘 조치하시길 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;근본적인 해결 방법&lt;/h3&gt; &lt;p&gt;프로젝트 기획 단계부터 디자인 프로세스나 구현 단계에서 해당하는 테이블 접근 순서를 문서화하는 것입니다. 그리고 트랜잭션 처리 루틴은 따로 관리를 하세요. 트랜잭션 처리 순서 루틴을 문서화해두고 X저장 프로시저가 A-&amp;gt; B -&amp;gt; C 순서로 처리한다면, Y저장 프로시저를 생성할 때도 A -&amp;gt; B -&amp;gt; C 순서로 리소스에 접근하도록, 문서화를 해 두시면 큰 규모의 프로젝트에서 여러 팀이 나누어 개발을 할 경우에도 교착상태나 블로킹을 최소화하실 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;너무 무서운 이야기만 많이 드린 것 같아요. 블로킹이나 교착상태 문제를 접하면서 이 강좌에서 설명드린 내용 이상의 이슈는 거의 없습니다. 너무 두려워하실 필요 없습니다. 블로킹이나 교착상태가 발생한다면 이전 강좌 내용대로 모니터링하면서 블로킹 유발 쿼리들을 확인하고, 이어서 조치를 취하면 됩니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;수고하셨습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>데드락</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124861</guid>
			<comments>https://www.sqler.com/board_Column/1124861#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:36:44 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 14-6. 트랜잭션과 잠금처리 - 잠금 관리</title>
			<link>https://www.sqler.com/board_Column/1124858</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-6. 트랜잭션과 잠금처리 - 잠금 관리를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 잠금 관리입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/7w2fuGizdJI?si=zj5oFc914D3mvHlz&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;블로킹 상황 해결 방안을 진행합니다. 세션 관리를 통해 블로킹에 대응하고, 성능 모니터링 도구와 SQL Server Profiler를 활용한 블로킹 및 교착상태 분석 방법을 진행하며, 블로킹 관리와 성능 개선 전략을 살펴봅니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 잠금과 블로킹 관리&lt;/h2&gt; &lt;p&gt;지금까지 트랜잭션과 잠금에 대해서 논의했습니다. 그렇다면, 잠금으로 인해 블로킹을 유발하는 상태를 어떻게 관리해야 할까요?&lt;br /&gt; 지난 &lt;a href=&quot;https://www.sqler.com/board_Column/1124852&quot;&gt;14-4. 트랜잭션과 잠금처리 - 잠금(Lock)과 블로킹 강좌&lt;/a&gt;에서 잠금과 블로킹을 확인하는 방법, 블로킹을 유발하는 세션의 상세 정보를 확인하는 방법을 안내해 드렸습니다.&lt;br /&gt; sp_who2와 sys.dm_exec_input_buffer 시스템 카탈로그를 이용해 블로킹을 유발하는 프로세스 정보를 확인하였습니다. 이 프로세스를 어떤 형태로든 관리해야 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금과 블로킹을 유발하는 세션 관리 - kill &amp;lt;SPID&amp;gt;&lt;/h3&gt; &lt;p&gt;kill &amp;lt;SPID&amp;gt; &amp;nbsp;명령으로 해당 세션을 kill 하면 됩니다. 예를 들어, sp_who2로 블로킹을 유발하는 세션을 확인했고, SPID가 71이라면, 아래처럼 실행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;kill&amp;nbsp;71&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;현업에서 완벽한 해결책은 아닙니다. kill 명령으로 해당 세션을 죽여서 문제가 완전히 해결되는 경우는 없습니다. 수만 명이 동시에 접속하는 웹서비스가 약 100여 개의 Restful API 서비스로 제작되었고, 해당 API 마다 사용하는 SQL 구문이 다른데, 그중 1개가 잠금과 블로킹을 유발한다면, 아무리 kill 명령으로 죽여봐야 해당 애플리케이션 모듈 로직을 수정하고 다시 배포하지 않는 이상 계속 문제가 발생하기 때문입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: Restful API 서비스에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금과 블로킹을 유발하는 세션 관리 - lock timeout 설정&lt;/h3&gt; &lt;p&gt;해결책이라기보다는, 블로킹이 주기적으로 발생하는 초기에 어느 코드와 SQL 구문이 블로킹을 유발하는지 안다면, timeout 설정으로 코드와 SQL 구문 수정 전까지, 블로킹으로 인한 장애를 완화할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--락&amp;nbsp;타임아웃&amp;nbsp;시간&amp;nbsp;조사&lt;br /&gt; select&amp;nbsp;@@lock_timeout;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;결과가&amp;nbsp;-1&amp;nbsp;일&amp;nbsp;경우&amp;nbsp;타임아웃&amp;nbsp;없음.&amp;nbsp;무한&amp;nbsp;대기.&lt;br /&gt; &lt;br /&gt; --락&amp;nbsp;타임아웃&amp;nbsp;설정&amp;nbsp;:&amp;nbsp;단위는&amp;nbsp;밀리초.&amp;nbsp;30초&amp;nbsp;설정&lt;br /&gt; SET&amp;nbsp;LOCK_TIMEOUT&amp;nbsp;30000;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; select&amp;nbsp;@@lock_timeout;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 Timeout 설정으로 잠시 완화할 수 있습니다. 다시 말씀드리지만, 문제가 되는 로직을 찾고, 코드와 SQL 구문을 변경해 해결해야 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금과 블로킹을 유발하는 세션 관리 - 성능 모니터&lt;/h3&gt; &lt;p&gt;잠금으로 인해 블로킹이 의심된다고 매번 SSMS에서 쿼리를 수행해 모니터링할 수 없습니다. 자동화 방식으로 메트릭(Metric)을 수집하고, 기록해야 합니다. 이때 성능 모니터 도구와 SQL Server Profiler를 이용할 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQL Server가 설치되어 있다면, Windows의 성능 모니터 도구에서 SQLServer: Locks 항목을 기록해 모니터링 및 기록을 저장할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;156-2-Performance_Locks.png&quot; data-file-srl=&quot;1125845&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/bde660399deb64def3881b71e03714dc.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 성능 모니터 - 잠금 항목&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;특히, 교착상태(데드락-DeadLock)도 모니터링 / 기록할 수 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 교착상태가 발생할 경우,&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;&lt;em&gt;트랜잭션(프로세스 ID xxx)이 (xxx) 리소스에서 다른 프로세스와 교착 상태가 발생하여 실행이 중지되었습니다. 트랜잭션을 다시 실행하십시오.&amp;nbsp;&lt;/em&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 오류 메시지가 발생합니다. 교착상태 관리는 다음 강좌에서 조금 더 상세하게 다룹니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금과 블로킹을 유발하는 세션 관리 - SQL Server Profiler&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;156-1-SQL_Porfiler_DeadLock.png&quot; data-file-srl=&quot;1125846&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/ce10d61e4c43ca8558a837e610756c75.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 SQL Server - Profiler 데드락 트레이스&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;SQL Server의 Profiler를 이용해, 잠금 상태 및 교착상태 쿼리를 모두 실시간 모니터링 / 기록 가능해 자주 블로킹이나 교착상태를 유발하는 SQL 구문을 확인할 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQL Server Profiler는 SQL 구문이나 저장 프로시저 쿼리 튜닝에도 자주 사용되는 도구입니다. SQL Server에서 실행되는 모든 처리가 기록되며, 다양한 필터를 적용해 원하는 실행만 따로 수집도 가능합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 성능 모니터 도구와 Profiler를 이용하면, 문제를 유발하는 SQL 구문과 애플리케이션을 판단할 수 있습니다.&lt;br /&gt; 그럼 다음 강좌에서 블로킹 및 교착상태 관리 방안에 대해 살펴보겠습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>잠금</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124858</guid>
			<comments>https://www.sqler.com/board_Column/1124858#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:36:01 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 14-5. 트랜잭션과 잠금처리 - 잠금과 트랜잭션 격리 수준</title>
			<link>https://www.sqler.com/board_Column/1124855</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-5. 트랜잭션과 잠금처리 - 잠금과 트랜잭션 격리 수준을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 잠금(Lock)과 트랜잭션 격리 수준입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/ayHKKfydgnk?si=7M68gtiXbpHnz5Jj&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;트랜잭션 격리 수준과 설정 방법을 진행하며, 잠금과 트랜잭션 격리 수준이 데이터베이스 동시성 및 블로킹에 미치는 영향을 다룹니다. 또한, 블로킹 해결을 위한 모니터링 방법과 조치를 소개합니다.&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; &lt;br /&gt; 트랜잭션 격리 수준(Transaction Isolation Level)&lt;/h2&gt; &lt;p&gt;SQL Server에서 트랜잭션을 수행할 때 잠금 격리 수준을 설정합니다. 아래와 같은 SQL 구문으로 설정합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;SET TRANSACTION ISOLATION LEVEL&lt;br /&gt; &amp;nbsp; &amp;nbsp; { READ UNCOMMITTED&lt;br /&gt; &amp;nbsp; &amp;nbsp; | READ COMMITTED&lt;br /&gt; &amp;nbsp; &amp;nbsp; | REPEATABLE READ&lt;br /&gt; &amp;nbsp; &amp;nbsp; | SNAPSHOT&lt;br /&gt; &amp;nbsp; &amp;nbsp; | SERIALIZABLE&lt;br /&gt; &amp;nbsp; &amp;nbsp; }&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;div dir=&quot;ltr&quot;&gt;&amp;nbsp;&lt;/div&gt; &lt;table style=&quot;border-collapse:collapse; width:448pt; border:none&quot; width=&quot;598&quot;&gt; &lt;colgroup&gt; &lt;col style=&quot;width:119pt&quot; width=&quot;159&quot; /&gt; &lt;col style=&quot;width:329pt&quot; width=&quot;439&quot; /&gt; &lt;/colgroup&gt; &lt;tbody&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl65&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt; &lt;div dir=&quot;ltr&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;트랜잭션 격리 수준&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt; &lt;/td&gt; &lt;td class=&quot;xl65&quot; style=&quot;border:0.5pt solid black; background:white; border-left:none; width:329pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;439&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;설명&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;READ UNCOMMITTED&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;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:329pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;439&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;NOLOCK 힌트와 같으며, 트랜잭션이 완료되지 않은 데이터도 조회 가능&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;READ COMMITTED&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;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:329pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;439&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;SQL Server 기본 설정. 다른 사용자의 COMMIT 된 데이터만 읽거나 수정 가능.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;REPEATABLE READ&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;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:329pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;439&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;트랜잭션 내부에서 S Lock이 설정되어 다른 세션에서 읽기는 가능하지만, 수정할 경우는 대기하게 됨.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;SNAPSHOT&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;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:329pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;439&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;트랜잭션 중에 발생한 데이터 수정은 다른 세션에서 변경 내용이 조회되지 않고, 대기도 없음. 오라클의 기본 설정과 유사함.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;SERIALIZABLE&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;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:329pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;439&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;직렬화로 가장 높은 격리 수준. 데이터 수정과 삽입 처리 모두 커밋되기 전까지 대기가 발생함. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 내부적으로 잠금 모드가 다르게 구성되며, 트랜잭션 세션 설정에 따라 다른 세션의 조회/삽입/수정/삭제 등이 선별적으로 대기하게 됩니다. 각각 수준에 따라 Dirty Read, Repeatable Read, Phantom Read를 방지할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;예를 들어, 게시판 로직에 조회수 + 1 루틴이 있습니다.&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;UPDATE 게시판 SET 조회수컬럼 = 조회수컬럼 + 1 WHERE 게시글키컬럼 = 조건&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;이런 패턴입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 조금 극단적으로 예시로, 위와 같은 게시글 조회 수 처리 루틴으로 테이블에 일부 로우 단위 잠금이 발생할 경우 NOLOCK 힌트나 READ UNCOMMITTED 격리 수준으로 읽는다고 문제가 발생할까요? 잠금을 무시하고 읽어오지만 Dirty Read가 발생해도 조회수가 +1 되었는지 아닌지 문제라면 무시해도 되는 상황일 겁니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 하지만, 계좌 이체는 어떨까요? 내 계좌에서 1억이 이체되는 중인데, ATM에서 내 계좌를 조회해 보고 이체받을 상대방에게 문의하니 계좌에서 돈은 나갔는데 아직 상대방 계좌로 입금 처리는 완료되지 않은 지연 상태라면? 여러 정황상 문제가 될 소지가 있습니다. 재화와 관련되면 잠시 동안 조회 지연이라도 문제가 심각해집니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이런 문제를 방지하기 위해서 비즈니스의 요구조건과 트랜잭션 격리 수준을 잘 고려해 SQL 쿼리를 작성하시기 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;블로킹(차단 - Blocking)을 유발하는 쿼리 처리&lt;/h2&gt; &lt;p&gt;이제 잠금이 무엇이고, 차단 주체(블로킹을 유발하는 세션)가 무엇인지 조금 알 것 같습니다. 이렇게 차단이 일어날 경우를 블로킹(Blocking)이 발생한다라고 보통 말을 하게 되며 블로킹은 데이터베이스 리소스를 동시에 여러 명 또는 여러 프로세스가 사용하기 때문에 당연히 일어나는 디자인 특성입니다. - 특히 금융권 등에서 재화와 관련된 프로세스일 경우 거의 모든 과정에서 이런 트랜잭션을 이용한 처리를 하기 때문에 자주 블로킹이 발생합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 하지만 지나치게 응답속도가 늦거나 - CPU는 놀고 있는데도 불구하고 - 세션 Timeout이 발생해 트랜잭션이 ROLLBACK 되는 상황이 너무 자주 발생한다면, 여러 블로킹 / 교착상태(Deadlock) 처리를 살펴봐야 합니다. 이때 XEvents(확장 이벤트)나 SQL Server Profiler를 이용해 로깅을 수행하고 모니터링할 수 있으며, 블로킹을 유발하는 세션을 파악해 쿼리 패턴이나 트랜잭션을 다시 설계해 블로킹 문제를 해결해야 합니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>잠금</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124855</guid>
			<comments>https://www.sqler.com/board_Column/1124855#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:35:24 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 14-4. 트랜잭션과 잠금처리 - 잠금(Lock)과 블로킹</title>
			<link>https://www.sqler.com/board_Column/1124852</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-4. 트랜잭션과 잠금처리 - 잠금(Lock)과 블로킹을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 잠금(Lock)과 블로킹입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/06bqqpYjAGk?si=lb2t12fwxQz0s1ki&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;트랜잭션과 잠금의 관계를 다루며, 잠금이 발생하는 상태를 예제로 설명합니다. 잠금의 종류와 잠금 단위, 잠금 힌트와 잠금 모드에 대해 소개하고, 잠금 에스컬레이션에 대한 내용을 설명합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 트랜잭션과 잠금은 밀접한 관계가 있습니다. 트랜잭션 작업이 여러 형태의 잠금을 유발할 수 있기 때문입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;공유 폴더에서 워드 문서 파일을 수정할 때&lt;/h3&gt; &lt;p&gt;잠금을 처음 설명할 때 좋은 샘플이 있습니다. 예를 들어, 사내 공유 폴더에 워드 문서를 두고 작업합니다. 내가 워드 문서를 오픈해 수정하다가, 다른 사용자가 같은 워드 파일을 오픈하면,&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;다른 프로세스나 사용자가 현재 해당 파일을 오픈하고 있습니다. 읽기 전용으로 여시겠습니까?&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;라는 메시지와 함께 파일을 읽기 전용으로 열었을 거예요. 이런 상황이 바로 오늘 공부할 잠금 개념과 비슷합니다. 두 사용자가 동시에 테이블의 같은 로우에 쓰기 작업을 하면, 어느 것을 먼저 적용시켜야 할지 알 수 없겠지요.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;DBMS와 잠금&lt;/h2&gt; &lt;p&gt;DBMS는 기본적으로 여러 명의 사용자 또는 프로세스가 동시에 접속해 작업하는 동시 다중 사용성이 있습니다. 위의 상황과 같은 병행처리가 DBMS는 반드시 제공되어야 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;잠금 상황을 SQL 쿼리로 시뮬레이션&lt;/h2&gt; &lt;p&gt;그 개념이 바로 잠금이며 SQL Server는 이 잠금이 대단히 다양하고 세분화되어 있습니다.&lt;br /&gt; 먼저 잠금 상황을 SQL 쿼리로 재현해 보겠습니다. 말 그대로, 억지로 잠금과 블로킹(Blocking)을 보실 수 있는 쿼리입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;운영&amp;nbsp;환경에서&amp;nbsp;수행하지&amp;nbsp;마시고,&amp;nbsp;개인&amp;nbsp;개발&amp;nbsp;환경에서만&amp;nbsp;수행하세요.&lt;br /&gt; USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;트랜잭션&amp;nbsp;격리&amp;nbsp;수준을&amp;nbsp;가장&amp;nbsp;높은&amp;nbsp;단계인&amp;nbsp;SERIALIZABLE로&amp;nbsp;설정&lt;br /&gt; SET&amp;nbsp;TRANSACTION&amp;nbsp;ISOLATION&amp;nbsp;LEVEL&amp;nbsp;SERIALIZABLE;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;ListPrice&amp;nbsp;*&amp;nbsp;2&amp;nbsp;수행&lt;br /&gt; BEGIN&amp;nbsp;TRAN;&lt;br /&gt; UPDATE&amp;nbsp;Production.Product&amp;nbsp;SET&amp;nbsp;ListPrice&amp;nbsp;=&amp;nbsp;ListPrice&amp;nbsp;*&amp;nbsp;2;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;BEGIN TRAN만 있고, COMMIT TRAN이나 ROLLBACK이 없습니다. 이 상태에서, 새 쿼리를 수행해 새로운 세션을 열고 아래 쿼리를 수행해 블로킹을 유발합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; SET&amp;nbsp;TRANSACTION&amp;nbsp;ISOLATION&amp;nbsp;LEVEL&amp;nbsp;SERIALIZABLE;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;테이블&amp;nbsp;데이터&amp;nbsp;조회&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;Production.Product;&lt;br /&gt; &amp;nbsp;&lt;/div&gt; &lt;p&gt;&lt;br /&gt; 실행하면, 결과가 나오지 않고, 계속 대기 중인 상태입니다. 다시 새 쿼리를 수행해 새로운 세션을 열고 블로킹 상태를 체크합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;dm_tran_locks&amp;nbsp;시스템&amp;nbsp;카탈로그에서&amp;nbsp;잠금&amp;nbsp;정보&amp;nbsp;확인&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;sys.dm_tran_locks&lt;br /&gt; WHERE&amp;nbsp;resource_database_id&amp;nbsp;=&amp;nbsp;(SELECT&amp;nbsp;db.database_id&lt;br /&gt; FROM&amp;nbsp;sys.databases&amp;nbsp;AS&amp;nbsp;db&lt;br /&gt; WHERE&amp;nbsp;name&amp;nbsp;=&amp;nbsp;&amp;#39;Adventureworks&amp;#39;);&lt;br /&gt; GO&lt;br /&gt; --&amp;nbsp;sp_lock도&amp;nbsp;가능하지만,&amp;nbsp;차기&amp;nbsp;버전에서&amp;nbsp;지원하지&amp;nbsp;않음.&lt;br /&gt; --&amp;nbsp;dm_tran_locks&amp;nbsp;사용을&amp;nbsp;권장&lt;br /&gt; EXEC&amp;nbsp;sp_lock;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;BlkBy&amp;nbsp;컬럼에서&amp;nbsp;블로킹을&amp;nbsp;유발하는&amp;nbsp;세션&amp;nbsp;확인&amp;nbsp;가능&lt;br /&gt; EXEC&amp;nbsp;sp_who2;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;sp_who2에서&amp;nbsp;블로킹을&amp;nbsp;유발하는&amp;nbsp;세션이&amp;nbsp;71번이면,&amp;nbsp;아래&amp;nbsp;쿼리로&amp;nbsp;상세&amp;nbsp;정보&amp;nbsp;출력&lt;br /&gt; DBCC&amp;nbsp;INPUTBUFFER(71);&lt;br /&gt; GO&lt;br /&gt; --&amp;nbsp;또는&amp;nbsp;dm_exec_input_buffer&amp;nbsp;사용&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;sys.dm_exec_input_buffer&amp;nbsp;(71,&amp;nbsp;0);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;또는&amp;nbsp;아래&amp;nbsp;쿼리를&amp;nbsp;수행해&amp;nbsp;블로킹&amp;nbsp;유발&amp;nbsp;세션의&amp;nbsp;상세&amp;nbsp;정보&amp;nbsp;확인&amp;nbsp;가능&lt;br /&gt; --&amp;nbsp;https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/performance/understand-resolve-blocking#analyze-blocking-data&lt;br /&gt; SELECT&amp;nbsp;tst.session_id,&amp;nbsp;[database_name]&amp;nbsp;=&amp;nbsp;db_name(s.database_id)&lt;br /&gt; ,&amp;nbsp;tat.transaction_begin_time&lt;br /&gt; ,&amp;nbsp;transaction_duration_s&amp;nbsp;=&amp;nbsp;datediff(s,&amp;nbsp;tat.transaction_begin_time,&amp;nbsp;sysdatetime())&amp;nbsp;&lt;br /&gt; ,&amp;nbsp;transaction_type&amp;nbsp;=&amp;nbsp;CASE&amp;nbsp;tat.transaction_type&amp;nbsp;&amp;nbsp;WHEN&amp;nbsp;1&amp;nbsp;THEN&amp;nbsp;&amp;#39;Read/write&amp;nbsp;transaction&amp;#39;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHEN&amp;nbsp;2&amp;nbsp;THEN&amp;nbsp;&amp;#39;Read-only&amp;nbsp;transaction&amp;#39;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHEN&amp;nbsp;3&amp;nbsp;THEN&amp;nbsp;&amp;#39;System&amp;nbsp;transaction&amp;#39;&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHEN&amp;nbsp;4&amp;nbsp;THEN&amp;nbsp;&amp;#39;Distributed&amp;nbsp;transaction&amp;#39;&amp;nbsp;END&lt;br /&gt; ,&amp;nbsp;input_buffer&amp;nbsp;=&amp;nbsp;ib.event_info,&amp;nbsp;tat.transaction_uow&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt; ,&amp;nbsp;transaction_state&amp;nbsp;&amp;nbsp;=&amp;nbsp;CASE&amp;nbsp;tat.transaction_state&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHEN&amp;nbsp;0&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;has&amp;nbsp;not&amp;nbsp;been&amp;nbsp;completely&amp;nbsp;initialized&amp;nbsp;yet.&amp;#39;&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;WHEN&amp;nbsp;1&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;has&amp;nbsp;been&amp;nbsp;initialized&amp;nbsp;but&amp;nbsp;has&amp;nbsp;not&amp;nbsp;started.&amp;#39;&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;WHEN&amp;nbsp;2&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;is&amp;nbsp;active&amp;nbsp;-&amp;nbsp;has&amp;nbsp;not&amp;nbsp;been&amp;nbsp;committed&amp;nbsp;or&amp;nbsp;rolled&amp;nbsp;back.&amp;#39;&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;WHEN&amp;nbsp;3&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;has&amp;nbsp;ended.&amp;nbsp;This&amp;nbsp;is&amp;nbsp;used&amp;nbsp;for&amp;nbsp;read-only&amp;nbsp;transactions.&amp;#39;&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;WHEN&amp;nbsp;4&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;commit&amp;nbsp;process&amp;nbsp;has&amp;nbsp;been&amp;nbsp;initiated&amp;nbsp;on&amp;nbsp;the&amp;nbsp;distributed&amp;nbsp;transaction.&amp;#39;&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;WHEN&amp;nbsp;5&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;is&amp;nbsp;in&amp;nbsp;a&amp;nbsp;prepared&amp;nbsp;state&amp;nbsp;and&amp;nbsp;waiting&amp;nbsp;resolution.&amp;#39;&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;WHEN&amp;nbsp;6&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;has&amp;nbsp;been&amp;nbsp;committed.&amp;#39;&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;WHEN&amp;nbsp;7&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;is&amp;nbsp;being&amp;nbsp;rolled&amp;nbsp;back.&amp;#39;&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;WHEN&amp;nbsp;8&amp;nbsp;THEN&amp;nbsp;&amp;#39;The&amp;nbsp;transaction&amp;nbsp;has&amp;nbsp;been&amp;nbsp;rolled&amp;nbsp;back.&amp;#39;&amp;nbsp;END&amp;nbsp;&lt;br /&gt; ,&amp;nbsp;transaction_name&amp;nbsp;=&amp;nbsp;tat.name,&amp;nbsp;request_status&amp;nbsp;=&amp;nbsp;r.status&lt;br /&gt; ,&amp;nbsp;tst.is_user_transaction,&amp;nbsp;tst.is_local&lt;br /&gt; ,&amp;nbsp;session_open_transaction_count&amp;nbsp;=&amp;nbsp;tst.open_transaction_count&amp;nbsp;&amp;nbsp;&lt;br /&gt; ,&amp;nbsp;s.host_name,&amp;nbsp;s.program_name,&amp;nbsp;s.client_interface_name,&amp;nbsp;s.login_name,&amp;nbsp;s.is_user_process&lt;br /&gt; FROM&amp;nbsp;sys.dm_tran_active_transactions&amp;nbsp;tat&amp;nbsp;&lt;br /&gt; INNER&amp;nbsp;JOIN&amp;nbsp;sys.dm_tran_session_transactions&amp;nbsp;tst&amp;nbsp;&amp;nbsp;on&amp;nbsp;tat.transaction_id&amp;nbsp;=&amp;nbsp;tst.transaction_id&lt;br /&gt; INNER&amp;nbsp;JOIN&amp;nbsp;Sys.dm_exec_sessions&amp;nbsp;s&amp;nbsp;on&amp;nbsp;s.session_id&amp;nbsp;=&amp;nbsp;tst.session_id&amp;nbsp;&lt;br /&gt; LEFT&amp;nbsp;OUTER&amp;nbsp;JOIN&amp;nbsp;sys.dm_exec_requests&amp;nbsp;r&amp;nbsp;on&amp;nbsp;r.session_id&amp;nbsp;=&amp;nbsp;s.session_id&lt;br /&gt; CROSS&amp;nbsp;APPLY&amp;nbsp;sys.dm_exec_input_buffer(s.session_id,&amp;nbsp;null)&amp;nbsp;AS&amp;nbsp;ib;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 잠금 정보 조회&lt;/h2&gt; &lt;p&gt;dm_tran_locks 시스템 카탈로그 조회 결과를 조금 더 상세히 살펴보겠습니다. 먼저 resource_type으로 잠금 타입이며, 잠금이 걸리는 형식입니다. 보시면 Database, PAGE, KEY, OBJECT 등이 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금 단위&lt;/h3&gt; &lt;p&gt;잠금이 걸리는 단위는 무엇일까요? 테이블 단위? 로우 단위? 아래 표가 잠금의 단위 리소스입니다. RID 행 식별자부터 TABLE 단위까지는 자주 보시게 될 겁니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table style=&quot;border-collapse:collapse; width:413pt; border:none&quot; width=&quot;551&quot;&gt; &lt;colgroup&gt; &lt;col style=&quot;width:119pt&quot; width=&quot;159&quot; /&gt; &lt;col style=&quot;width:294pt&quot; width=&quot;392&quot; /&gt; &lt;/colgroup&gt; &lt;tbody&gt; &lt;tr height=&quot;20&quot; style=&quot;height:15.0pt&quot;&gt; &lt;td class=&quot;xl65&quot; height=&quot;20&quot; style=&quot;border:0.5pt solid black; background:white; height:15.0pt; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt; &lt;div dir=&quot;ltr&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;리소스&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt; &lt;/td&gt; &lt;td class=&quot;xl65&quot; style=&quot;border:0.5pt solid black; background:white; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;Description&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;RID&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;행 식별자는 힙 내의 단일 행을 잠그는 데 사용됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; background:white; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;KEY&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;인덱스 내의 행 잠금은 직렬화 가능한 트랜잭션에서 키 범위를 보호하는 데 사용됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; background:white; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;PAGE&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;데이터 또는 인덱스 페이지와 같은 데이터베이스의 8KB 페이지입니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;19&quot; style=&quot;height:14.25pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;19&quot; style=&quot;border:0.5pt solid black; background:white; height:14.25pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;EXTENT&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;데이터 또는 인덱스 페이지와 같은 인접한 8개의 페이지 그룹입니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; background:white; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;HoBT&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;힙 또는 B-트리입니다. 클러스터형 인덱스가 없는 테이블에서 힙 데이터 페이지나 B-트리(인덱스)를 보호하는 잠금입니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;TABLE&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;모든 데이터와 인덱스가 포함된 전체 테이블입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;FILE&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;데이터베이스 파일입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;APPLICATION&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;애플리케이션이 지정한 리소스입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;METADATA&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;메타데이터 잠금입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;ALLOCATION_UNIT&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;할당 단위입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;DATABASE&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;전체 데이터베이스입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;Xact&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;최적화된 잠금에 사용되는 TID(트랜잭션 ID) 잠금입니다. &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;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;SQL Server는 SQL 쿼리 구문을 분석해 잠금 범위를 자동으로 설정합니다. 물론 사용자가 쿼리 힌트(Query hint)를 이용해 잠금 범위를 의도적으로 설정할 수도 있습니다. 하지만 이렇게 사용자가 직접 잠금을 설정하는 것은 권장하지 않으며, BCP나 Bulk insert 같은 대용량 벌크 작업 시 TABLE Lock을 의도적으로 거는 경우와 SELECT시 일부 쿼리에 NOLOCK을 거는 경우를 제외하고는 권장하지 않습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금 힌트&lt;/h3&gt; &lt;p&gt;SQL 구문에서 잠금 힌트를 사용해, 잠금 상황에 따라 쿼리가 가능합니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; SET&amp;nbsp;TRANSACTION&amp;nbsp;ISOLATION&amp;nbsp;LEVEL&amp;nbsp;SERIALIZABLE;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;테이블&amp;nbsp;데이터&amp;nbsp;조회&amp;nbsp;-&amp;nbsp;NOLOCK&amp;nbsp;옵션으로&amp;nbsp;잠금을&amp;nbsp;무시하며&amp;nbsp;테이블에서&amp;nbsp;데이터를&amp;nbsp;읽습니다.&lt;br /&gt; --&amp;nbsp;Dirty&amp;nbsp;Read&amp;nbsp;가능성이&amp;nbsp;있어도&amp;nbsp;데이터를&amp;nbsp;읽습니다.&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;Production.Product&amp;nbsp;WITH(NOLOCK);&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;아래와 같은 다양한 잠금 힌트가 제공됩니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;em&gt;NOLOCK, READUNCOMMITTED, UPDLOCK, REPEATABLEREAD, SERIALIZABLE, READCOMMITTED, TABLOCK, TABLOCKX, PAGLOCK, ROWLOCK, NOWAIT, READPAST, XLOCK, SNAPSHOT, NOEXPAND&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;참조링크: &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16&quot;&gt;Table Hints (Transact-SQL) - SQL Server | Microsoft Learn&lt;/a&gt; &lt;/p&gt; &lt;h3&gt;&lt;br /&gt; NOLOCK 힌트&lt;/h3&gt; &lt;p&gt;NOLOCK 힌트는 SELECT 구문에만 적용되며, 잠금이 걸린 상태에서도 데이터 읽기를 허용하는 쿼리 힌트입니다. Dirty Read(더티 읽기)는 데이터 수정이 진행되는 잠금 상황에서 데이터를 읽는 방법입니다. 잠금을 무시하고 데이터를 읽지만, 데이터 수정이 ROLLBACK 될 경우 업데이트된 값을 읽거나(롤백되었음에도 불구하고), Phantom Read(팬텀 리드) 같은 로우가 더 많이 출력되는 상황도 발생할 수 있습니다. 현업에서 잠금 상황에 무조건 대비해 NOLOCK을 남발하는(?) 경우가 많은데, 이렇게 Dirty Read나 Phantom Read가 발생할 수 있는 상황을 고려해 영향을 평가하고 선택해 사용해야 합니다. 또한 NOLOCK은 READUNCOMMITTED 격리 수준과 같습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 다시 강조하지만, 일부 SELECT &amp;nbsp;쿼리에서 Dirty Read나 Phantom Read 영향이 없을 경우 NOLOCK 처리, 또는 대용량 데이터 BULK 처리를 위해 TABLE LOCK을 의도적으로 거는 처리를 제외하면, SQL Server가 잠금 범위를 자동으로 정하는 것이 대부분의 상황에서 최선이며, 잠금의 범위가 커질 경우 역시 SQL Server가 자동으로 락을 에스컬레이션 하도록 유지하는 것이 좋습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: 트랜잭션 처리 중 발생하는 Dirty Read(더티 읽기)와 Phantom Read(팬텀 리드)에 대해 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;잠금 모드&lt;/h3&gt; &lt;p&gt;잠금도 계층(Hierarchy)이 있습니다. 예를 들어, 여러 개의 로우에 잠금이 걸린다면 - 페이지 잠금으로 에스컬레이션(Escalation) 시켜 많은 수의 미세 잠금(fine-grain lock)을 적은 수의 큰 잠금(coarse-grain lock)으로 변환하는 과정도 자동으로 실행됩니다. 잠금 에스컬레이션으로 동시성 경합 가능성(Probability of concurrency contention)은 높아지지만, 오버헤드는 낮아집니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 예를 들어, 하위 잠금 단위에서 여러 X(Exclusive - 배타적) 잠금이 걸릴 경우, 상위 잠금 단위는 IX(Intent exclusive - 내재된 배타적) 잠금 모드가 걸릴 수 있습니다.&amp;nbsp;&lt;/p&gt; &lt;div dir=&quot;ltr&quot;&gt;&amp;nbsp;&lt;/div&gt; &lt;table style=&quot;border-collapse:collapse; width:413pt; border:none&quot; width=&quot;551&quot;&gt; &lt;colgroup&gt; &lt;col style=&quot;width:119pt&quot; width=&quot;159&quot; /&gt; &lt;col style=&quot;width:294pt&quot; width=&quot;392&quot; /&gt; &lt;/colgroup&gt; &lt;tbody&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl65&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:white; height:12.75pt; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt; &lt;div dir=&quot;ltr&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;잠금 모드&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt; &lt;/td&gt; &lt;td class=&quot;xl65&quot; style=&quot;border:0.5pt solid black; background:white; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;Description&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; background:white; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;공유(S)&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;SELECT 문처럼 데이터를 변경하거나 업데이트하지 않는 읽기 작업에 사용합니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;51&quot; style=&quot;height:38.25pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;51&quot; style=&quot;border:0.5pt solid black; background:white; height:38.25pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;업데이트(U)&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;업데이트할 수 있는 리소스에 사용합니다. 여러 개의 세션이 리소스를 읽고, 잠그고, 나중에 업데이트할 때 발생하는 일반적인 교착 상태를 방지합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;51&quot; style=&quot;height:38.25pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;51&quot; style=&quot;border:0.5pt solid black; background:white; height:38.25pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;배타적(X)&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;INSERT, UPDATE, DELETE와 같은 데이터 수정 작업에 사용합니다. 여러 개의 업데이트 작업이 같은 리소스에 대해 동시에 이루어지지 못하게 합니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; background:white; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;의도&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;잠금 계층 구조를 만드는 데 사용합니다. 의도 잠금의 종류에는 내재된 공유(IS), 내재된 배타(IX), 공유 내재된 배타(SIX)가 있습니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;51&quot; style=&quot;height:38.25pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;51&quot; style=&quot;border:0.5pt solid black; background:white; height:38.25pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;스키마&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;테이블의 스키마에 종속되는 작업이 실행될 때 사용합니다. 스키마 잠금에는 스키마 수정(Sch-M)과 스키마 안정성(Sch-S) 잠금이 있습니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;34&quot; style=&quot;height:25.5pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;34&quot; style=&quot;border:0.5pt solid black; background:white; height:25.5pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;대량 업데이트(BU)&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;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;데이터를 테이블로 대량 복사하는 경우와 TABLOCK 힌트가 지정된 경우에 사용합니다.&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;51&quot; style=&quot;height:38.25pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;51&quot; style=&quot;border:0.5pt solid black; background:white; height:38.25pt; border-top:none; width:119pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;159&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;키 범위&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; background:white; border-top:none; border-left:none; width:294pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;392&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;직렬화 가능 트랜잭션 격리 수준을 사용할 때 쿼리가 읽는 행 범위를 보호합니다. 쿼리가 다시 실행될 경우 직렬화 가능 트랜잭션의 쿼리에 대해 반환되는 행을 다른 트랜잭션이 삽입할 수 없도록 합니다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: 잠금 에컬레이션(Lock escalation), 동시성 경합 가능성(Probability of concurrency contention), 오버헤드(Overhead) 대해서 알려줘&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>잠금</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124852</guid>
			<comments>https://www.sqler.com/board_Column/1124852#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:34:54 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 14-3. 트랜잭션과 잠금처리 - 트랜잭션과 체크포인트</title>
			<link>https://www.sqler.com/board_Column/1124846</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-3. 트랜잭션과 잠금처리 - 트랜잭션과 체크포인트를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 트랜잭션과 체크포인트입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/810SEccXAAg?si=vprqzzfFa7plZ3jH&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;트랜잭션과 트랜잭션 로그의 관계, 데이터 변경 작업이 디스크에 기록되는 체크포인트 시점에 대한 내용을 다룹니다. 체크포인트 발생 시 트랜잭션과 데이터의 처리 상황을 설명하고, 재해 복구 과정에서 REDO, UNDO 작업의 중요성을 설명합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;br /&gt; 트랜잭션과 트랜잭션 로그는 아주 밀접한 관계가 있습니다. 트랜잭션 로그는 장애(Failure)와 복구(Recovery)와도 밀접한 관련이 있지요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;트랜잭션과 체크포인트의 관계&lt;/h2&gt; &lt;p&gt;강좌를 시작하기 전에 퀴즈입니다. 매번 데이터 변경 작업이 일어날 때마다, 예를 들면 INSERT나 DELETE, UPDATE 작업이 수행될 때마다 이 작업이 매번, 즉시, 디스크의 데이터 파일과 로그 파일에 기록될까요? 답은 &amp;ldquo;X - 아니다&amp;rdquo;입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQL Server는 빠른 처리 속도를 위해 이 데이터 변경을 캐시에 저장하고 있다가 체크포인트 프로세스(Check-point Process)라고 하는 SQL서버 내부의 프로세스가 활성화될 경우에 이 캐시의 데이터 변경을 디스크에 쓰게 됩니다. 왜 그런가요? - 빠른 처리 속도를 위해서입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 그렇다면 또 질문입니다.&lt;/p&gt; &lt;p&gt;테이블에 데이터를 INSERT를 하자마자 SELECT 하면 항상 데이터가 삽입된 게 보입니다. 이건 왜 그런가요?&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;SQL Server는 SELECT를 수행하면,&lt;/h3&gt; &lt;p&gt;1. 디스크의 테이블에서 데이터를 조회&lt;br /&gt; 2. 메모리상의 데이터 캐시 영역에서 조회&lt;br /&gt; 3. SELECT의 결과셋을 내부적으로 생성하고 사용자에게 출력&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 절차로 진행됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 조금 더 흥미 있는 논의를 진행해 볼까요? 진행 중인 트랜잭션 역시 디스크에 쓰게 됩니다. 언제 쓰나요? 체크포인트 발생시마다 쓰게 됩니다. 체크포인트는 퍼지 알고리즘에 의해 대략 1분 정도에 한 번씩 발생합니다. - 주기는 설정으로 변경 가능합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이때 현재 활성 트랜잭션(계속 실행 중인 트랜잭션) 역시 디스크에 씁니다. 이 작업을 Write Ahead Log(WAL - 먼저 쓰기 로그)라고 하며 SQL서버는 이 방식으로 로그를 기록합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: 데이터베이스 트랜잭션 - Write Ahead Log(먼저 쓰기 로그)에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;트랜잭션, 체크포인트와 장애&lt;/h2&gt; &lt;p&gt;&lt;img alt=&quot;153-1-체크포인트.png&quot; data-file-srl=&quot;1125826&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/940a84f767fc8042e1f4dd7a908949c8.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 트랜잭션과 체크포인트&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 트랜젝션과 체크포인트를 공부하면 보게 되는 그림입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;체크포인트 및 장애 발생 상황&lt;/h3&gt; &lt;p&gt;체크포인트 프로세스가 두 번 실행되었고, 시스템 장애가 발생했습니다. Tran #1, Tran #2, Tran #3 작업이 실행 중입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;Tran #1 상태&lt;/strong&gt;&lt;br /&gt; Tran #1은 첫 번째 체크포인트에서 실행 중이었습니다. 두 번째 체크포인트 전에 종료되었습니다. 즉, 두 번째 체크포인트에서 디스크에 기록되었습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;Tran #2 상태&lt;/strong&gt;&lt;br /&gt; Tran2는 첫 번째 체크포인트에서 실행 중, 두 번째 체크포인트에서도 실행 중이고 트랜젝션이 끝났습니다. 하지만, 체크포인트 없이 장애가 발생합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;Tran #3 상태&lt;/strong&gt;&lt;br /&gt; 두 번째 체크포인트에서 실행 중이었으며 실행 중에 시스템 장애가 발생했습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;장애 해결 - 재수행(REDO)과 철회(UNDO)&lt;/h3&gt; &lt;p&gt;이런 장애 상황에서 어떻게 트랜잭션을 복구해야 정석일까요? 강좌 시작에서 말씀드린 REDO와 UNDO가 여기에서 필요합니다. SQL Server는 시작 시 항상 자동복구 프로세스가 동작합니다. 자동 복구 프로세스는 먼저 로그를 확인하고 REDO 할 트랜잭션과 UNDO 할 트랜잭션을 판단합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;Tran #1 처리&lt;/strong&gt;&lt;br /&gt; 체크포인트 전에 Commit이 있습니다. REDO(재수행) 시킵니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;Tran #2 처리&lt;/strong&gt;&lt;br /&gt; 체크포인트 전에 Commit 기록이 없으니 UNDO(철회) 시킵니다. 즉, 데이터를 트랜잭션이 시작하기 전의 상태로 바꿉니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;Tran #3 처리&lt;/strong&gt;&lt;br /&gt; 마찬가지로, 체크포인트 전에 Commit이 없으니 철회됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;위의 작업 후 데이터베이스는 스테이블한 상태가 되면서 계속 작업을 수행합니다. 체크포인트가 중요한 프로세스이고, 장애 시 복구와 처리 여부가 결정되는 처리기입니다. 그럼 체크포인트는 언제 실행되나요?&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;자동적으로 약 1분 정도에 한 번씩 발생합니다. (실행 주기 변경 가능)&lt;/li&gt; &lt;li&gt;SSMS에서 &amp;ldquo;CHECKPOINT&amp;rdquo;라고 수행할 경우&lt;/li&gt; &lt;li&gt;SHUTDOWN 구문을 수행할 경우&lt;/li&gt; &lt;li&gt;SQL서버 서비스를 중단할 경우&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;체크포인트 발생 주기 변경&lt;/h3&gt; &lt;p&gt;아래 방식으로 주기를 변경할 수 있습니다. 단위는 분단위입니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; EXEC&amp;nbsp;sp_configure&amp;nbsp;&amp;#39;show&amp;nbsp;advanced&amp;nbsp;options&amp;#39;,&amp;nbsp;1;&lt;br /&gt; RECONFIGURE;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;체크포인트&amp;nbsp;주기를&amp;nbsp;3분으로&amp;nbsp;변경&lt;br /&gt; EXEC&amp;nbsp;sp_configure&amp;nbsp;&amp;#39;recovery&amp;nbsp;interval&amp;nbsp;(min)&amp;#39;,&amp;nbsp;3;&lt;br /&gt; GO&lt;br /&gt; RECONFIGURE;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;체크포인트와 자동 복구 프로세스는 SQL Server의 내부 구조로 트랜잭션 처리 과정과 디스크 IO로 인한 성능 저하 해결 등에 중요하니 차근차근 살펴보시길 바랍니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 그럼 다음 강좌인 잠금 강좌로 넘어가도록 하겠습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>트랜잭션</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124846</guid>
			<comments>https://www.sqler.com/board_Column/1124846#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:28:16 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 14-2. 트랜잭션과 잠금처리 - 트랜잭션 종류</title>
			<link>https://www.sqler.com/board_Column/1124843</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-2. 트랜잭션과 잠금처리 - 트랜잭션 종류를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 트랜잭션 종류입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/czlYQpTNtzA?si=PSfr1qZZ2Z1o10i3&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;자동 커밋, 명시적, 암시적 트랜잭션 분류를 살펴보고, 여러 SQL Server 인스턴스에서 수행 가능한 분산 트랜잭션과, 명시적 트랜잭션에서 SET XACT_ABORT 설정의 중요성을 다룹니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;br /&gt; SQL Server는 내부적으로 작업의 최소 단위인 이 트랜잭션을 조금 더 세분화해 두었습니다. 이 강좌에서는 트랜잭션의 종류와 명시적으로 트랜잭션 작업을 수행할 경우, 아주 중요한 SET XACT_ABORT 설정에 대해서도 살펴봅니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;트랜잭션 종류&lt;/h2&gt; &lt;p&gt;SQL Server에서는 아래와 같이 세 가지 종류로 트랜잭션 작업을 분류합니다.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Autocommit transactions (자동 커밋 트랜잭션)&lt;/li&gt; &lt;li&gt;Explicit transactions (명시적 트랜잭션)&lt;/li&gt; &lt;li&gt;Implicit transactions (암시적 트랜잭션)&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt; &lt;br /&gt; Autocommit (자동 커밋 트랜잭션)&lt;/h3&gt; &lt;p&gt;아래와 같은 SQL 구문이 있을 경우,&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;-&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;김대우&amp;#39;&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;+&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;손석구&amp;#39;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Autocommit은 위의 작업을 자동으로 다음처럼 변경합니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;BEGIN&amp;nbsp;TRAN&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;-&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;김대우&amp;#39;&lt;br /&gt; COMMIT&amp;nbsp;TRAN&lt;br /&gt; &lt;br /&gt; BEGIN&amp;nbsp;TRAN&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;+&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;손석구&amp;#39;&lt;br /&gt; COMMIT&amp;nbsp;TRAN&lt;/div&gt; &lt;p&gt;&lt;br /&gt; 이렇게 자동으로 변환하고 수행되는 트랜잭션을 Autocommit이라고 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Explicit transactions (명시적 트랜잭션)&lt;/h3&gt; &lt;p&gt;Explicit 트랜잭션은 아래의 SQL 구문처럼, 명시적으로 사용자가 트랜잭션을 정의하고 수행하는 처리입니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;BEGIN&amp;nbsp;TRAN&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;-&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;김대우&amp;#39;&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;+&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;손석구&amp;#39;&lt;br /&gt; COMMIT&amp;nbsp;TRAN&lt;/div&gt; &lt;p&gt;&lt;br /&gt; 이렇게 사용자가 직접 트랜잭션 범위를 정의하고 실행하는 것을 의미합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Implicit transactions (암시적 트랜잭션)&lt;/h3&gt; &lt;p&gt;SQL Server만 사용하셨다면 약간 특이한 방식입니다. 참고로, Oracle 데이터베이스는 기본적으로 Implicit 트랜잭션 방식을 사용합니다.&lt;br /&gt; SQL Server에서 Implicit 트랜잭션이 활성화되면 모든 데이터 변경 작업 후, 반드시 Commit 문을 실행해야만 데이터 변경이 적용됩니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQLER의 질문 게시판에 가끔 들어오는 문의로,&amp;nbsp;&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;Q. SQL Server 버그인가요?&lt;br /&gt; DBMS 관리자가 휴가 중이라 잠시 회사 내 관리 도구로 SQL서버를 관리하는 중입니다. 제품 테이블에서 특정 제품 가격을 2배로 변경하는 작업을 수행했고, 결과도 확인했는데, 잠시 후 누군가 데이터를 바꿔 두는 것인지 알 수 없으나 다른 사용자가 로그인해 확인하면 가격이 다시 원상태로 돌아와 있습니다. 버그인가요?&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;br /&gt; Implicit transactions 설정이 ON으로 되어 있을 경우 발생합니다. 위의 경우는 자체 관리 도구에서 해당하는 커넥션 - 연결된 세션에만 설정한 것일 수 있으며, 회사 내 관리 도구를 이용한다면, 관리자가 연결에 설정을 추가해 제어할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;암시적&amp;nbsp;트랜잭션&amp;nbsp;설정&lt;br /&gt; SET&amp;nbsp;IMPLICIT_TRANSACTIONS&amp;nbsp;ON;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; SELECT&amp;nbsp;ProductID,&amp;nbsp;Name,&amp;nbsp;ListPrice&amp;nbsp;FROM&amp;nbsp;Production.Product&lt;br /&gt; WHERE&amp;nbsp;ProductID&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;가격을&amp;nbsp;2배로&amp;nbsp;변경&lt;br /&gt; UPDATE&amp;nbsp;Production.Product&amp;nbsp;SET&amp;nbsp;ListPrice&amp;nbsp;=&amp;nbsp;ListPrice&amp;nbsp;*&amp;nbsp;2&lt;br /&gt; WHERE&amp;nbsp;ProductID&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;조회하면&amp;nbsp;변경되어&amp;nbsp;있음.&lt;br /&gt; SELECT&amp;nbsp;ProductID,&amp;nbsp;Name,&amp;nbsp;ListPrice&amp;nbsp;FROM&amp;nbsp;Production.Product&lt;br /&gt; WHERE&amp;nbsp;ProductID&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;&amp;quot;새&amp;nbsp;쿼리&amp;quot;를&amp;nbsp;실행해&amp;nbsp;새로운&amp;nbsp;쿼리창&amp;nbsp;세션을&amp;nbsp;열고&amp;nbsp;조회하면&amp;nbsp;가격이&amp;nbsp;그대로임.&lt;br /&gt; SELECT&amp;nbsp;ProductID,&amp;nbsp;Name,&amp;nbsp;ListPrice&amp;nbsp;FROM&amp;nbsp;Production.Product&lt;br /&gt; WHERE&amp;nbsp;ProductID&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;결론적으로, SET IMPLICIT TRANSACTION이 설정되어 있다면, 눈에 보이지 않지만 암시적으로 &amp;ldquo;BEGIN TRAN&amp;rdquo; 구문이 추가된 상태입니다. 따라서, 맨 마지막에 COMMIT TRAN을 실행하면 변경사항이 데이터베이스에 적용됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;가격을&amp;nbsp;2배로&amp;nbsp;변경&lt;br /&gt; UPDATE&amp;nbsp;Production.Product&amp;nbsp;SET&amp;nbsp;ListPrice&amp;nbsp;=&amp;nbsp;ListPrice&amp;nbsp;*&amp;nbsp;2&lt;br /&gt; WHERE&amp;nbsp;ProductID&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; COMMIT&amp;nbsp;TRAN;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;&amp;quot;새&amp;nbsp;쿼리&amp;quot;를&amp;nbsp;실행해&amp;nbsp;새로운&amp;nbsp;세션을&amp;nbsp;열고&amp;nbsp;조회하면&amp;nbsp;트랜잭션&amp;nbsp;처리가&amp;nbsp;완료되어&amp;nbsp;변경된&amp;nbsp;가격임.&lt;br /&gt; SELECT&amp;nbsp;ProductID,&amp;nbsp;Name,&amp;nbsp;ListPrice&amp;nbsp;FROM&amp;nbsp;Production.Product&lt;br /&gt; WHERE&amp;nbsp;ProductID&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;분산 트랜잭션 처리(Distributed Transaction)&lt;/h2&gt; &lt;p&gt;다음은 분산 트랜잭션입니다. 예를 들어, 두대의 서로 다른 SQL Server 인스턴스가 있을 경우, 두 시스템에서 트랜잭션 처리를 수행할 때, 분산 트랜잭션을 사용합니다. 연결된 서버(Linked Server)를 활용해 4 파트 쿼리(서버명.DB명.스키마명.테이블명)나 오픈쿼리(OPENQUERY) 이용해 처리하며, MS-DTC(Distributed Transaction Coordinator)가 적절하게 구성되고 활성화되어 있어야만 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;BEGIN&amp;nbsp;DISTRIBUTED&amp;nbsp;TRANSACTION&lt;br /&gt; UPDATE&amp;nbsp;시스템이름A.디비명.소유자명.테이블명&amp;nbsp;SET&amp;nbsp;price=&amp;nbsp;price*2&lt;br /&gt; UPDATE&amp;nbsp;시스템이름B.디비명.소유자명.테이블명&amp;nbsp;SET&amp;nbsp;price=&amp;nbsp;price*2&lt;br /&gt; COMMIT&amp;nbsp;TRAN&amp;nbsp;--또는&amp;nbsp;ROLLBACK&amp;nbsp;TRAN&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;중요한 부분으로, MS-DTC 활성화가 잘 되어있는지를 조사해야 하며, 연결된 서버에 적절한 권한으로 로그인된 후 객체를 핸들 할 수 있는지 역시 잘 체크해야 합니다. 대부분의 경우 이 두 가지 문제로 분산 트랜잭션 처리가 안될 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SET XACT_ABORT ON&lt;/h2&gt; &lt;p&gt;마지막으로, 트랜잭션 처리에서 가장 중요한 설정인 SET XACT_ABORT ON입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; BEGIN TRAN 구문을 이용하는 처리는 항상 SET XACT_ABORT ON이 같이 따라온다고 생각하면 편합니다. 그럼, SQL 쿼리 예제로 살펴보도록 하겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--SET&amp;nbsp;XACT_ABORT를&amp;nbsp;이용한&amp;nbsp;런타임시의&amp;nbsp;오류라도&amp;nbsp;에러&amp;nbsp;시&amp;nbsp;롤백&lt;br /&gt; USE&amp;nbsp;AdventureWorks;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;만약&amp;nbsp;테이블이&amp;nbsp;존재하면&amp;nbsp;삭제&lt;br /&gt; IF&amp;nbsp;OBJECT_ID(N&amp;#39;dbo.TR_Test&amp;#39;,&amp;nbsp;N&amp;#39;U&amp;#39;)&amp;nbsp;IS&amp;nbsp;NOT&amp;nbsp;NULL&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;DROP&amp;nbsp;TABLE&amp;nbsp;dbo.TR_Test;&amp;nbsp;&amp;nbsp;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;테이블&amp;nbsp;생성&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;TR_Test(&lt;br /&gt; c1&amp;nbsp;INT&amp;nbsp;NOT&amp;nbsp;NULL&amp;nbsp;PRIMARY&amp;nbsp;KEY&lt;br /&gt; ,&amp;nbsp;c2&amp;nbsp;INT&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;삽입&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(1,&amp;nbsp;1);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Syntax로&amp;nbsp;INSERT&amp;nbsp;문&amp;nbsp;오류&lt;br /&gt; insertT&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(1,&amp;nbsp;1);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;테이블명&amp;nbsp;-&amp;nbsp;OBJECT&amp;nbsp;명&amp;nbsp;오류&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_TestZZZ(c1,c2)&amp;nbsp;VALUES(1,&amp;nbsp;1);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --기본키&amp;nbsp;제약&amp;nbsp;위반&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(1,&amp;nbsp;1);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;조회&lt;br /&gt; select&amp;nbsp;*&amp;nbsp;from&amp;nbsp;TR_Test;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;INSERT를&amp;nbsp;수행합니다.&amp;nbsp;기본키&amp;nbsp;제약&amp;nbsp;오류가&amp;nbsp;런타임에서&amp;nbsp;발생합니다.&lt;br /&gt; BEGIN&amp;nbsp;TRAN;&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(2,&amp;nbsp;2);&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(2,&amp;nbsp;2);&amp;nbsp;&amp;nbsp;--&amp;nbsp;기본키&amp;nbsp;제약&amp;nbsp;오류&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(3,&amp;nbsp;3);&lt;br /&gt; COMMIT&amp;nbsp;TRAN;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;조회&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;TR_Test;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;트랜잭션&amp;nbsp;작업&amp;nbsp;중에서&amp;nbsp;하나라도&amp;nbsp;작업이&amp;nbsp;실패하면,&amp;nbsp;에러와&amp;nbsp;함께&amp;nbsp;모두&amp;nbsp;ROLLBACK&amp;nbsp;해야&amp;nbsp;함.&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;테이블&amp;nbsp;데이터&amp;nbsp;삭제&lt;br /&gt; TRUNCATE&amp;nbsp;TABLE&amp;nbsp;TR_Test;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; --&amp;nbsp;XACT_ABORT&amp;nbsp;설정&lt;br /&gt; SET&amp;nbsp;XACT_ABORT&amp;nbsp;ON;&lt;br /&gt; --&amp;nbsp;INSERT를&amp;nbsp;수행합니다.&amp;nbsp;기본키&amp;nbsp;제약&amp;nbsp;오류가&amp;nbsp;런타임에서&amp;nbsp;발생합니다.&lt;br /&gt; BEGIN&amp;nbsp;TRAN;&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(2,&amp;nbsp;2);&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(2,&amp;nbsp;2);&amp;nbsp;&amp;nbsp;--&amp;nbsp;기본키&amp;nbsp;제약&amp;nbsp;오류&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(3,&amp;nbsp;3);&lt;br /&gt; COMMIT&amp;nbsp;TRAN;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;모두&amp;nbsp;롤백된&amp;nbsp;것을&amp;nbsp;확인.&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;TR_Test;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;애플리케이션이나 저장 프로시저에서 개발할 경우, 트랜잭션 처리를 한다면 항상 SET XACT_ABORT ON을 선언하고 작업하세요. 런타임 오류가 발생해도 이렇게 롤백시키고 완료합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; XACT_ABORT ON 방식 외에 @@ERROR로 트랜잭션 롤백을 수행하는 방안이 있으나, 권장하지 않습니다. 항상 XACT_ABORT ON 방식을 이용하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;@@ERROR로 트랜잭션 롤백을 수행하는 방안 - 권장하지 않습니다.&lt;/h3&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;새&amp;nbsp;쿼리&amp;nbsp;수행&amp;nbsp;-&amp;nbsp;만약&amp;nbsp;테이블이&amp;nbsp;존재하면&amp;nbsp;삭제&lt;br /&gt; IF&amp;nbsp;OBJECT_ID(N&amp;#39;dbo.TR_Test&amp;#39;,&amp;nbsp;N&amp;#39;U&amp;#39;)&amp;nbsp;IS&amp;nbsp;NOT&amp;nbsp;NULL&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;DROP&amp;nbsp;TABLE&amp;nbsp;dbo.TR_Test;&amp;nbsp;&amp;nbsp;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;테이블&amp;nbsp;생성&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;TR_Test(&lt;br /&gt; c1&amp;nbsp;INT&amp;nbsp;NOT&amp;nbsp;NULL&amp;nbsp;PRIMARY&amp;nbsp;KEY&lt;br /&gt; ,&amp;nbsp;c2&amp;nbsp;INT&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --추천하지&amp;nbsp;않지만,&amp;nbsp;@@ERROR로&amp;nbsp;트랜잭션&amp;nbsp;롤백&amp;nbsp;방안&lt;br /&gt; BEGIN&amp;nbsp;TRAN;&lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(2,&amp;nbsp;2);&lt;br /&gt; IF&amp;nbsp;@@ERROR&amp;nbsp;&amp;lt;&amp;gt;&amp;nbsp;0&amp;nbsp;GOTO&amp;nbsp;ERROR_TRANSACTION;&lt;br /&gt; &lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(2,&amp;nbsp;2);&amp;nbsp;&amp;nbsp;--에러&amp;nbsp;발생&lt;br /&gt; IF&amp;nbsp;@@ERROR&amp;nbsp;&amp;lt;&amp;gt;&amp;nbsp;0&amp;nbsp;GOTO&amp;nbsp;ERROR_TRANSACTION;&lt;br /&gt; &lt;br /&gt; insert&amp;nbsp;into&amp;nbsp;TR_Test(c1,c2)&amp;nbsp;VALUES(3,&amp;nbsp;3);&lt;br /&gt; IF&amp;nbsp;@@ERROR&amp;nbsp;&amp;lt;&amp;gt;&amp;nbsp;0&amp;nbsp;GOTO&amp;nbsp;ERROR_TRANSACTION;&lt;br /&gt; &lt;br /&gt; --모든&amp;nbsp;작업&amp;nbsp;성공&lt;br /&gt; print&amp;nbsp;N&amp;#39;삽입이&amp;nbsp;성공했습니다.&amp;#39;;&lt;br /&gt; COMMIT&amp;nbsp;TRAN;&lt;br /&gt; GOTO&amp;nbsp;END_BATCH;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;하나라도&amp;nbsp;실패&lt;br /&gt; ERROR_TRANSACTION:&lt;br /&gt; print&amp;nbsp;N&amp;#39;삽입&amp;nbsp;실패&amp;#39;;&lt;br /&gt; ROLLBACK&amp;nbsp;TRAN;&lt;br /&gt; &lt;br /&gt; END_BATCH:&lt;br /&gt; print&amp;nbsp;N&amp;#39;BATCH가&amp;nbsp;끝났습니다.&amp;#39;;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;다음으로 트랜잭션과 체크포인트 프로세스를 리뷰하면서, 장애 상황에서 트랜잭션이 어떻게 처리되는지, REDO와 UNDO에 대해서 상세히 알아보도록 하겠습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>트랜잭션</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124843</guid>
			<comments>https://www.sqler.com/board_Column/1124843#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:27:51 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 14-1. 트랜잭션과 잠금처리 - 트랜잭션 이해</title>
			<link>https://www.sqler.com/board_Column/1124840</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 14-1. 트랜잭션과 잠금처리 - 트랜잭션 이해를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 트랜잭션과 잠금처리 - 트랜잭션 이해입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/I9F1PodjVgc?si=M3eDY49dCl8tuVtB&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;데이터베이스 트랜잭션을 소개합니다. 원자성, 일관성, 격리성, 영속성 - 트랜잭션의 4가지 요건에 대해 설명하고, 데이터베이스가 트랜잭션으로 어떻게 일관된 상태를 유지하는지 정리합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 데이터베이스를 공부하면서 &amp;ldquo;트랜잭션&amp;rdquo;이라는 키워드는 여러 형태로 사용됩니다. 지난 백업과 복원 강좌에서 데이터 변경이 기록되는 &amp;ldquo;트랜잭션 로그&amp;rdquo;에 대해 살펴보았고, 단위 작업이라는 의미의 &amp;ldquo;트랜잭션&amp;rdquo; 역시 여러 번 강좌를 진행하면서 말씀드렸습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;시스템은 놀고 있는데, SQL 쿼리가 아주 느리거나 실패함&lt;/h2&gt; &lt;p&gt;SQL 쿼리 구문을 실행하는 애플리케이션을 개발할 경우에도 이 트랜잭션은 중요하고 속도에 많은 영향을 주게 됩니다. 특히, 동시 다수 사용자 데이터베이스에서 데이터 조회/수정을 진행할 때 - 예를 들어, INSERT/UPDATE/DELETE 와 같은 구문과 SELECT 구문을 잘 못 수행할 경우, CPU나 리소스는 펑펑 놀고 있는데, 처리 속도는 느려지는 사태가 빈번하게 발생합니다. 잠금에 의한 블로킹 / 데드락 현상입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 만약, 이런 상황이 종종 발생한다면, 트랜잭션 처리 루틴을 SQL Server Profiler와 같은 모니터링 도구를 이용해 애플리케이션과 SQL 쿼리에서 점검해 보시는 게 좋습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQLER 강좌에서 이러한 현상을 실제로 유발해 보고 해결하는 방안에 대해서도 진행하니 도움 되시길 바랍니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;트랜잭션이란 무엇인가&lt;/h2&gt; &lt;p&gt;이 챕터 이름이 트랜잭션과 잠금처리입니다. 트랜잭션은 무엇일까요?&amp;nbsp;&lt;br /&gt; 트랜잭션은 SQL Server와 같은 데이터베이스에서 가장 작은, 분리할 수 없는 작업의 단위입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;은행 계좌이체로 트랜잭션을 풀어 보면,&lt;br /&gt; 김대우의 은행 계좌에 500원이 있고. 손석구 님의 계좌에 300원이 있습니다.&lt;br /&gt; 김대우는 500원에서 100원을 온라인으로 손석구 님에게 계좌이체 해야 합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 은행에서 온라인으로 계좌를 이체하려면 아래와 같이 진행됩니다.&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;1. 김대우 계좌에서 100원을 뺌: 김대우 계좌 = 400원 &amp;nbsp; 손석구 님 계좌 = 300원&lt;br /&gt; 2. 손석구 님 계좌에 100원을 더함: 김대우 계좌 = 400원 &amp;nbsp; 손석구 님 계좌 = 400원&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 이렇게 은행에서 계좌 이체를 하려고 했는데, 갑자기 정전이 발생해서 1번 작업만 끝내고 은행의 기간계 시스템이 다운되었습니다. 은행에서 그 당시 온라인으로 계좌 이체를 시킨 사람이 1,000명이었다면, 1,000명에게 발생한 이 문제를 어떻게 해결할 수 있을까요?&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;위의 내용을 우리가 사용하는 SQL 구문으로 바꿔서 실행하면 이렇게 실행될 겁니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;-&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;김대우&amp;#39;&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;+&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;손석구&amp;#39;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;앗! 주의하세요. SQL Server에서 위의 작업을 하나의 단위 작업으로 묶으려면 다르게 적어야 합니다. 위와 같이 SQL 쿼리를 작성하면 다음과 같이 변환됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;BEGIN&amp;nbsp;TRAN&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;-&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;김대우&amp;#39;&lt;br /&gt; COMMIT&amp;nbsp;TRAN&lt;br /&gt; &lt;br /&gt; BEGIN&amp;nbsp;TRAN&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;+&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;손석구&amp;#39;&lt;br /&gt; COMMIT&amp;nbsp;TRAN&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 자동으로 변화하게 됩니다. 내부적으로 SQL Server의 엔진이 SQL 쿼리를 위와 같이 변환해 수행하게 됩니다. 그렇다면, 어떻게 SQL 쿼리를 작성해야 계좌 이체 작업을 하나의 단위 작업으로 묶어서 수행할 수 있을까요?&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 다음과 같이, 명시적으로 BEGIN TRAN과 COMMIT TRAN을 사용하면 됩니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;BEGIN&amp;nbsp;TRAN&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;-&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;김대우&amp;#39;&lt;br /&gt; UPDATE&amp;nbsp;계좌&amp;nbsp;SET&amp;nbsp;금액&amp;nbsp;=&amp;nbsp;금액&amp;nbsp;+&amp;nbsp;100&amp;nbsp;WHERE&amp;nbsp;ID&amp;nbsp;LIKE&amp;nbsp;&amp;#39;손석구&amp;#39;&lt;br /&gt; COMMIT&amp;nbsp;TRAN&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 묶어서 사용하면 두 개의 작업이 하나의 단위로 처리가 됩니다.&amp;nbsp;&lt;br /&gt; 그렇다면, 데이터베이스 개론 측면에서 트랜잭션을 살펴보도록 하겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;트랜잭션 4개의 요건&lt;/h2&gt; &lt;p&gt;트랜잭션은 DBMS차원에서 다음 요건들을 만족해야만 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;원자성(atomicity)&lt;/h3&gt; &lt;p&gt;트랜잭션은 전부(All) 또는 전무(Nothing) 실행만 있으며 일부 작업만 완료/중단하는 처리는 불가능합니다. 계좌 이체 과정에서 출금 작업은 완료했지만, 입금 작업에서 실패했다면, 이 작업은 모든 작업을 실패 상태로 되돌려야 합니다. 즉, 트랜잭션으로 선언한 모든 작업은 성공 또는 취소되어야만 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;일관성(consistency)&lt;/h3&gt; &lt;p&gt;트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관된 데이터베이스 상태가 유지되어야 합니다. 즉, 트랜잭션 실행으로 데이터베이스의 비즈니스 규칙이나 데이터베이스 무결성이 위배되지 않는 일관된 데이터베이스 상태가 유지되어야 합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;격리성(isolation)&lt;/h3&gt; &lt;p&gt;여러 트랜잭션이 동시에 실행될 경우, 한 트랜잭션 연산의 중간 결과를 다른 트랜잭션이나 작업이 접근할 수 없도록 격리되어야 합니다. 즉, 한 트랜잭션이 완료하기 전까지 다른 트랜잭션은 해당 트랜잭션의 결과를 참조할 수 없도록 격리됩니다. 이어지는 강좌에서 트랜잭션 격리 수준(Transaction Isolation Level)이 진행됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;영속성(durability)&lt;/h3&gt; &lt;p&gt;트랜잭션이 완료되면 트랜잭션 결과를 데이터베이스에 반영하고 어떠한 경우에라도 보장받습니다. 이 요건이 영속성입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;약간 어렵게 느껴질 수 있습니다. 앞으로 차근차근 내용을 진행하니 너무 걱정 안 하셔도 됩니다. 그렇다면, 트랜잭션 장애나 시스템 장애 상황에서 어떻게 회복이 될까요? 이때, Checkpoint와 Redo / Undo를 이용하며, 다음 강좌에서 상세히 살펴봅니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;데이터베이스 장애(Failure)와 회복(Recovery)&lt;/h2&gt; &lt;p&gt;데이터베이스 회복(Recovery)이란, 데이터베이스 장애(Failure)가 발생했을 때 데이터 베이스를 장애 이전의 상태로 다시 복원시켜 일관된 상태로(consistent state)로 되돌리는 작업입니다. 이런 장애를 조금 더 세분화를 시켜야 오늘 진행할 트랜잭션 장애와 차별화가 가능합니다.&lt;/p&gt; &lt;h3&gt;&lt;br /&gt; 트랜잭션 장애&lt;/h3&gt; &lt;p&gt;트랜잭션 처리 중에 논리적 오류나 내부 조건, 입력 데이터 불량, 데이터 불명, 시스템 자원의 과다한 사용 요구 등으로 정상적인 실행을 계속할 수 없는 상태.&lt;/p&gt; &lt;h3&gt;&lt;br /&gt; 시스템 장애&lt;/h3&gt; &lt;p&gt;하드웨어나 플랫폼 오류로 메인 메모리에 있는 정보의 손실이나 교착 상태가 발생해 더 이상 실행을 계속할 수 없는 상태를 의미.&lt;/p&gt; &lt;h3&gt;&lt;br /&gt; 미디어 장애&lt;/h3&gt; &lt;p&gt;디스크와 같은 저장 미디어 오류로 저장 장치의 데이터베이스 일부 또는 전부가 손상된 상태를 의미.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이런 다양한 장애 상황에서도 데이터베이스는 트랜잭션을 이용해 일관된 상태를 유지합니다.&amp;nbsp;&lt;br /&gt; 그럼 다음 강좌에서 실제 쿼리를 이용해 트랜잭션을 조금 더 살펴보도록 하겠습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>트랜잭션</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124840</guid>
			<comments>https://www.sqler.com/board_Column/1124840#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:27:20 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 13-5. 백업과 복원 - 로그 전달, Always On 고가용성과 재해 복구 구현</title>
			<link>https://www.sqler.com/board_Column/1124837</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 13-5. 백업과 복원 - 로그 전달, Always On 고가용성과 재해&amp;nbsp;복구 구현을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 백업과 복원 - 로그 전달, Always On 고가용성과 재해 복구 구현입니다. 이 강좌에서는 기본적인 고가용성에 대한 이해와 여러 고가용성 기능을 살펴봅니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/ommczM_fWek?si=kDUEvtOScuVJe6gE&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;데이터베이스의 고가용성과 재해 복구에 관한 내용을 진행하고, 클라우드 환경에서 HA/DR(고가용성/재해 복구) 구성도 소개합니다. 데이터베이스 미러링, 로그 전달, Always On 고가용성의 기능과 차이점을 설명합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 클라우드 시대 고가용성(HA - High Availability)과 재해 복구(DR - Disaster Recovery)&lt;/h2&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;클라우드 시대에 웬 On-Premise 고가용성과 재해 복구?&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;br /&gt; 이 글을 보고 계시다면 이미 클라우드 서비스 제공자(CSP - Cloud Service Provider)를 통해 여러 형태의 데이터베이스를 사용하고 계실 거에요. DaaS(Database-as-a-Service) 서비스로 대표적인 마이크로소프트의 Azure SQL Database나 AWS의 RDS for SQL Server와 같은 서비스부터 VM(Virtual Machine-가상머신)을 이용해 데이터베이스 서버를 클라우드에 전개하고 서비스하고 계실 거에요.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이 강좌의 목표는 HA/DR 에 대한 기본적인 이해입니다. 기본적인 이해가 있다면 사설 클라우드(Private Cloud)나 여러 CSP의 HA/DR을 더 쉽게 설정하고 사용할 수 있습니다. 이 강좌에서는 HA/DR 기본 설정과 기능별 차이에 대해 진행합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 다시 강조하지만, HA/DR을 구성해야 할 중요 데이터베이스 서비스라면 꼭 클라우드를 활용하시길 바랍니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: 고가용성(HA - High Availability)과 재해 복구(DR - Disaster Recovery)에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;데이터베이스 고가용성&lt;/h2&gt; &lt;p&gt;SQL Server는 여러 HA/DR 기능을 제공합니다. SQL Server의 대표적인 HA/DR 기능은 아래 세 가지가 존재합니다. 미러링은 SQL Server 2022 차기 버전부터 지원하지 않으니, Always On과 로그 전달 서비스를 주로 설명합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;데이터베이스 미러링(Mirroring) - SQL Server 2022 이후 지원하지 않음&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;145-1-미러링.gif&quot; data-file-srl=&quot;1125805&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/17807f7668ededd721ccef19c4232270.gif&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - SQL Server 미러링&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 하나의 SQL Server 데이터베이스에 대해, 다른 SQL Server 인스턴스에서 복사본을 유지 관리하는 기능입니다. 주 서버(Principal Server)가 실제 데이터베이스 서비스를 제공하며, 다른 서버는 미러 서버(Mirror Server)로 대기(Standby) 상태를 유지합니다. 미러링은 주 서버에서 발생하는 데이터베이스 변경(삽입/수정/삭제) 트랜잭션을 미러 데이터베이스로 보내 REDO 하는 형태로 데이터베이스를 동기화합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 주 서버에 장애가 발생할 경우 자동/수동 조치를 통해 역할을 전환시킬 수 있습니다. 반드시 모니터링 서버가 있어야 자동 장애 조치가 수행됩니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 차기 SQL Server부터는 지원되지 않으니, 아래에서 설명하는 로그 전달이나 Always On을 사용하시길 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;로그 전달(Log Shipping)&lt;/h3&gt; &lt;p&gt;미러링과 유사합니다. 주 서버(Primary Server)에서 트랜잭션 로그를 백업해 보조 서버(Secondary Server)로 복사하고, 보조 서버에서 트랜잭션 로그를 복원해 최신 상태를 유지합니다. 보조 서버의 데이터베이스를 제한된 읽기 전용(Read-only) 방식으로 접근해 데이터 조회 용도로 사용할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;145-2-로그전달.gif&quot; data-file-srl=&quot;1125806&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/d1ce5d46b5b38a4f0e5687560798a39b.gif&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 로그 전달&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;미러링과 로그 전달 차이&lt;/h3&gt; &lt;p&gt;SQL Server의 미러링과 유사해 보이지만 몇몇 차이점이 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;로그 전달은 수동으로 장애 조치를 수행합니다.&amp;nbsp;&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;미러링은 차기 SQL Server부터는 지원하지 않습니다. 로그 전달이나 Always On을 사용하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Always On&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;145-3-alwayson.gif&quot; data-file-srl=&quot;1125807&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/85d7bd0a01e1746d4d7605c79a862d58.gif&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - Always On 구성&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Always On은 가용성 그룹(AG - Availability Group)을 구성하고 관리하는 고가용성(HA - High Availability) 기능과 재해 복구(DR - Disaster Recovery) 기능을 제공하며, 로그 전달과 비교해 여러 장점들을 제공합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;WSFC(Windows Server Failover Clustering)와 통합되어 가용성 그룹으로 데이터베이스 사용&lt;/li&gt; &lt;li&gt;가용성 그룹은 1개의 주 데이터베이스와 1~8개의 보조 복제본 데이터베이스를 지원&lt;/li&gt; &lt;li&gt;보조 데이터베이스에 대해 읽기 전용으로 접근 가능&lt;/li&gt; &lt;li&gt;다양한 장애 조치 설정 지원(자동/수동/강제)&lt;/li&gt; &lt;li&gt;Availability Group Listener로 클라이언트는 장애조치 복제본에 자동 연결(장애 발생 시 수동으로 연결 문자열을 변경할 필요 없음)&lt;/li&gt; &lt;li&gt;Always On 가용성 그룹은 SQL Server 최상위 버전인 엔터프라이즈 버전에서만 지원됩니다.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;기본 설명만으로도 끝판왕 느낌입니다. 24시간, 365일 무정지 시스템으로 운영되어야 하는 HA/DR 데이터베이스를 직접 구성할 경우 최선의 선택입니다. 다양한 구성 시나리오와 패턴이 제공되므로 회사나 조직에서 원하는 구성에 맞춰 FCI(Failover Cluster Instance)나 AG를 구성할 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: WSFC(Windows Server Failover Clustering)에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;비즈니스 연속성과 고가용성 / 재해 복구&lt;/h2&gt; &lt;p&gt;데이터베이스는 대표적인 24시간 중단 없이 운영되어야 하는 시스템입니다. SQL Server는 이러한 비즈니스 연속성 제공을 위해 다양한 고가용성 및 장애 조치 기능과 시나리오를 제공합니다. 로그 전달 및 Always On 기능 등을 활용해 비즈니스 연속성과 고가용성 / 장애 조치를 자동화해 구현할 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 최선의 HA/DR 구성 방안은, 클라우드 마이그레이션을 통해 점차 서비스를 On-Premise에서 클라우드로 이전하는 방안이며, 특히, 클라우드 서비스 제공자(CSP)가 제공하는 DaaS를 활용해 운영에 대한 비용을 낮추고, 개발에만 초점을 맞춰 운영하는 방안을 추천해 드립니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>고가용성</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124837</guid>
			<comments>https://www.sqler.com/board_Column/1124837#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:26:40 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 13-4. 백업과 복원 - 유지 관리 계획 수립</title>
			<link>https://www.sqler.com/board_Column/1124834</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 13-4. 백업과 복원 - 유지 관리 계획 수립을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 백업과 복원 - 유지 관리 계획 수립입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/oCtCuinDkkA?si=oISk60PK_ULCqrMG&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;데이터베이스 유지관리 계획(Database Maintenance Plan)은 데이터베이스에서 수행해야 하는 유지관리 작업을 주기적으로 자동 실행하기 위한 SQL Server의 관리 기능입니다. 유지 관리 계획 구성과 전체 백업, 로그 백업 태스크 내용도 진행됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 데이터베이스 유지관리 계획(Database Maintenance Plan)은 종합적으로 데이터베이스를 유지 관리하기 위한 기능입니다. 백업 / 인덱스 관리 등 주기적으로 진행해야 하는 작업을 자동적으로 수행할 수 있도록 설정하는 매우 유용한 SQL Server의 관리 기능입니다.&lt;br /&gt; 유지 관리 계획 수립 전에 아래 두 가지 내용을 미리 체크합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;DBCC CHECKDB - 데이터베이스 개체의 무결성 검사&lt;/h2&gt; &lt;p&gt;이름부터 뭔가 DB를 체크할 것 같은 느낌이 드는 명령입니다. 수행하면 지정한 데이터베이스에서 모든 개체의 무결성을 검사하게 됩니다.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;참조 무결성 검사인가요? 왜 이걸 유지 관리 작업으로 수행하나요?&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;br /&gt; 데이터베이스는 바이너리 형식으로 디스크에 저장됩니다. 디스크는 물리적인 저장소로, 일정 시간 사용하게 되면 배드섹터(Bad sector)나 손상이 발생하는 소비재입니다. 디스크 액세스(Access)가 많은 데이터베이스는 디스크 소모가 극심하고, 손상되면 치명적인 사태가 발생할 수 있습니다. 즉, 주기적으로 데이터베이스의 물리적/논리적 무결성을 검사해야 합니다. 이 무결성 검사 명령이 DBCC CHECKDB입니다.(참조 무결성 검사 아닙니다.)&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;CHECKDB 명령은 다음과 같이 수행할 수 있습니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; DBCC&amp;nbsp;CHECKDB(&amp;#39;AdventureWorks&amp;#39;);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; DBCC&amp;nbsp;results&amp;nbsp;for&amp;nbsp;&amp;#39;AdventureWorks&amp;#39;.&lt;br /&gt; Service&amp;nbsp;Broker&amp;nbsp;Msg&amp;nbsp;9675,&amp;nbsp;State&amp;nbsp;1:&amp;nbsp;Message&amp;nbsp;Types&amp;nbsp;analyzed:&amp;nbsp;14.&lt;br /&gt; DBCC&amp;nbsp;results&amp;nbsp;for&amp;nbsp;&amp;#39;sys.sysrscols&amp;#39;.&lt;br /&gt; There&amp;nbsp;are&amp;nbsp;2445&amp;nbsp;rows&amp;nbsp;in&amp;nbsp;28&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;object&amp;nbsp;&amp;quot;sys.sysrscols&amp;quot;.&lt;br /&gt; DBCC&amp;nbsp;results&amp;nbsp;for&amp;nbsp;&amp;#39;sys.sysrowsets&amp;#39;.&lt;br /&gt; &amp;hellip;&lt;br /&gt; CHECKDB&amp;nbsp;found&amp;nbsp;0&amp;nbsp;allocation&amp;nbsp;errors&amp;nbsp;and&amp;nbsp;0&amp;nbsp;consistency&amp;nbsp;errors&amp;nbsp;in&amp;nbsp;database&amp;nbsp;&amp;#39;AdventureWorks&amp;#39;.&lt;br /&gt; DBCC&amp;nbsp;execution&amp;nbsp;completed.&amp;nbsp;If&amp;nbsp;DBCC&amp;nbsp;printed&amp;nbsp;error&amp;nbsp;messages,&amp;nbsp;contact&amp;nbsp;your&amp;nbsp;system&amp;nbsp;administrator.&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;클라우드 데이터베이스 - PaaS를 이용한다면, DBCC CHECKDB를 실행할 일이 많지 않습니다. 만약, On-Premise의 SQL Server에서 DBCC CHECKDB 오류를 만나면 다음 절차를 고려합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;DBCC CHECKDB(&amp;lsquo;DB명&amp;rsquo;, REPAIR_REBUILD)로 데이터 손실 가능성이 없는 복원을 시도&lt;/li&gt; &lt;li&gt;REPAIR_REBUILD로 복원 불가하다면, SQL Server를 잠시 중지하고 백업 파일 또는 데이터파일과 로그 파일(mdf / ldf)을 복사하고 다른 디스크나 시스템에서 복원이나 Attach 해 데이터 복원 시도&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;이렇게 복원을 시도합니다. 더 좋은 방법은 데이터베이스 디스크 등의 장비에 RAID1나 RAID5 등 미러링이나 패리티 체크 장비를 이용하는 방법이며, 점차 클라우드로 이전하는 방안입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 위의 시도로 복원이 안된다면, 이제부터 데이터 손실 가능성이 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;DBCC CHECKDB - REPAIR_ALLOW_DATA_LOSS로 일부 데이터 손실을 감수하고 복원 시도&lt;/li&gt; &lt;li&gt;손실이 크다면 최근 정상 백업본에서 복원 수행&lt;br /&gt; 비즈니스 결정으로 손상이 커서 복원이 어렵다면, 최근 정상 백업으로 디스크 등의 하드웨어 등을 교체하고 복원 수행&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;이런 상황을 예방하는 방법은 곧 진행될 유지 관리 계획의 일부로 DBCC CHECKDB를 수행해 미리 예방하는 방안입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: RAID1, RAID5, 패리티 체크 장비(Parity Check Device)에 대해서 알려줘&lt;br /&gt; ☑️ 챗GPT 활용: 클라우드 환경에 디스크 장애가 거의 없는 이유에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL Server 에이전트(Agent)&lt;/h2&gt; &lt;p&gt;SQL Server에서 주기적으로 실행하는 이런 자동화 작업은 어떤 원리로 실행되는 것일까요? SQL Server는 데이터베이스 엔진 프로세스와 SQL Server Agent 스케줄러 서비스 프로세스로 분리되어 있습니다. 이 SQL Server Agent는 자동화와 관련된, 주기적으로 실행하는 작업을 트리거하거나 SQL Mail 등의 설정으로 알림을 보내는 작업을 수행하는 프로세스입니다. 리눅스의 Systemd(또는 Cron)이나 윈도의 작업 스케줄러와 유사하지만, SQL Server 작업에 특화되어 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: 리눅스 Systemd와 Cron 스케줄러에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;SSMS 개체 탐색기의 아래쪽에서 SQL Server Agent 서비스를 확인 가능합니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-1-SQL Server Agent.png&quot; data-file-srl=&quot;1125777&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/aca6a855d60a59c4ab5c902e3219c1e4.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - SQL Server Agent&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;만약, SQL Server Agent가 기본 중지 상태라고 놀라지 마세요. 윈도일 경우, 수동 시작으로 기본 설정되며, 윈도의 &amp;ldquo;서비스&amp;rdquo;에서 자동으로 변경해야 시스템이 재시작되어도 백그라운드에서 자동으로 시작됩니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 윈도키+R 키를 눌러 실행 창 시작 - services.msc 실행 - SQL Server Agent 서비스 설정을 자동 시작 유형으로 변경하고 확인&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;141-2 SQL Server Agent Service.png&quot; data-file-srl=&quot;1125778&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/12a72155398821bcc55fc7b836cef82b.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - SQL Server Agent Service&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;데이터베이스 유지 관리 계획 수립&lt;/h2&gt; &lt;p&gt;데이터베이스 유지 관리 계획은 SQL Server의 여러 관리 작업을 자동화하는 기능입니다. 백업 / 인덱스 재구축 등, 관리자의 작업이 개입되어야 하는 다양한 업무를 자동적으로 수행하는 매우 유용한 기능입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 유지 관리 계획은 아래의 작업으로 구성됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;141-3 유지관리계획.png&quot; data-file-srl=&quot;1125779&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/f880d7bcdaf5010115dc532311e42a49.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 태스크&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;1. 데이터베이스 무결성 검사&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;DBCC CHECKDB 명령이 실행되며 무결성 검사가 진행됩니다. 전체 백업 전에 수행하는 것이 좋습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;2. 데이터베이스 축소&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;데이터베이스 축소 작업으로 DBCC SHRINKDATABASE 작업을 수행합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;3. 인덱스 다시 구성&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;인덱스 REORGANIZE 작업입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;4. 인덱스 다시 작성&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;인덱스 REBUILD 작업입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;5. 통계 업데이트&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;UPDATE STATISTICS 작업을 수행합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;6. 기록 정리&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;설정한 기간보다 오래된 작업 히스토리(job history)나 유지 관리 계획 기록을 msdb에서 주기적으로 삭제하는 유지 관리 계획을 생성합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;7. SQL Server 에이전트 작업 실행&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;SQL Server Agent 작업 중 실행할 작업을 유지 관리 계획으로 생성합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;8. 데이터베이스 백업(전체)&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;전체 백업을 수행합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;9. 데이터베이스 백업(차등)&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;차등 백업을 수행합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;10. 데이터베이스 백업(트랜잭션 로그)&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;트랜잭션 로그 백업을 수행합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;strong&gt;11. 유지 관리 정리 태스크&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;지정한 기간보다 오래된 유지 관리 계획에서 생성된 텍스트 보고서나 백업 파일을 삭제하는 유지 관리 계획을 생성합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;유지 관리 계획 패턴은 비슷합니다. 실행할 작업과 스케줄을 정의하면 해당 스케줄에 맞춰 작업이 실행됩니다. 다음 작업을 묶어서 수행하는 것이 좋습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;전체 백업 추천 태스크&lt;/h3&gt; &lt;p&gt;- 데이터베이스 무결성 검사(전체)&lt;br /&gt; - 인덱스 다시 작성&lt;br /&gt; - 데이터베이스 백업(전체)&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;로그 백업 추천 태스크&lt;/h3&gt; &lt;p&gt;- 데이터베이스 무결성 검사(물리적 전용)&lt;br /&gt; - 인덱스 다시 구성&lt;br /&gt; - 데이터베이스 백업(트랜잭션 로그)&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;유지 관리 계획 마법사 실행 - 전체 백업&lt;/h2&gt; &lt;p&gt;이제, 유지 관리 계획 마법사를 실행하고 관리 계획을 생성하겠습니다.&amp;nbsp;&lt;br /&gt; 매일 주기적으로 전체 백업을 수행하고, 매 시간 트랜잭션 로그를 백업하는 유지 관리 계획을 생성합니다.&amp;nbsp;&lt;br /&gt; 아래와 같이 SSMS의 관리 - 유지 관리 계획에서 유지 관리 계획 마법사를 실행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-6-유지관리계획.png&quot; data-file-srl=&quot;1125780&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/cd308856fdb884a3ea378520480faa24.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 실행&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 유지관리 계획 마법사를 실행하면 간단한 소개가 진행됩니다. 다음을 진행합니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-5-유지관리계획마법사.png&quot; data-file-srl=&quot;1125781&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/d3db2fbdd7d8152c622c6cdf70fd5145.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 마법사&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;계획 속성을 선택합니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-7-유지관리계획속성.png&quot; data-file-srl=&quot;1125782&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/315be539f0529bbd7ac831534025a400.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 속성&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;ldquo;다음 계정으로 실행&amp;rdquo;에서 기본적으로 SQL Agent 프로세스로 스케쥴링하고 SQL Agent 계정의 권한으로 작업을 실행합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &amp;ldquo;일정&amp;rdquo;에서는 다양한 일정 패턴을 구성할 수 있습니다. 매시간, 매일, 매주 특정 요일 작업을 설정할 수 있으며, 이번 강좌에서는 다음과 같이 일정을 설정합니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-8-유지관리계획_작업스케쥴.png&quot; data-file-srl=&quot;1125783&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/55da675322cb9ff2cc642a0d341c18d2.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 작업스케줄&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;- 매일, 오전 12시 5분 진행&lt;/strong&gt;&lt;br /&gt; 5분으로 지정하는 이유는, 다른 관리자에 의해 이미 생성된 정시 실행 스케줄 패턴이 있을 수 있으며, 이를 피하기 위해 약간 시간을 딜레이 시켜 진행합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;유지 관리 태스크 선택&lt;/h3&gt; &lt;p&gt;간단히 소개해 드렸던 다음 세 가지 작업을 전체 백업을 위해 수행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-9-유지관리계획_태스크 선택.png&quot; data-file-srl=&quot;1125784&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/dc02541b1180d4d6ff3512fc89d6c902.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 -태스크 선택&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&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;&amp;nbsp;&lt;/p&gt; &lt;p&gt;유지 관리 태스크 작업 순서를 설정합니다. 무결성 검사, 인덱스 다시 작성, 전체 백업 순서로 설정합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-10-유지관리계획_태스크순서.png&quot; data-file-srl=&quot;1125785&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/3503af46026b7033cc195407bd8a9d58.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 태스크순서&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;유지 관리 계획 - 무결성 검사 태스크&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;144-11-유지관리계획_무결성 검사 태스크.png&quot; data-file-srl=&quot;1125786&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/e836bc6f8418c66bb807ee2c1bedfbdc.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 무결성 검사 태스크&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 무결성 검사를 진행할 데이터베이스를 선택합니다. 사용자 데이터베이스를 선택하면 되며, 이번 강좌에서 진행한 bkup_test 데이터베이스를 선택합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 설정 중에 &amp;ldquo;물리적 전용&amp;rdquo; 체크를 제거합니다. 물리적 전용(Physical only)은 페이지와 헤더의 물리적 구조 무결성과 일관성만 검사합니다. DBCC CHECKDB 실행 시간은 줄어들지만, 전체 백업 과정의 일부로 진행하므로, 체크를 제거해 데이터베이스의 모든 무결성을 검사합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; Tablock은 다음 강좌에서 진행하는 잠금 설정입니다. 무결성 검사 세션에게 테이블 단위 잠금을 적용해 다른 세션이 테이블에 접근해 작업할 경우 대기하도록 설정합니다. 무결성 검사에 우선순위를 두고 작업할 경우 설정 가능합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 최대 병렬 수준 - DOP(Degree of Parallelism)는 병렬 작업 설정입니다. 무결성 검사에서 사용할 최대 병렬 CPU를 제한하는 설정입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 위의 이미지와 같이 &amp;ldquo;인덱스 포함&amp;rdquo;만 체크하고 다음 과정을 진행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;유지 관리 계획 - 인덱스 다시 작성 태스크&lt;/h3&gt; &lt;p&gt;인덱스 다시 작성은 이전 &lt;a href=&quot;https://www.sqler.com/board_Column/1124819&quot;&gt;12-8. 인덱스 생성과 관리 - 인덱스 재구성/재구축 강좌&lt;/a&gt;에서 진행한 인덱스 재구축(Rebuild) 작업입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-12-유지관리계획_인덱스-다시-작성 태스크.png&quot; data-file-srl=&quot;1125787&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/12ff307547e507538e1f4b25eff0ba5f.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 인덱스 다시 작성 태스크&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;지난 인덱스 강좌와 인덱스 재구성 작업을 다시 떠올려 보면 어렵지 않습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 데이터베이스와 개체를 선택합니다. 개체는 테이블만 / 뷰만 / 테이블과 뷰 모두 작업 중 선택합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 사용 가능한 공간 옵션은 인덱스의 채우기 비율(FILLFACTOR)을 설정합니다. 인덱스를 생성할 때 지정한 FILLFACTOR 대로 인덱스 다시 작성을 수행하거나, 지정한 FILLFACTOR로 설정합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 고급옵션에서 tempdb 결과 정렬은 인덱스 정렬 시 임시 공간으로 tempdb를 사용하는 설정이며, &amp;ldquo;인덱스 패딩&amp;rdquo;은 &lt;a href=&quot;https://www.sqler.com/board_Column/1124813&quot;&gt;12-7. 인덱스 생성과 관리 - 인덱스 옵션&lt;/a&gt;에서 소개한 PAD_INDEX 설정이며 인덱스의 중간 레벨(Non-leaf) 레벨까지 여유를 두게 됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 인덱스를 온라인으로 유지하는 설정은 인덱스 재구축 작업 중에 인덱스에 액세스 가능한 옵션입니다.(SQL Server Enterprise 에디션에서만 제공되는 기능)&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 인덱스 검색 유형은 통계 수집 옵션으로 &amp;ldquo;빠르게&amp;rdquo; 설정을 수행해 인덱스 통계를 수집합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 마지막 인덱스 최적화 조건은 조각화(Fragmentation)가 30% 일 경우에만 인덱스를 재작성하고, 페이지 수가 최소 1천 개 = 8KB * 1천 개면 약 8M 이상일 경우에만(최소 8M 이상) 재작성하도록 설정합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 필요에 따라 인덱스 다시 작성 태스크를 설정하고, 다음 과정을 진행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;유지 관리 계획 - 전체 백업&lt;/h3&gt; &lt;p&gt;마지막 단계인 전체 백업 단계입니다. 마찬가지로, 전체 백업 과정과 설정을 그대로 유지 관리 계획에서 선택합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-13-유지관리계획_전체백업-일반.png&quot; data-file-srl=&quot;1125788&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/5a17aa95084ba0c7bcb11b4654281175.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 전체백업-일반&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;백업할 데이터베이스를 선택합니다. 데이터베이스를 여러 개의 파일 및 파일 그룹으로 생성했을 경우 &amp;ldquo;파일 및 파일 그룹&amp;rdquo; 단위 백업도 가능합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 백업할 위치는 &amp;ldquo;디스크&amp;rdquo;, &amp;ldquo;테이프&amp;rdquo;, &amp;ldquo;URL&amp;rdquo;이 가능하며 URL은 클라우드 서비스 제공자(CSP)의 blob 저장소에 백업을 보관할 수 있습니다. 예를 들어, Microsoft Azure Blob Storage에 저장 가능합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: 클라우드 서비스 제공자(CSP)의 blob 저장소 종류에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-14-유지관리계획_전체백업-대상.png&quot; data-file-srl=&quot;1125789&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/a2e3946a35e24e3876f593988fa2b8c7.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 전체백업 대상&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;전체 백업 - 대상 탭에서는 백업 파일 타깃을 설정합니다. &amp;ldquo;모든 데이터베이스에 대한 백업 파일 만들기&amp;rdquo; 설정은 지정한 폴더에 백업 파일을 생성하고, 데이터베이스 당 하나의 파일을 생성합니다. 테이프나 디스크 디바이스를 이용할 경우 해당 장치에 백업할 수 있습니다. 백업 대상은 반드시 데이터베이스와 물리적으로 다른 시스템/디스크에 저장하세요. 가능하다면, 클라우드 저장소에 백업하는 것도 좋은 선택입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-14-유지관리계획_전체백업-옵션.png&quot; data-file-srl=&quot;1125790&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/6a8058954f22fd659ecfd1dd61f59f31.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 전체백업 옵션&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 백업을 압축하거나, 백업 세트 만료 기간을 설정할 수 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 백업 암호화 옵션은 백업 파일을 보호하는 설정입니다. 만약 백업 대상 위치에 대한 보안 설정이 어려워 백업본 접근 제한이 어렵다면, 암호화를 이용해 백업하고, 반드시 설정한 암호키를 안전한 장소에 잘 기록해 두세요.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: AES 암호화 알고리즘에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-17-유지관리계획_전체백업-보고서.png&quot; data-file-srl=&quot;1125791&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/c9453d45b71321bfd12890dfbcafb48d.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 전체백업 보고서&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;다음 과정은 보고서 작성입니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-18-유지관리계획_전체백업-완료.png&quot; data-file-srl=&quot;1125792&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/596b5bc8dd6da86eb47e0c314c80c5ae.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 전체백업 완료&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;모든 과정을 완료했습니다. 설정을 리뷰하고 유지 관리 계획을 생성합니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-19-유지관리계획_전체백업-완료.png&quot; data-file-srl=&quot;1125793&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/e91e42ed3c34b4603adbb65c1c3e2681.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 전체백업 진행&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 전체 백업 과정을 완료합니다. 생성이 완료되면 유지 관리 계획에서 리프레시하고 생성한 계획을 확인합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-20-유지관리계획_확인.png&quot; data-file-srl=&quot;1125794&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/3b4bd48968220e1fbb694a7854cd483a.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 확인&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 전체 백업 과정 - 유지 관리 계획이 잘 생성되었습니다. 주기적으로 유지 관리 계획에서 수립한 과정들이 잘 수행되는지 확인해 보시길 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 유지 관리 계획 마법사 실행 - 로그 백업&lt;/h2&gt; &lt;p&gt;다음으로, 로그 백업 과정을 유지 관리 계획으로 생성합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;유지 관리 태스크에서 다음 세 가지 작업을 선택합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&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;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;144-23-유지관리계획_로그백업-스케쥴.png&quot; data-file-srl=&quot;1125795&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/5aa3784806b0b9266e8065c8934765ec.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 로그백업 스케줄&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;계획 속성 선택에서 일정을 매 시간으로 설정합니다.&lt;/p&gt; &lt;h3&gt;&lt;br /&gt; 유지 관리 계획 -무결성 검사&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;144-21-유지관리계획_로그백업-무결성검사.png&quot; data-file-srl=&quot;1125796&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/6030377c265e79d027906517a1924e6f.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 로그백업 무결성 검사&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;매 시간 실행되는 작업이기 때문에 전체 검사는 필요하지 않습니다. &amp;ldquo;물리적 전용&amp;rdquo;을 체크하고 검사합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;인덱스 다시 구성 태스크&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;144-21-유지관리계획_로그백업-인덱스재구성.png&quot; data-file-srl=&quot;1125797&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/122200bfe0b7ae1173643580b078d3b0.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 로그백업 - 인덱스 재구성&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 다시 구성은 인덱스 REORGANIZE 작업입니다. 기본 설정으로 &amp;ldquo;빠르게&amp;rdquo; 통계를 수집하고, 조각화가 15% 이상, 페이지 수가 1천 개 이상일 경우에 동작하도록 설정합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;데이터베이스 백업(트랜잭션 로그) 태스크&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;144-22-유지관리계획_로그백업-로그백업.png&quot; data-file-srl=&quot;1125798&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/f3bd27b010993157e74d6b81efe09df2.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 유지 관리 계획 - 로그백업&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;트랜잭션 로그 설정이 기본 선택되고, 백업할 데이터베이스만 선택합니다. 나머지 대상 및 옵션 탭은 기본으로 설정하며, 특정 옵션이 필요할 경우 변경해 실행하세요.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 위의 과정을 수행해 트랜잭션 로그 백업 유지 관리 계획을 생성할 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 유지 관리 태스크에서 &amp;ldquo;기록 정리&amp;rdquo;, &amp;ldquo;유지 관리 정리 태스크&amp;rdquo;는 강좌에서 진행하지 않았지만 이전 기록들을 특정 기간 후 삭제하는 과정이므로, 직접 진행해 보시길 바랍니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 아울러, SQL Server 시스템 데이터베이스 역시 주기적으로 백업해야 합니다. 유지 관리 계획을 수립해 시스템 데이터베이스 역시 주기적으로 전체 백업을 수행해 안전한 장소에 저장 하시기 바랍니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>데이터베이스 유지관리 계획</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124834</guid>
			<comments>https://www.sqler.com/board_Column/1124834#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:26:16 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 13-3. 백업과 복원 - 백업과 복원 전략 실행</title>
			<link>https://www.sqler.com/board_Column/1124831</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 13-3. 백업과 복원 - 백업과 복원 전략 실행을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 백업과 복원 - 백업과 복원 전략 실행입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/HBvrJJSg3BQ?si=UA7x7icVHre3tmSv&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;단순 복구 모델 복원과정을 설명하며, 전체 백업과 로그 백업이 적용된 전체 복구 모델 백업본 복원 과정도 소개합니다. 특정 시점 복원과 비상 로그 백업 및 복원 절차를 단계별로 설명하며, 백업과 복원 옵션, 데이터베이스 사용자 프로세스 정리, 단일 사용자 모드 작업에 관한 내용도 진행됩니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;br /&gt; 지난 백업과 복원 전략 강좌에서 진행한 단순 복구 모델과 전체 복구 모델을 살펴보겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;단순 복구 모델&lt;/h2&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;단순&amp;nbsp;복구&amp;nbsp;모델&amp;nbsp;설정&lt;br /&gt; USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;생성&lt;br /&gt; CREATE&amp;nbsp;DATABASE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델&amp;nbsp;확인&lt;br /&gt; SELECT&amp;nbsp;name,&amp;nbsp;recovery_model_desc&amp;nbsp;FROM&amp;nbsp;sys.databases&lt;br /&gt; WHERE&amp;nbsp;name&amp;nbsp;LIKE&amp;nbsp;&amp;#39;bkupTest&amp;#39;;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델을&amp;nbsp;단순&amp;nbsp;복구&amp;nbsp;모델로&amp;nbsp;변경&lt;br /&gt; ALTER&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;SET&amp;nbsp;RECOVERY&amp;nbsp;SIMPLE;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --테이블&amp;nbsp;생성&lt;br /&gt; DROP&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;EXISTS&amp;nbsp;RecoveryTest;&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;RecoveryTest(&lt;br /&gt; idx&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INT,&lt;br /&gt; dt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DATETIME&amp;nbsp;DEFAULT(GETDATE())&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터를&amp;nbsp;삽입하고&amp;nbsp;테스트&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(1);&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --파일로&amp;nbsp;전체&amp;nbsp;백업&amp;nbsp;--&amp;nbsp;초기화&amp;nbsp;옵션,&amp;nbsp;10%마다&amp;nbsp;진행&amp;nbsp;상태&amp;nbsp;정보&amp;nbsp;출력&lt;br /&gt; BACKUP&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;TO&amp;nbsp;DISK=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;&amp;nbsp;WITH&amp;nbsp;INIT,&amp;nbsp;STATS=10;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --결과&lt;br /&gt; 11&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 20&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 30&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 41&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 50&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 60&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 71&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 80&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 90&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 100&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; Processed&amp;nbsp;520&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; Processed&amp;nbsp;1&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest_log&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; BACKUP&amp;nbsp;DATABASE&amp;nbsp;successfully&amp;nbsp;processed&amp;nbsp;521&amp;nbsp;pages&amp;nbsp;in&amp;nbsp;0.025&amp;nbsp;seconds&amp;nbsp;(162.558&amp;nbsp;MB/sec).&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;SHUTDOWN&amp;nbsp;수행&lt;br /&gt; SHUTDOWN;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;SHUTDOWN을 수행하면, SQL Server 인스턴스가 멈춥니다. 이제 장애 상황을 가정합니다. bkupTest 데이터베이스의 데이터 MDF 파일 - bkupTest.mdf을 &amp;nbsp;삭제합니다.(기본 SQL Server 데이터베이스 설치 경로는 &amp;ldquo;C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA&amp;rdquo;입니다.)&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SSMS에서 SQL Server 인스턴스를 시작합니다. 좌측 개체 탐색기에서 맨 위의 SQL Server 인스턴스 선택 - 시작하면 됩니다. 예상대로, bkupTest 데이터베이스에 &amp;ldquo;복구 보류 중&amp;rdquo; 오류가 발생합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;143_1 데이터베이스 장애 발생.png&quot; data-file-srl=&quot;1125766&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/36df7c744449df12ab4d901c5c5491ac.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 데이터베이스 장애 발생&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;데이터베이스 업계에서 가장 두렵다는 공포의 서스펙트 모드(Suspect mode), 혼수상태입니다. 이렇게 데이터베이스 이름이 나오는 이유는 뭘까요? 데이터베이스 이름과 같은 메타 정보는 master 데이터베이스에 있기 때문입니다. mdf - 주 데이터 파일을 삭제했으니 당연히 오류가 발생합니다. 이제 백업본을 이용해 복원을 진행하겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;데이터베이스&amp;nbsp;접근&amp;nbsp;시도&lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; 오류&amp;nbsp;발생&amp;nbsp;&lt;br /&gt; 메시지&amp;nbsp;945,&amp;nbsp;수준&amp;nbsp;14,&amp;nbsp;상태&amp;nbsp;2,&amp;nbsp;줄&amp;nbsp;2&lt;br /&gt; Database&amp;nbsp;&amp;#39;bkupTest&amp;#39;&amp;nbsp;cannot&amp;nbsp;be&amp;nbsp;opened&amp;nbsp;due&amp;nbsp;to&amp;nbsp;inaccessible&amp;nbsp;files&amp;nbsp;or&amp;nbsp;insufficient&amp;nbsp;memory&amp;nbsp;or&amp;nbsp;disk&amp;nbsp;space.&amp;nbsp;&amp;nbsp;See&amp;nbsp;the&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;errorlog&amp;nbsp;for&amp;nbsp;details.&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --복원&amp;nbsp;수행&amp;nbsp;-&amp;nbsp;성공&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;조회&amp;nbsp;가능&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;다시 개체 탐색기의 데이터베이스들을 새로고침 해보면 정상 상태로 돌아온 것을 확인할 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 어떤 백업본을 복원할 수 있었나요? 가장 최근의 전체 백업본까지 복구가 가능합니다. 로그 백업도 불가합니다. 복구 모델이 단순 복구 모델이기 때문입니다. 하지만, 자동으로 로그를 비워주니 로그 저장소가 한없이 커지는 사태는 발생하지 않겠지요. 단순 복구 모델은 혼자 개발하거나 테스트하는 용도가 아니면 거의 사용되지 않고, 대부분 전체 복구 모델을 사용합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 다음은 전체 백업과 로그백업을 확인하겠습니다.&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; &lt;br /&gt; 전체 복구 모델로 전체 백업과 로그 백업 수행&lt;/h2&gt; &lt;p&gt;앞으로 가장 많이 사용하게 될 전체 백업과 로그 백업 수행 방식입니다. 꼭 전체 과정을 이해하시고, 이어지는 강좌 - 유지관리 계획에 전체 백업과 로그 백업 자동화를 수립하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델&amp;nbsp;확인&lt;br /&gt; SELECT&amp;nbsp;name,&amp;nbsp;recovery_model_desc&amp;nbsp;FROM&amp;nbsp;sys.databases&lt;br /&gt; WHERE&amp;nbsp;name&amp;nbsp;LIKE&amp;nbsp;&amp;#39;bkupTest&amp;#39;;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델이&amp;nbsp;전체가&amp;nbsp;아닐&amp;nbsp;경우&amp;nbsp;전체로&amp;nbsp;변경&lt;br /&gt; ALTER&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;SET&amp;nbsp;RECOVERY&amp;nbsp;FULL;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --테이블을&amp;nbsp;생성합니다.&lt;br /&gt; DROP&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;EXISTS&amp;nbsp;RecoveryTest;&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;RecoveryTest(&lt;br /&gt; idx&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INT,&lt;br /&gt; dt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DATETIME&amp;nbsp;DEFAULT(GETDATE())&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터를&amp;nbsp;삽입하고&amp;nbsp;테스트&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(1);&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --파일로&amp;nbsp;백업&amp;nbsp;--&amp;nbsp;초기화&amp;nbsp;옵션,&amp;nbsp;10%마다&amp;nbsp;진행&amp;nbsp;상태&amp;nbsp;정보&amp;nbsp;출력&lt;br /&gt; BACKUP&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;TO&amp;nbsp;DISK=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;&amp;nbsp;WITH&amp;nbsp;INIT,&amp;nbsp;STATS=10;&amp;nbsp;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --결과&lt;br /&gt; 11&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 20&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 30&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 41&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 50&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 60&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 71&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 80&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 90&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; 100&amp;nbsp;percent&amp;nbsp;processed.&lt;br /&gt; Processed&amp;nbsp;520&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; Processed&amp;nbsp;1&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest_log&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; BACKUP&amp;nbsp;DATABASE&amp;nbsp;successfully&amp;nbsp;processed&amp;nbsp;521&amp;nbsp;pages&amp;nbsp;in&amp;nbsp;0.025&amp;nbsp;seconds&amp;nbsp;(162.558&amp;nbsp;MB/sec).&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;전체&amp;nbsp;백업&amp;nbsp;후&amp;nbsp;데이터를&amp;nbsp;삽입하고&amp;nbsp;테스트&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(2);&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;로그&amp;nbsp;백업&amp;nbsp;수행&lt;br /&gt; BACKUP&amp;nbsp;LOG&amp;nbsp;bkupTest&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&amp;#39;c:\backup\bkupTest_log_bkup01&amp;#39;&amp;nbsp;WITH&amp;nbsp;INIT;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;로그&amp;nbsp;백업&amp;nbsp;후&amp;nbsp;데이터를&amp;nbsp;삽입하고&amp;nbsp;테스트&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(3);&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;인스턴스&amp;nbsp;종료.&lt;br /&gt; SHUTDOWN;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;자 잘 기억해 두세요. 로그 백업이 어디까지 진행되었나요? 2번 데이터를 넣고 나서 로그 백업을 수행했고, 3번 데이터를 넣었으나, 장애가 발생했습니다. 3번 데이터는 로그 백업에 포함되어 있지 않습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이제 다시 bkupTest 데이터베이스의 데이터파일 MDF를 삭제합니다. 그리고 SSMS에서 SQL Server 인스턴스를 다시 시작하세요. 전체 백업과 로그 백업본 복원을 시작합니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;복원&amp;nbsp;시도&amp;nbsp;전에&amp;nbsp;항상&amp;nbsp;로그&amp;nbsp;백업을&amp;nbsp;먼저&amp;nbsp;시도&lt;br /&gt; --&amp;nbsp;WITH&amp;nbsp;NO_TRUNCATE&amp;nbsp;옵션은&amp;nbsp;데이터베이스&amp;nbsp;손상&amp;nbsp;시에도&amp;nbsp;로그에&amp;nbsp;접근이&amp;nbsp;가능하면&amp;nbsp;로그를&amp;nbsp;백업하는&amp;nbsp;옵션.&lt;br /&gt; BACKUP&amp;nbsp;LOG&amp;nbsp;bkupTest&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&amp;#39;c:\backup\bkupTest_taillog_bkup&amp;#39;&amp;nbsp;WITH&amp;nbsp;NO_TRUNCATE,&amp;nbsp;INIT;&lt;br /&gt; GO&lt;br /&gt; --&amp;nbsp;WITH&amp;nbsp;NO_TRUNCATE로&amp;nbsp;로그&amp;nbsp;백업&amp;nbsp;성공&lt;br /&gt; Processed&amp;nbsp;2&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest_log&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; BACKUP&amp;nbsp;LOG&amp;nbsp;successfully&amp;nbsp;processed&amp;nbsp;2&amp;nbsp;pages&amp;nbsp;in&amp;nbsp;0.006&amp;nbsp;seconds&amp;nbsp;(1.953&amp;nbsp;MB/sec).&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;전체&amp;nbsp;백업&amp;nbsp;복원.&amp;nbsp;NORECOVERY로&amp;nbsp;이어지는&amp;nbsp;복원&amp;nbsp;항목&amp;nbsp;있음&amp;nbsp;옵션&amp;nbsp;설정.&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;&lt;br /&gt; WITH&amp;nbsp;NORECOVERY;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;1차&amp;nbsp;로그&amp;nbsp;백업&amp;nbsp;복원.&amp;nbsp;NORECOVERY로&amp;nbsp;이어지는&amp;nbsp;복원&amp;nbsp;항목&amp;nbsp;있음&amp;nbsp;옵션&amp;nbsp;설정.&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_log_bkup01&amp;#39;&lt;br /&gt; WITH&amp;nbsp;NORECOVERY;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;2차&amp;nbsp;장애&amp;nbsp;후&amp;nbsp;백업한&amp;nbsp;로그&amp;nbsp;백업&amp;nbsp;복원.&amp;nbsp;RECOVERY로&amp;nbsp;최종&amp;nbsp;복원&amp;nbsp;옵션&amp;nbsp;설정&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_taillog_bkup&amp;#39;&lt;br /&gt; WITH&amp;nbsp;RECOVERY;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;3번&amp;nbsp;데이터까지&amp;nbsp;복원,&amp;nbsp;장애&amp;nbsp;발생&amp;nbsp;후&amp;nbsp;로그를&amp;nbsp;백업해&amp;nbsp;복원&amp;nbsp;가능&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게, 장애가 발생해도 로그 백업이 가능한 경우라면, 로그를 백업한 다음 복원을 진행해 최대한 많은 데이터를 복원할 수 있습니다. 잊지 마시고, 장애가 발생하면 항상 로그 백업을 먼저 시도하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;STOPAT을 이용한 특정 시점 복원(Point in time restore) 수행&lt;/h2&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124825&quot;&gt;13-1. 백업과 복원 - 백업과 복원 이해 강좌&lt;/a&gt;에서 자주 받는 질문으로 &amp;nbsp;이런 내용이 있었습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt; &lt;h3&gt;전체백업(O) 로그백업(X) 특정시점 복원 문의&lt;/h3&gt; &lt;p&gt;&lt;br /&gt; Q. 지속적으로 전체 백업만을 받아 왔습니다. 개발자의 실수로 update 회원테이블 set 이름 = &amp;#39;아무개&amp;#39;로 WHERE절 없이 update를 해 버렸습니다. 복원할 방법이 없을까요?&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;A. 제약 조건이 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;복구 모델이 전체 모델일 것(DB를 생성하면 기본입니다.)&lt;/li&gt; &lt;li&gt;문제 발생 후 풀백업이나 로그에 쓰지 않는 작업을 하지 않았을 것&lt;/li&gt; &lt;li&gt;로그 백업이 가능할 것입니다.&lt;/li&gt; &lt;/ul&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 괜찮습니다. 흔히 발생하는 경우이니 이렇게 FAQ에도 올라가 있지요. 더 좋은 상황은 로그도 주기적으로 백업하는 것인데 아쉽네요.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 전체 백업을 예전에 한번 이상 받았습니다. 한 번도 로그를 백업하지 않았지만, 복구 모델이 전체(FULL)이고, 로그 백업이 가능하다면, 시도해 볼 수 있습니다. 그럼 쿼리로 위의 상황을 수행해 보도록 하겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델&amp;nbsp;확인&lt;br /&gt; SELECT&amp;nbsp;name,&amp;nbsp;recovery_model_desc&amp;nbsp;FROM&amp;nbsp;sys.databases&lt;br /&gt; WHERE&amp;nbsp;name&amp;nbsp;LIKE&amp;nbsp;&amp;#39;bkupTest&amp;#39;;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델이&amp;nbsp;전체가&amp;nbsp;아닐&amp;nbsp;경우&amp;nbsp;전체로&amp;nbsp;변경&lt;br /&gt; ALTER&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;SET&amp;nbsp;RECOVERY&amp;nbsp;FULL;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --테이블을&amp;nbsp;생성합니다.&lt;br /&gt; DROP&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;EXISTS&amp;nbsp;RecoveryTest;&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;RecoveryTest(&lt;br /&gt; idx&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INT,&lt;br /&gt; dt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DATETIME&amp;nbsp;DEFAULT(GETDATE())&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터를&amp;nbsp;삽입하고&amp;nbsp;테스트&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(1);&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;전체&amp;nbsp;백업본이&amp;nbsp;반드시&amp;nbsp;1개는&amp;nbsp;있어야만&amp;nbsp;STOPAT&amp;nbsp;복원이&amp;nbsp;가능합니다.&lt;br /&gt; --&amp;nbsp;파일로&amp;nbsp;전체&amp;nbsp;백업.&amp;nbsp;INIT&amp;nbsp;초기화&amp;nbsp;옵션&lt;br /&gt; BACKUP&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;TO&amp;nbsp;DISK=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;&amp;nbsp;WITH&amp;nbsp;INIT;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; Processed&amp;nbsp;520&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; Processed&amp;nbsp;1&amp;nbsp;pages&amp;nbsp;for&amp;nbsp;database&amp;nbsp;&amp;#39;bkupTest&amp;#39;,&amp;nbsp;file&amp;nbsp;&amp;#39;bkupTest_log&amp;#39;&amp;nbsp;on&amp;nbsp;file&amp;nbsp;1.&lt;br /&gt; BACKUP&amp;nbsp;DATABASE&amp;nbsp;successfully&amp;nbsp;processed&amp;nbsp;521&amp;nbsp;pages&amp;nbsp;in&amp;nbsp;0.025&amp;nbsp;seconds&amp;nbsp;(162.558&amp;nbsp;MB/sec).&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;전체&amp;nbsp;백업&amp;nbsp;후&amp;nbsp;데이터를&amp;nbsp;삽입하고&amp;nbsp;조회&amp;nbsp;1,2,3&amp;nbsp;데이터가&amp;nbsp;존재&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(2);&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;RecoveryTest(idx)&amp;nbsp;VALUES(3);&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; --&amp;nbsp;마지막&amp;nbsp;시간을&amp;nbsp;체크하고&amp;nbsp;복사.&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;실수로&amp;nbsp;WHERE절&amp;nbsp;없이&amp;nbsp;모든&amp;nbsp;테이블&amp;nbsp;데이터를&amp;nbsp;UPDATE&amp;nbsp;함&lt;br /&gt; UPDATE&amp;nbsp;RecoveryTest&amp;nbsp;SET&amp;nbsp;idx&amp;nbsp;=&amp;nbsp;999;&lt;br /&gt; GO&lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;장애&amp;nbsp;발생.&amp;nbsp;상황을&amp;nbsp;팀원들에게&amp;nbsp;리포트&amp;nbsp;하고&amp;nbsp;복원&amp;nbsp;준비.&lt;br /&gt; --&amp;nbsp;우선&amp;nbsp;UPDATE&amp;nbsp;작업&amp;nbsp;실수&amp;nbsp;직전&amp;nbsp;시각을&amp;nbsp;확인해야&amp;nbsp;함.&lt;br /&gt; --&amp;nbsp;DATETIME&amp;nbsp;컬럼을&amp;nbsp;참고해&amp;nbsp;확인.&amp;nbsp;2023-08-04&amp;nbsp;23:13:47.693&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; --&amp;nbsp;대부분의&amp;nbsp;경우&amp;nbsp;놀라서&amp;nbsp;최근&amp;nbsp;전체&amp;nbsp;백업본&amp;nbsp;복원을&amp;nbsp;시도함.&lt;br /&gt; USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --복원을&amp;nbsp;시도하면&amp;nbsp;비상&amp;nbsp;로그&amp;nbsp;백업&amp;nbsp;오류&amp;nbsp;발생(Tail-Log&amp;nbsp;Backup&amp;nbsp;error)&lt;br /&gt; 메시지&amp;nbsp;3159,&amp;nbsp;수준&amp;nbsp;16,&amp;nbsp;상태&amp;nbsp;1,&amp;nbsp;줄&amp;nbsp;61&lt;br /&gt; The&amp;nbsp;tail&amp;nbsp;of&amp;nbsp;the&amp;nbsp;log&amp;nbsp;for&amp;nbsp;the&amp;nbsp;database&amp;nbsp;&amp;quot;bkupTest&amp;quot;&amp;nbsp;has&amp;nbsp;not&amp;nbsp;been&amp;nbsp;backed&amp;nbsp;up.&amp;nbsp;Use&amp;nbsp;BACKUP&amp;nbsp;LOG&amp;nbsp;WITH&amp;nbsp;NORECOVERY&amp;nbsp;to&amp;nbsp;backup&amp;nbsp;the&amp;nbsp;log&amp;nbsp;if&amp;nbsp;it&amp;nbsp;contains&amp;nbsp;work&amp;nbsp;you&amp;nbsp;do&amp;nbsp;not&amp;nbsp;want&amp;nbsp;to&amp;nbsp;lose.&amp;nbsp;Use&amp;nbsp;the&amp;nbsp;WITH&amp;nbsp;REPLACE&amp;nbsp;or&amp;nbsp;WITH&amp;nbsp;STOPAT&amp;nbsp;clause&amp;nbsp;of&amp;nbsp;the&amp;nbsp;RESTORE&amp;nbsp;statement&amp;nbsp;to&amp;nbsp;just&amp;nbsp;overwrite&amp;nbsp;the&amp;nbsp;contents&amp;nbsp;of&amp;nbsp;the&amp;nbsp;log.&lt;br /&gt; 메시지&amp;nbsp;3013,&amp;nbsp;수준&amp;nbsp;16,&amp;nbsp;상태&amp;nbsp;1,&amp;nbsp;줄&amp;nbsp;61&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;is&amp;nbsp;terminating&amp;nbsp;abnormally.&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;SQLER&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;항상&amp;nbsp;최우선으로&amp;nbsp;시도하세요.&amp;nbsp;가장&amp;nbsp;중요합니다.&lt;br /&gt; BACKUP&amp;nbsp;LOG&amp;nbsp;bkupTest&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TO&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;&amp;#39;c:\backup\bkupTest_taillog_bkup&amp;#39;&amp;nbsp;WITH&amp;nbsp;INIT,&amp;nbsp;NORECOVERY;&lt;br /&gt; GO&lt;br /&gt; --&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;제한&amp;nbsp;됨.&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;이제&amp;nbsp;복원&amp;nbsp;명령을&amp;nbsp;수행.&amp;nbsp;전체&amp;nbsp;백업을&amp;nbsp;복원.&amp;nbsp;NORECOVERY로&amp;nbsp;후속&amp;nbsp;복원&amp;nbsp;있음&amp;nbsp;설정.&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_full_bkup&amp;#39;&lt;br /&gt; WITH&amp;nbsp;NORECOVERY;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;STOPAT으로&amp;nbsp;특정&amp;nbsp;시간&amp;nbsp;복원&amp;nbsp;수행.&amp;nbsp;마지막&amp;nbsp;복원이니&amp;nbsp;RECOVERY&amp;nbsp;옵션&amp;nbsp;설정.&lt;br /&gt; --&amp;nbsp;DATETIME에서&amp;nbsp;기록한&amp;nbsp;시간&amp;nbsp;+&amp;nbsp;1초로&amp;nbsp;복원.&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;bkupTest&amp;nbsp;FROM&amp;nbsp;DISK&amp;nbsp;=&amp;#39;c:\backup\bkupTest_taillog_bkup&amp;#39;&lt;br /&gt; WITH&amp;nbsp;STOPAT&amp;nbsp;=&amp;nbsp;&amp;#39;2023-08-24&amp;nbsp;20:43:50.353&amp;#39;,&amp;nbsp;RECOVERY;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;bkupTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;RecoveryTest;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; idx&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dt&lt;br /&gt; -----------&amp;nbsp;-----------------------&lt;br /&gt; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2023-08-24&amp;nbsp;20:43:43.660&lt;br /&gt; 2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2023-08-24&amp;nbsp;20:43:49.353&lt;br /&gt; 3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2023-08-24&amp;nbsp;20:43:49.353&lt;br /&gt; &lt;br /&gt; (3개&amp;nbsp;행이&amp;nbsp;영향을&amp;nbsp;받음)&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게, 전체 백업만 받고 로그 백업은 한 번도 받지 않았지만 장애 상황에서 STOPAT으로 특정 시점 복원을 수행해 피해를 최소화할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;비상 로그 백업(Tail-Log Backups)&lt;/h3&gt; &lt;p&gt;비상 로그 백업은 데이터베이스 복구 모델이 전체(Full) 또는 대량로그(bulk-logged) 일 경우, 아직 백업되지 않은 로그를 백업해 데이터 손실을 최소화하는 작업입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;u&gt;데이터베이스 장애가 발생할 때, 최우선으로 실행해야 하는 작업은 복원 구문 실행이 아니라, 로그 백업입니다.&lt;/u&gt; 하지만, 긴장되고 놀라서 복원 먼저 시도하는 경우가 많습니다. SQL Server는 복원을 시도할 경우 경우, 최근 로그 백업이 없다면 위와 같이 비상 로그 백업을 권장하고 최대한 로그를 많이 백업해 복원에 이용할 것을 권장합니다. 만약, 비상 로그 백업 없이 전체 백업만 복원하려면 WITH REPLACE 옵션을 이용해 전체 백업으로 강제 복원도 가능합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;복원 소요 시간 기록&lt;/h3&gt; &lt;p&gt;항상 백업과 복원에 소요되는 시간을 주의 깊게 살펴보세요. 앞으로 기가 단위를 넘어 테라 단위의 SQL Server 데이터베이스를 다루게 될 수도 있습니다. 백업과 복원에 소요되는 시간을 항상 주의 깊게 살펴보시기 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;백업과 복원 옵션&lt;/h3&gt; &lt;p&gt;데이터베이스 백업과 복원에 여러 옵션이 있습니다. 위의 예제에서 사용한 옵션들이 일반적으로 사용되는 항목이니 천천히 살펴보시고 개발에 사용하시길 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;데이터베이스 사용자 프로세스 정리 및 단일 사용자 모드 작업&lt;/h3&gt; &lt;p&gt;복구하기 전, USE master 구문으로 master DB에서 복구를 진행하고, 데이터베이스 사용자를 스크립트로 KILL 하는 이유는 해당하는 DB가 사용 중(in-use)이면 복구가 불가하기 때문입니다. 만약, 사용자를 제어하기 어렵다면, 데이터베이스 사용자 KILL 스크립트를 실행하고, 이후 단일 사용자 모드로 세팅한 다음 진행하는 것도 방법입니다. (이미 데이터베이스 장애가 발생했으니 애플리케이션을 통해 DB 사용자가 붙어도 의미 없겠죠.)&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;데이터베이스&amp;nbsp;사용자를&amp;nbsp;자동&amp;nbsp;kill&amp;nbsp;하는&amp;nbsp;SQL&amp;nbsp;쿼리.&lt;br /&gt; --&amp;nbsp;중요&amp;nbsp;작업&amp;nbsp;프로세스가&amp;nbsp;있는지&amp;nbsp;미리&amp;nbsp;체크&lt;br /&gt; USE&amp;nbsp;master&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; DECLARE&amp;nbsp;@kill&amp;nbsp;varchar(max)&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;#39;;&lt;br /&gt; SELECT&amp;nbsp;@kill&amp;nbsp;=&amp;nbsp;@kill&amp;nbsp;+&amp;nbsp;&amp;#39;KILL&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;CONVERT(varchar(10),&amp;nbsp;spid)&amp;nbsp;+&amp;nbsp;&amp;#39;;&amp;nbsp;&amp;#39;&lt;br /&gt; FROM&amp;nbsp;master..sysprocesses&amp;nbsp;&lt;br /&gt; WHERE&amp;nbsp;spid&amp;nbsp;&amp;gt;&amp;nbsp;50&amp;nbsp;AND&amp;nbsp;dbid&amp;nbsp;=&amp;nbsp;DB_ID(&amp;#39;DATABASE_NAME&amp;#39;)&amp;nbsp;&amp;nbsp;--&amp;nbsp;데이터베이스&amp;nbsp;이름으로&amp;nbsp;변경&lt;br /&gt; EXEC(@kill);&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;데이터베이스를&amp;nbsp;단일사용자&amp;nbsp;모드로&amp;nbsp;수정&lt;br /&gt; ALTER&amp;nbsp;DATABASE&amp;nbsp;datbase_name&amp;nbsp;SET&amp;nbsp;SINGLE_USER&amp;nbsp;WITH&amp;nbsp;ROLLBACK&amp;nbsp;IMMEDIATE&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; &amp;hellip;&lt;br /&gt; &lt;br /&gt; --다시&amp;nbsp;다중사용자&amp;nbsp;모드로&amp;nbsp;수정&lt;br /&gt; ALTER&amp;nbsp;DATABASE&amp;nbsp;datbase_name&amp;nbsp;SET&amp;nbsp;MULTI_USER&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이제 유지 관리 계획을 수립해 백업과 같은 여러 관리 작업을 자동화시키는 방법을 알아보도록 하겠습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>백업과 복원</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124831</guid>
			<comments>https://www.sqler.com/board_Column/1124831#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:25:41 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 13-2. 백업과 복원 - 백업과 복원 전략</title>
			<link>https://www.sqler.com/board_Column/1124828</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 13-2. 백업과 복원 - 백업과 복원 전략을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 백업과 복원 - 백업과 복원 전략입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/CvVxQKA-pW0?si=EqukF1tIDDuaCkSw&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;전체 백업, 로그 백업, 차등 백업 시나리오와 장단점을 설명합니다. 세 가지 복원 전략을 비교하여 데이터베이스의 특성에 따라 적절한 전략을 선택하는 방법을 소개합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 백업과 복원 전략&lt;/h2&gt; &lt;p&gt;이제 백업과 복원의 중요한 전략을 수립해야 합니다. 전체 백업 / 로그 백업 / 차등 백업에 대해서 살펴보겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;1. 전체 백업만 진행할 경우&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;142-1 전체백업.PNG&quot; data-file-srl=&quot;1125751&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/f6ff13df5aafb6c8458b20a76e0c6ae9.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 먼저 이러한 타임라인을 생각해 보세요. 주단위 타임라인이며, 월요일 / 화요일 / ... &amp;nbsp;패턴입니다. 시간은 08시부터 24시간이 표시되어 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 전체 백업만 하루에 한 번 진행하면 어떻게 될까요?&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 전체 백업은 매일 아침 08시 업무가 시작되기 전에 진행됩니다. 이렇게 전체 백업만 수행해 운영하는 분들이 대단히 많을 겁니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;자 그럼, 장애 상황을 가정해 보겠습니다.&lt;/p&gt; &lt;h3&gt;&lt;br /&gt; 1. 로그를 백업하지 않으므로 로그가 계속 증가하는 상황이 발생할 수 있다.&lt;/h3&gt; &lt;p&gt;로그는 데이터의 변경 본입니다. 백업하면 비워지지만 지우지 않으므로 데이터는 50메가인데 로그는 1기가 이런 상황이 발생하며, 로그로 인해 시스템이 느려질 수 있습니다.&lt;/p&gt; &lt;h3&gt;&lt;br /&gt; 2. 장애 발생 시 복구 가능한 데이터가 가장 적다.&amp;nbsp;&lt;/h3&gt; &lt;p&gt;실제 장애 상황을 가정하겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;142-3_전체백업장애.PNG&quot; data-file-srl=&quot;1125752&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/8e29c88d6473932b1142c776a3be1506.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;자 이렇게 12시 30분에 하드웨어 장애로 데이터베이스가 깨졌다고 가정해 봅시다.(비상 로그 백업 불가 상황)&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 언제까지 데이터로 복구가 가능할까요? 가장 최근의 전체 백업본이 월요일 08시이니, 기본적으로 월요일 08시의 데이터로만 복구 가능합니다. 물론 한 번도 전체 백업을 한 적이 없다면 복구 불가 합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 08시부터 4시간 30분간의 데이터는 복구가 불가해지는 겁니다. 아득한 상황이지요.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이런 조치는 어떨까요? - &lt;em&gt;&amp;quot;그렇다면 풀백업을 한 시간에 하나씩 받으면 어떨까요?&amp;quot;&lt;/em&gt;&lt;br /&gt; 좋은 아이디어이지만 맹점이 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 전체 백업 작업을 온라인상에서 백업을 진행해도 큰 무리 없이 처리 가능하지만, 대부분 데이터의 용량은 크기가 대단히 큽니다. 데이터가 수기가 또는 수백 기가를 훌쩍 넘기도 합니다. 만약 한 시간에 한 번씩 전체 백업을 한다면? 대단히 많은 부하가 걸려 백업만 하다가 시스템 리소스를 다 소진할 수도 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 만약, 대단히 적은 데이터이지만, 매우 빈번하게 수정되고, 전체 데이터는 적게 유지되는 경우(주식 상황판 업데이트를 생각해 보세요) 이런 전체 백업 전략을 고려할 수 있지만, 아쉽게도 대부분의 경우, 전체 백업은 좋은 솔루션이 아닙니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 다른 방법으로 풀백업 + 로그 백업의 방법이 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;2. 전체 백업과 로그 백업을 진행할 경우&lt;/h3&gt; &lt;p&gt;&lt;img alt=&quot;142-4_로그백업.PNG&quot; data-file-srl=&quot;1125753&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/d2384073955ac04b9fd9a242ab53d222.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이러한 백업 패턴을 생각해 보세요. 매일 아침 08시 전체 백업을 수행하고, 매 시간마다 로그를 백업하는 패턴입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 로그를 백업해야 하기 때문에 당연히, SQL Server의 DB는 단순 복구 모델이 아닙니다. SQL서버의 데이터베이스가 단순 모델이면? 로그 백업이 불가합니다. 복구 모델이 전체 모델 또는 대량 로그(Bulk Load) 모델이어야 합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&amp;quot;저렇게 한 시간에 한 번씩 로그를 백업하는 것도 부하가 대단히 크지 않나요?&amp;quot;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;라고 생각하실 수도 있지만, 로그는 그 크기가 대단히 작습니다. 예를 들어, 애플리케이션이나 웹사이트 게시판을 생각해 보세요. INSERT / UPDATE / DELETE 작업은 대단히 적은 비율이지만, 조회는 매우 빈번합니다. 즉, 로그 데이터가 적은 경우가 대부분입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 그럼, 장애 상황을 또 가정해 보겠습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;142-5_로그백업_장애.PNG&quot; data-file-srl=&quot;1125754&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/9f7dd01367c4cc10fd4155b257ccfb4e.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이런 경우 언제까지 복구가 가능할까요?&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;142_9 데이터 상태.png&quot; data-file-srl=&quot;1125755&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/f377becbf33bf6e752501f51433294da.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 08시부터 12시 20분까지 이렇게 데이터 변경이 진행되었습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 08시 - 전체 백업본이 있습니다. 전체 백업본을 복원하면 데이터는 어떻게 될까요?&lt;/p&gt; &lt;div dir=&quot;ltr&quot;&gt;&amp;nbsp;&lt;/div&gt; &lt;table style=&quot;border-collapse:collapse; width:128pt; border:none&quot; width=&quot;170&quot;&gt; &lt;colgroup&gt; &lt;col style=&quot;width:64pt&quot; width=&quot;85&quot; /&gt; &lt;col style=&quot;width:64pt&quot; width=&quot;85&quot; /&gt; &lt;/colgroup&gt; &lt;tbody&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl69&quot; colspan=&quot;2&quot; height=&quot;17&quot; style=&quot;border:none; border-bottom:0.5pt solid black; border-right:.5pt solid #cccccc; height:12.75pt; width:128pt; text-align:center; vertical-align:middle; border-top:0.5pt solid #cccccc; border-left:0.5pt solid #cccccc; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;170&quot;&gt; &lt;div dir=&quot;ltr&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:700&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;08시 데이터&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt; &lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl67&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; background:#d9d9d9; height:12.75pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;회원 이름&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:#d9d9d9; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;나이&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; height:12.75pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;김대우&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;19&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; height:12.75pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;손석구&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;40&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;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl66&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; height:12.75pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;박은빈&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl66&quot; style=&quot;border:0.5pt solid black; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:Arial,sans-serif&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;30 &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;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 네 맞습니다. 위와 같이 08시 데이터가 살아납니다. 그러면, 우리는 여기까지만 복원이 가능한 걸까요? 아닙니다! 우리에겐 로그 백업본이 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;09시의 로그 백업본을 복원하면?&lt;/p&gt; &lt;table style=&quot;border-collapse:collapse; width:202pt; border:none&quot; width=&quot;269&quot;&gt; &lt;colgroup&gt; &lt;col style=&quot;width:64pt&quot; width=&quot;85&quot; /&gt; &lt;col style=&quot;width:64pt&quot; width=&quot;85&quot; /&gt; &lt;col style=&quot;width:74pt&quot; width=&quot;99&quot; /&gt; &lt;/colgroup&gt; &lt;tbody&gt; &lt;tr height=&quot;19&quot; style=&quot;height:14.25pt&quot;&gt; &lt;td class=&quot;xl69&quot; colspan=&quot;2&quot; height=&quot;19&quot; style=&quot;border:none; border-bottom:0.5pt solid black; height:14.25pt; width:128pt; text-align:center; vertical-align:middle; border-top:none; border-right:none; border-left:none; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;170&quot;&gt; &lt;div dir=&quot;ltr&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;09시 데이터&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt; &lt;/td&gt; &lt;td class=&quot;xl70&quot; style=&quot;border:none; background:white; width:74pt; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px; vertical-align:bottom&quot; width=&quot;99&quot;&gt;&lt;span style=&quot;font-size:11pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;19&quot; style=&quot;height:14.25pt&quot;&gt; &lt;td class=&quot;xl67&quot; height=&quot;19&quot; style=&quot;border:0.5pt solid black; background:#d9d9d9; height:14.25pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;회원 이름&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl67&quot; style=&quot;border:0.5pt solid black; background:#d9d9d9; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;나이&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl71&quot; style=&quot;border:none; border-bottom:none; background:white; border-left:none; width:74pt; border-top:none; border-right:none; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px; vertical-align:bottom&quot; width=&quot;99&quot;&gt;&lt;span style=&quot;font-size:11pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;19&quot; style=&quot;height:14.25pt&quot;&gt; &lt;td class=&quot;xl65&quot; height=&quot;19&quot; style=&quot;border:0.5pt solid black; height:14.25pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;김대우&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl65&quot; style=&quot;border:0.5pt solid black; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;19&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;/td&gt; &lt;td class=&quot;xl71&quot; style=&quot;border:none; border-bottom:none; background:white; border-left:none; width:74pt; border-top:none; border-right:none; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px; vertical-align:bottom&quot; width=&quot;99&quot;&gt;&lt;span style=&quot;font-size:11pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;19&quot; style=&quot;height:14.25pt&quot;&gt; &lt;td class=&quot;xl65&quot; height=&quot;19&quot; style=&quot;border:0.5pt solid black; height:14.25pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;손석구&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl65&quot; style=&quot;border:0.5pt solid black; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;40&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;/td&gt; &lt;td class=&quot;xl71&quot; style=&quot;border:none; border-bottom:none; background:white; border-left:none; width:74pt; border-top:none; border-right:none; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px; vertical-align:bottom&quot; width=&quot;99&quot;&gt;&lt;span style=&quot;font-size:11pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr height=&quot;17&quot; style=&quot;height:12.75pt&quot;&gt; &lt;td class=&quot;xl65&quot; height=&quot;17&quot; style=&quot;border:0.5pt solid black; height:12.75pt; border-top:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;박은빈&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt; &lt;td class=&quot;xl65&quot; style=&quot;border:0.5pt solid black; border-top:none; border-left:none; width:64pt; text-align:center; vertical-align:middle; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;85&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;29&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;/td&gt; &lt;td class=&quot;xl72&quot; style=&quot;border:none; border-bottom:none; background:white; border-left:none; width:74pt; text-align:center; vertical-align:middle; border-top:none; border-right:none; white-space:normal; padding-top:1px; padding-right:1px; padding-left:1px&quot; width=&quot;99&quot;&gt;&lt;span style=&quot;font-size:10pt&quot;&gt;&lt;span style=&quot;overflow-wrap:break-word&quot;&gt;&lt;span style=&quot;color:black&quot;&gt;&lt;span style=&quot;font-family:나눔고딕,monospace&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;text-decoration:none&quot;&gt;&lt;span style=&quot;white-space:pre-wrap&quot;&gt;&amp;lt; 데이터 수정 &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;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 네 맞습니다. 이렇게 데이터가 수정된 상태로 복원이 됩니다. 로그는 데이터의 변경입니다. 로그 백업을 적용시켜, 데이터 변경을 그대로 반영하면, 최종 데이터가 생성됩니다. 이 과정을 로그 데이터 REDO라고 부릅니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 그렇다면, 여기서 문제입니다. 9시, 10시, 11시, 12시 로그를 잘 복원했습니다. 그렇지만, 12시 20분 데이터는 로그를 백업하지 못해 복원이 불가합니다. 만약, 전체 복구 모델이고 로그 백업이 가능하다면, 12시 20분은 물론, 장애 발생 직전 12시 29분까지 복구가 가능합니다. 하지만, 장애로 인해 로그가 깨져서 로그 백업이 불가하다면 가장 최근 로그 백업까지만 복원 가능합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 마지막으로, 차등 백업에 대해서 간략하게 알아보겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;3. 차등 백업(Differential backup)&lt;/h3&gt; &lt;p&gt;앞에서 공부한 로그 백업의 범위는 이렇습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;142-6_로그백업_범위.PNG&quot; data-file-srl=&quot;1125756&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/fe53e3481b4a021db9e074dcc2362255.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;정확히 마지막 로그 백업 이후 로그 데이터만 백업합니다. 즉, 09시의 로그 백업은 08시~09시 사이의 데이터 변경만 백업합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 하지만 차등 백업은 이 범위가 약간 다릅니다.&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;142-7_차등백업.PNG&quot; data-file-srl=&quot;1125757&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/28731e4671e149a838c821193a935340.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;차등백업은 가장 최근의 전체 백업본 이후 발생한 모든 변경을 백업합니다. 즉, 09시의 차등 백업본은 08시~09시까지 데이터 변경을 백업하며, 12시의 차등 백업본은 08시~12시까지 데이터 변경을 백업합니다. 약간 복구 속도를 높일 수 있는 장점이 있고, 전체 백업본과 가장 최근 차등 백업본 총 2개만 유지하면 되기 때문에 백업본 관리가 비교적 수월합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;142_8_차등백업_장애.PNG&quot; data-file-srl=&quot;1125758&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/225f1587abc66a655db2c2626a7d6a82.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 차등 백업을 받고 있을 때 마찬가지로, 12시 30분에 데이터베이스가 장애 발생 상황을 가정해 보겠습니다. 차등 백업을 수행할 때에는 전체 백업본과 가장 최근 차등백업본을 복원합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 즉, 08시의 풀백업본을 리스토어 합니다. 이어서 12시의 차등 백업본 하나만 복원을 하면 가능한 모든 데이터가 복구됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;백업과 복원 전략 정리&lt;/h2&gt; &lt;p&gt;이렇게, 대표적인 세 가지 복원 전략을 차근차근 소개해 드렸습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 일반적인 조회가 매우 빈번하고, 데이터 변경이 적은 상황에서는 전체 백업 + 로그 백업 조합을 여러 장점이 있기 때문에 더 선호합니다. 데이터는 적으나 변경이 매우 빈번하다면 전체 백업과 차등 백업을 고려할 수도 있으며, 운영하는 서비스의 데이터 패턴에 따라 적합한 방식의 백업 전략을 수립하시길 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;다음 강좌에서는 실제 쿼리로 백업과 복원 전략을 실행하겠습니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>백업과 복원</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124828</guid>
			<comments>https://www.sqler.com/board_Column/1124828#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:25:17 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 13-1. 백업과 복원 - 백업과 복원 이해</title>
			<link>https://www.sqler.com/board_Column/1124825</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 13-1. 백업과 복원 - 백업과 복원 이해를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 백업과 복원 - 백업과 복원 이해입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/WwileF2BXMU?si=X6MGtOYHDhjnxLQ8&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;&lt;br /&gt; 백업과 복원의 기본 개념을 다룹니다. 백업은 데이터를 디스크나 디바이스로 복사하는 과정입니다. 데이터베이스 복구 모델에 따라 로그 파일 관리 및 백업 방식이 달라집니다. 로그 파일 백업, 데이터베이스 복구 모델별로 달라지는 백업 방식과 차이점을 소개합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;br /&gt; SQLER 분들이라면, 백업(Backup)과 복원(Restore)에 대해 들어 보셨을 거에요. 이번 강좌 챕터를 진행하기 전에, 먼저 질문드립니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width:500px;&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt; &lt;ul&gt; &lt;li&gt;백업과 관리 업무를 유지 관리 계획을 통해 주기적으로 진행하시나요?&lt;/li&gt; &lt;li&gt;사용자 데이터베이스와 시스템 데이터베이스(master, model, msdb)도 정기적으로 백업을 받으시나요?&amp;nbsp;&lt;/li&gt; &lt;li&gt;SQL Server의 복구 모델(Recovery model)을 설명하실 수 있나요?&lt;/li&gt; &lt;/ul&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;&lt;br /&gt; 위 세 가지 작업을 진행하고 설명하는 것이 백업과 복원 챕터의 목표입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;백업이란 무엇인가?&lt;/h2&gt; &lt;p&gt;백업은 두 가지 의미가 있습니다. 데이터 또는 트랜잭션 로그 데이터를 디스크나 디바이스로 &amp;ldquo;복사하는 과정&amp;rdquo;과, 장애 발생 후 데이터를 복구하는 데 사용할 수 있는 &amp;ldquo;데이터 복사본&amp;rdquo;을 의미합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 간단히, 백업은 데이터를 복사해 둔다는 의미입니다. 물론 그냥 복사만 하는 게 아니라 정확하게, 가능한 많은 데이터를 장애 발생 시 복구하기 위해 데이터 복사본을 만들어 두는 겁니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQL Server는 복구 모델을 제공합니다. 지난 데이터베이스 옵션 강좌에서 짧게 진행했지요.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;141-1 복구 모델.png&quot; data-file-srl=&quot;1125743&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/d0498976b46595157de7ed58c6f74fbd.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - SQL Server 복구 모델&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;SSMS에서 데이터베이스를 선택하고, 데이터베이스 속성 -&amp;gt; 옵션 탭을 보면 위와 같은 정보를 볼 수 있습니다. 또는 시스템 카탈로그를 이용해 확인 가능합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;데이터베이스&amp;nbsp;복구&amp;nbsp;모델&amp;nbsp;확인&lt;br /&gt; SELECT&amp;nbsp;name,&amp;nbsp;recovery_model_desc&amp;nbsp;FROM&amp;nbsp;sys.databases;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 데이터베이스 로그&amp;nbsp;&lt;/h2&gt; &lt;p&gt;로그가 뭔가요? 데이터베이스 강좌를 진행하면서 데이터 파일과 로그 파일을 생성하고 관리하는 방법을 간략히 말씀드렸습니다. 이 챕터에서는 좀 더 명확히 로그에 대해 살펴봅니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;데이터 관점에서 확인하는 백업과 복원 관점의 로그&lt;/h3&gt; &lt;p&gt;데이터 관점에서 로그는 &amp;ldquo;데이터 변경 기록&amp;rdquo;이며 백업과 복원 관점에서 로그는 &amp;ldquo;데이터 변경이 저장되는 저장소&amp;rdquo;입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &amp;ldquo;데이터 변경 기록-로그&amp;rdquo;는 변경 정보라서 대부분의 경우 실제 데이터에 비해 로그의 크기가 매우 작습니다. 데이터의 변경보다 대부분의 경우 데이터 조회가 훨씬 더 많으니까요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;로그는 백업하면 비워짐(empty)&lt;/h3&gt; &lt;p&gt;&amp;ldquo;데이터 변경 저장소-로그&amp;rdquo;는 로그를 백업하면 로그 저장소에서 비워집니다. - 지워진다기보다는 비워진다는 표현이 더 정확합니다. 로그 데이터 저장소 구조는 그대로 유지되고, 오직 로그 데이터만 비워지기 때문입니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 만약, 운영하면서 한 번도 이 로그를 백업하지 않았다면 로그 파일이 수기가까지 커져 속도가 느려지고 문제가 발생하는 경우가 종종 발생합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이전, &lt;a href=&quot;https://www.sqler.com/board_Column/1124624&quot;&gt;4-3. 데이터베이스 크기조절 강좌&lt;/a&gt;에서 이미 로그 파일 크기를 줄이는 작업도 진행하셨어요. 아래 이미지는 데이터는 수 메가바이트 정도인데, 로그는 데이터에 비해 매우 커졌습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;53-3-커진로그파일.png&quot; data-file-srl=&quot;1125744&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/c2ba5dfd95a18f3ae6cf4b601b2ca186.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - 커진 로그파일&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 로그는 매우 작은 분량임에도 불구하고, 한 번도 로그를 백업하지 않아 생기는 상황입니다. 사실 개발 과정에서 흔히 발생하는 케이스입니다. 이때, 사용되는 공간도 문제이지만 로그 데이터로 인해 시스템 성능이 저하되는 상황 역시 발생할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;만약, 관리하는 시스템이 있다면, SSMS에서 데이터베이스 속성을 확인하거나, 아래 SQL 구문을 수행해 로그 파일 크기를 체크할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;EXEC&amp;nbsp;sp_helpdb&amp;nbsp;&amp;#39;데이터베이스이름&amp;#39;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;로그파일을 줄이는 방법은 &lt;a href=&quot;https://www.sqler.com/board_Column/1124624&quot;&gt;4-3. 데이터베이스 크기조절&lt;/a&gt; - 데이터베이스 로그파일 줄이기를 참조하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;데이터베이스 복구 모델(Recovery model)&lt;/h2&gt; &lt;p&gt;SQL Server는 데이터베이스 단위로 복구모델을 설정합니다. 복구 모델은 트랜잭션 로그가 기록되는 방법과 트랜잭션 로그 백업 여부를 설정하고, 복원 시 복구 모델에 맞는 복원 방식을 설정합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;단순(Simple) 복구 모델&lt;/h3&gt; &lt;p&gt;단순 모델로 설정하면 로그 백업이 불가능하며, 마지막 전체 백업까지 복원 가능합니다. 개인 개발이나 테스트 환경에서 사용할 수 있습니다. 로그를 쌓지 않기 때문에 로그 데이터 파일이 비정상적으로 커지는 상황은 발생하지 않습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;대량로그(Bulk-logged) 복구 모델&lt;/h3&gt; &lt;p&gt;로그를 기록하고 백업 가능하지만, 대량작업(BULK INSERT 등)에 대해서는 최소로깅을 수행해 공간을 줄입니다. 지정시점 복원(RESTORE - STOPAT)은 지원하지 않고 가장 최근 로그 백업본까지 복원 가능합니다. 살짝 애매한 백업입니다. 대량작업 빈도에 따라 대량로그 모델을 결정할 수 있지만, 운영환경이라면 가급적 전체 모델을 권장합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; ☑️ 챗GPT 활용: SQL Server 대량작업(BULK INSERT, BCP)에 대해서 알려줘&lt;br /&gt; ☑️ 챗GPT 활용: SQL Server 데이터베이스 지정시점 복원(RESTORE - STOPAT)에 대해서 알려줘&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;전체(Full) 복구 모델&lt;/h3&gt; &lt;p&gt;모든 로그를 기록하고 백업합니다. 지정시간 복원 가능합니다. SQL Server의 모든 백업과 복원 기능을 사용합니다. 특히, 지정시간 복원은 자주 사용될 수 있으니, 가능한 팀단위 개발부터 운영 환경까지 데이터베이스는 전체 복구 모델로 설정하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;백업과 복원 관련 FAQ&lt;/h2&gt; &lt;p&gt;SQLER에서 자주 받았던 장애 상황과 발생 시 해결 방법을 먼저 기록합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;전체백업(X) 로그백업(X) 특정시점 복원 문의&lt;/h3&gt; &lt;p&gt;Q. 현재 웹사이트를 개발하는 중입니다. 애플리케이션 개발단계라, 한 번도 백업을 받은 적이 없습니다. 개발자의 실수로 update 회원테이블 set 이름 = &amp;#39;아무개&amp;#39;로 WHERE절 없이 update를 해 버렸습니다. 복원할 방법이 없을까요&lt;br /&gt; A. 복원 불가합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;전체백업(O) 로그백업(X) 특정시점 복원 문의&lt;/h3&gt; &lt;p&gt;Q. 지속적으로 전체 백업만을 받아 왔습니다. 개발자의 실수로 update 회원테이블 set 이름 = &amp;#39;아무개&amp;#39;로 WHERE절 없이 update를 해 버렸습니다. 복원할 방법이 없을까요?&lt;br /&gt; A. 제약 조건이 있습니다.&lt;br /&gt; - 복구 모델이 전체 복구 모델일 것(DB를 생성하면 기본입니다.)&lt;br /&gt; - 문제 발생 후 풀백업이나 로그에 쓰지 않는 작업을 하지 않았을 것&lt;br /&gt; - 로그 백업이 가능할 것입니다.&lt;br /&gt; 만약 이 세 조건에 부합한다면, 바로 로그를 비상로그 백업(Tail-Log Backup) 옵션으로 백업하신 후 RESTORE시 STOPAT 특정 시점 복원 명령으로 복원할 수 있습니다. 다음 강좌를 참고하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;전체백업(O) 로그백업(O) 특정시점 복원 문의&lt;/h3&gt; &lt;p&gt;Q. 풀백업과 로그백업을 지속적으로 수행하고 있습니다. 개발자의 실수로 update 회원테이블 set 이름 = &amp;#39;아무개&amp;#39;로 WHERE절 없이 update를 해 버렸습니다. 복원할 방법이 있을까요?&lt;br /&gt; A. 가능합니다.&amp;nbsp;&lt;br /&gt; - 복구 모델이 전체 모델일 것(DB를 생성하면 기본입니다.)&lt;br /&gt; - 문제 발생 후 풀백업이나 로그에 쓰지 않는 작업을 하지 않았을 것&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 만약 두 가지 조건에 부합한다면, 바로 로그를 비상로그 백업(Tail-Log Backup) 옵션으로 백업하신 후 RESTORE시 STOPAT 특정 시점 명령으로 복원할 수 있습니다. 다음 강좌의 SQL 구문을 참조하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;MDF 파일과 LDF 파일만 남았을 때 복원 방법&lt;/h3&gt; &lt;p&gt;Q. 이전 SQL Server에서 사용하던 시스템의 디바이스 문제로 해당하는 데이터베이스의 mdf 파일과 ldf 파일만 남았습니다. 새로 설치하는 시스템에서 복원 가능할까요?&lt;br /&gt; A. 이전 서버와 설정이 유사하고 이전에 사용하던 SQL서버가 정상적인 상태로 종료 되었을때 (SQL서버를 스탑 시켰거나 정상적으로 윈도 시스템을 종료시킨 경우 해당 mdf 파일과 ldf 파일이 정상적으로 닫혔을 경우) 복원 가능하며 이때 사용하는 SQL 구문입니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;CREATE&amp;nbsp;DATABASE&amp;nbsp;데이터베이스이름&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON&amp;nbsp;(FILENAME&amp;nbsp;=&amp;nbsp;N&amp;#39;mdf파일경로&amp;#39;),&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(FILENAME&amp;nbsp;=&amp;nbsp;N&amp;#39;ldf파일경로&amp;#39;)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOR&amp;nbsp;ATTACH&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;구문으로 복원할 수 있습니다.&lt;br /&gt; 이전, &lt;a href=&quot;https://www.sqler.com/board_Column/1124621&quot;&gt;4-2. 데이터베이스 생성 강좌&lt;/a&gt;를 참고하세요. 이때, Cross db ownership chaining 문제가 발생할 수 있으니, 위 문서 링크의 가이드 대로 수행하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;MDF 파일만 남았을 때 복원 방법&lt;/h3&gt; &lt;p&gt;Q. 이전 서버에서 사용하던 시스템의 문제로 해당하는 데이터베이스의 mdf 파일만 남았습니다. 새로 설치하는 시스템에서 복원 가능할까요?&lt;br /&gt; A. 이전 서버와 설정이 유사하고, 이전에 사용하던 SQL서버가 정상적인 상태로 종료되었을 &amp;nbsp;때(SQL서버를 스탑 시켰거나 정상적으로 윈도 시스템을 종료시킨 경우 - 해당 mdf 파일이 정상적으로 닫혔을 경우) 복원 가능하며 이때 사용하는 SQL 구문입니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;CREATE&amp;nbsp;DATABASE&amp;nbsp;데이터베이스이름&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON&amp;nbsp;(FILENAME&amp;nbsp;=&amp;nbsp;N&amp;#39;mdf파일경로&amp;#39;)&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOR&amp;nbsp;ATTACH&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;다른 시스템에의 전체 백업본에서 복원하는 방법&lt;/h3&gt; &lt;p&gt;Q. 이전 시스템에서 사용하던 전체 백업본이 있습니다. 새로 시스템을 설치한 후 이 전체 백업본을 신규 시스템에서 복원하려 하는데 방법이 있을까요?&lt;br /&gt; A. 가능합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Backup&amp;nbsp;파일의&amp;nbsp;데이터&amp;nbsp;파일과&amp;nbsp;로그파일&amp;nbsp;정보&amp;nbsp;출력&lt;br /&gt; RESTORE&amp;nbsp;FILELISTONLY&lt;br /&gt; FROM&amp;nbsp;DISK&amp;nbsp;=&amp;nbsp;N&amp;#39;C:\sql_backup\AdventureWorks2022.bak&amp;#39;;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;정보에&amp;nbsp;맞춰&amp;nbsp;Database&amp;nbsp;Restore&amp;nbsp;수행&lt;br /&gt; RESTORE&amp;nbsp;DATABASE&amp;nbsp;AdventureWorks&lt;br /&gt; FROM&amp;nbsp;disk=&amp;nbsp;N&amp;#39;C:\sql_backup\AdventureWorks2022.bak&amp;#39;&lt;br /&gt; WITH&amp;nbsp;MOVE&amp;nbsp;N&amp;#39;AdventureWorks2022&amp;#39;&lt;br /&gt; TO&amp;nbsp;N&amp;#39;C:\sql_data\AdventureWorks2022.mdf&amp;#39;,&lt;br /&gt; MOVE&amp;nbsp;N&amp;#39;AdventureWorks2022_log&amp;#39;&lt;br /&gt; TO&amp;nbsp;N&amp;#39;C:\sql_data\AdventureWorks2022_log.ldf&amp;#39;,&amp;nbsp;&lt;br /&gt; RECOVERY;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;자 이렇게 많이 받는 백업과 복원에 대해 자주 받는 질문을 정리했습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 실제 운영 서비스로 클라우드 데이터베이스를 이용하면, 이런 패턴을 사용할 일이 많지 않고, 바로 뒤에서 &amp;ldquo;유지 관리 계획&amp;rdquo; 자동화를 이용한 스케줄로 백업이나 유지보수 작업을 진행할 수 있으니 너무 마음 쓰지 않으셔도 됩니다.&lt;/p&gt; &lt;p&gt;다음 강좌에서는 다양한 백업 전략에 대해 소개해 드립니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>백업과 복원</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124825</guid>
			<comments>https://www.sqler.com/board_Column/1124825#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:24:45 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 12-9. 인덱스 생성과 관리 - DTA(데이터베이스 엔진 튜닝 관리자)</title>
			<link>https://www.sqler.com/board_Column/1124822</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 12-9. 인덱스 생성과 관리 - DTA(데이터베이스 엔진 튜닝 관리자)를 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 인덱스 생성과 관리 - DTA(데이터베이스 엔진 튜닝 관리자)입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/4ZddodJOJ9Q?si=CJa-O1OynVcTS_DM&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;데이터베이스 엔진 튜닝 관리자 도구를 소개하고 활용하는 방법을 설명합니다. DTA는 SQL Server의 쿼리를 분석하여 최적화된 인덱스와 성능 향상 가이드를 제공하며, 쿼리 선택 방법, 실행 방법, 결과 리포트 등을 자세히 다룹니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 그래서, 어떻게 해야 인덱스를 잘 생성하나요?&lt;/h2&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;SQL 쿼리 구문에 맞춰 인덱스를 생성해야 하는데 너무 어렵습니다. 애플리케이션에서 사용하는 SQL 구문도 복잡하고, 인덱스 잘 못 만들면 더 느려지고 문제가 많다고 해서 함부로 건드리기가 두렵습니다. 어떻게 해야 인덱스를 잘 생성하나요?&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;em&gt;클라우드에서 데이터베이스 애플리케이션을 개발하고 서비스하는 회사입니다. 시간이 지나 데이터가 쌓이면서 애플리케이션 응답속도가 느려지고, 데이터베이스 인스턴스는 계속 CPU 100%를 치는 상황이 발생합니다. 원인은 애플리케이션에서 사용하는 몇몇 기능만 수행하면 느려집니다. 테이블 4~5개를 JOIN 하고, 쿼리 하는 데이터가 많은 테이블인데, 사용자가 몰리면 더욱 느려지고 아무리 클라우드 인스턴스를 스케일업 해서 높은 사양으로 바꿔도 그때뿐입니다. 인덱스를 생성하면 된다고 하는데, 인덱스도 어렵고, 쿼리에 맞춰 어떻게 생성해야 하는지는 더욱 어렵습니다.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;br /&gt; 이럴 때, DTA(Database Engine Tuning Advisor - 데이터베이스 엔진 튜닝 관리자)를 먼저 사용할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;DTA 소개&lt;/h2&gt; &lt;p&gt;DTA는 SQL Server에서 실행되는 쿼리를 분석해, 쿼리 성능을 최적화할 수 있는 인덱스, 파티션 등의 성능을 높일 수 있는 가이드를 제공하는 도구입니다. SQL Server의 내부 구조나 데이터베이스 튜닝에 대한 전문적인 교육을 받지 않아도, 일정 수준 최적화된 결과 리포트를 가이드로 제공합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;DTA 사용 방법&lt;/h2&gt; &lt;p&gt;분석하기 원하는 (1) 쿼리를 SSMS에서 선택하고 DTA를 수행하거나, (2) SQL Server 쿼리 저장소(Query store)를 이용하거나, (3) SQL 서버의 Profiler 추적 파일 등의 정보에서 DTA를 수행할 수도 있습니다.&lt;/p&gt; &lt;p&gt;이번 SQLER 강좌에서는 (1) SSMS의 쿼리를 선택해 DTA를 실행하고, 인덱스를 생성하겠습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;DTA를 적용할 예제 데이터 생성&lt;/h3&gt; &lt;p&gt;아래 예제를 수행해 DTA 수행을 준비합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;master;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; ALTER&amp;nbsp;DATABASE&amp;nbsp;SQLERTestDB&amp;nbsp;SET&amp;nbsp;RECOVERY&amp;nbsp;SIMPLE;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; USE&amp;nbsp;SQLERTestDB;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;IndexDummy&amp;nbsp;테이블이&amp;nbsp;존재하면&amp;nbsp;삭제&lt;br /&gt; DROP&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;EXISTS&amp;nbsp;IndexDummy;&lt;br /&gt; --&amp;nbsp;인덱스&amp;nbsp;테스트&amp;nbsp;테이블&amp;nbsp;생성&lt;br /&gt; CREATE&amp;nbsp;TABLE&amp;nbsp;IndexDummy(&lt;br /&gt; idx&amp;nbsp;INT,&lt;br /&gt; dummy_dt&amp;nbsp;DATETIME&amp;nbsp;DEFAULT(GETDATE()),&lt;br /&gt; dummy_str&amp;nbsp;NVARCHAR(39)&amp;nbsp;DEFAULT(CONVERT(NVARCHAR(39),&amp;nbsp;NEWID()))&lt;br /&gt; );&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;10만&amp;nbsp;건&amp;nbsp;데이터를&amp;nbsp;WHILE문으로&amp;nbsp;생성.&lt;br /&gt; SET&amp;nbsp;NOCOUNT&amp;nbsp;ON&lt;br /&gt; DECLARE&amp;nbsp;@Counter&amp;nbsp;INT&lt;br /&gt; SET&amp;nbsp;@Counter&amp;nbsp;=&amp;nbsp;0&lt;br /&gt; WHILE&amp;nbsp;(@Counter&amp;nbsp;&amp;lt;&amp;nbsp;100000)&lt;br /&gt; BEGIN&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;INTO&amp;nbsp;IndexDummy(idx)&amp;nbsp;VALUES(@Counter)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;@Counter&amp;nbsp;=&amp;nbsp;@Counter&amp;nbsp;+&amp;nbsp;1&lt;br /&gt; END;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;완료&amp;nbsp;후&amp;nbsp;데이터&amp;nbsp;조회&lt;br /&gt; SELECT&amp;nbsp;COUNT(*)&amp;nbsp;FROM&amp;nbsp;IndexDummy;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;10만 건 데이터를 생성합니다. 테이블이 작을 경우 DTA가 리포트를 제공하지 않을 수 있으니 충분히 큰 테이블을 선택합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;SQL 구문으로 DTA 실행&amp;nbsp;&lt;/h3&gt; &lt;p&gt;아래 구문을 SSMS로 복사하고, 첫 SQL 구문을 선택해 DTA를 실행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy&amp;nbsp;WHERE&amp;nbsp;idx&amp;nbsp;=&amp;nbsp;5000&lt;br /&gt; &lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy&amp;nbsp;WHERE&amp;nbsp;idx&amp;nbsp;&amp;lt;&amp;nbsp;10&lt;br /&gt; &lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy&amp;nbsp;WHERE&amp;nbsp;idx&amp;nbsp;&amp;lt;&amp;nbsp;400&lt;br /&gt; &lt;br /&gt; SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy&amp;nbsp;WHERE&amp;nbsp;idx&amp;nbsp;&amp;lt;&amp;nbsp;10000&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-1-DTA실행.png&quot; data-file-srl=&quot;1125730&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/5158c2103397bf11d76d653a21e96967.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - SQL Server DTA 실행&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-2 DTA 확인.png&quot; data-file-srl=&quot;1125731&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/3785318b635aa500f6b8c70f07d7ad98.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - DTA 확인&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-3 DTA 튜닝 옵션.png&quot; data-file-srl=&quot;1125732&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/dedd7668c5f0f2f283f492cc2c53b4fb.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - DTA 튜닝 옵션 확인&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;분석 시작을 눌러 분석을 시작합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-4 DTA 진행률.png&quot; data-file-srl=&quot;1125733&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/b4aa84ed7a39358d17476fc07a3716f3.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - DTA 진행률 확인&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;DTA가 분석을 진행합니다. 이때 쿼리 패턴에 따라 시간이 오래 걸릴 수 있고, SQL Server 리소스가 많이 사용됩니다. 사용자가 적은 시간대에 실행하거나, 가급적이면 운영 환경이 아닌, 같은 구조의 DB가 실행되는 개발/테스트 시스템에서 수행하세요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-5 DTA 튜닝 권장 구성.png&quot; data-file-srl=&quot;1125734&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/97cb28facd29790aada0d0f2980ae495.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - DTA 튜닝 권장 구성&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;분석이 완료되면 권장 구성이 출력됩니다. 개체 정보를 확인하고, 권장 구성 결과 가장 오른쪽 &amp;ldquo;정의&amp;rdquo; 항목을 확인하면, SQL 스크립트로 생성된 인덱스나 파티셔닝 등의 가이드 구문을 확인 가능합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-6 DTA 튜닝 리포트.png&quot; data-file-srl=&quot;1125735&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/17c79d593ebe505511af4a9556f67d38.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - DTA 튜닝 리포트&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;DTA가 생성한 보고서입니다. 기본적인 요약 정보와 보고서에 따라 SQL 구문과 인덱스 등을 다양한 보고서 형식으로 확인할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;여러 쿼리를 선택하고 DTA 실행&lt;/h3&gt; &lt;p&gt;DTA는 하나의 SQL 구문뿐만 아니라, 여러 SQL 구문에 대해 가이드를 제공할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt=&quot;139-7 DTA 여러 쿼리 선택.png&quot; data-file-srl=&quot;1125736&quot; editor_component=&quot;image_link&quot; src=&quot;/files/attach/images/2023/08/28/3666658aa0ffeb825315183f6622edc2.png&quot; style=&quot;border-width: 1px; border-style: solid;&quot; /&gt;&lt;/p&gt; &lt;p&gt;이미지 - DTA 여러 쿼리 선택&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 하나의 쿼리로 DTA 분석을 수행했다면, 위와 같이 여러 SQL 쿼리 구문을 묶어서 DTA 분석 실행도 가능합니다. 애플리케이션에서 사용하는 다양한 쿼리 패턴을 DTA에 전달하는 게 좋습니다. 위의 여러 SQL 쿼리 구문을 묶어 분석하는 과정을 한번 더 수행해 인덱스 생성 스크립트를 추출합니다. 더 좋은 방법은 이후에 튜닝 강좌로 진행될 Profiler를 이용하는 방법입니다. 지금은 SSMS에서 쿼리를 통해 실행하는 과정에 집중하시길 바랍니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;DTA가 자동 생성한 인덱스&lt;/h3&gt; &lt;p&gt;최종적으로 아래와 같은 인덱스 구문을 얻을 수 있습니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;CREATE&amp;nbsp;CLUSTERED&amp;nbsp;INDEX&amp;nbsp;[_dta_index_IndexDummy_c_10_1269579561__K1]&amp;nbsp;ON&amp;nbsp;[dbo].[IndexDummy]&lt;br /&gt; (&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[idx]&amp;nbsp;ASC&lt;br /&gt; )WITH&amp;nbsp;(SORT_IN_TEMPDB&amp;nbsp;=&amp;nbsp;OFF,&amp;nbsp;DROP_EXISTING&amp;nbsp;=&amp;nbsp;OFF,&amp;nbsp;ONLINE&amp;nbsp;=&amp;nbsp;OFF)&amp;nbsp;ON&amp;nbsp;[PRIMARY]&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;DTA에서 자동 생성된 인덱스 이름이나 설정 등을 확인하고, 최종적으로 인덱스를 생성합니다. 인덱스를 생성하고, 실행계획이나 IO 사용량을 SQLER 강좌를 통해 다시 체크하고, 성능 이슈가 발생했던 SQL 쿼리가 적절하게 인덱스를 타서 실행되는지 다시 애플리케이션의 SQL 구문을 확인합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 인덱스는 SQL 쿼리 성능에 매우 중요한 데이터베이스 개체입니다. 반드시 잘 문서화하고, 지속적으로 모니터링하세요.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 이렇게 인덱스 강좌를 마무리합니다. SQL Server &amp;nbsp;튜닝 관련 강좌도 이후에 진행 예정이니 기대해 주세요.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>인덱스 튜닝</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124822</guid>
			<comments>https://www.sqler.com/board_Column/1124822#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:23:42 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 12-8. 인덱스 생성과 관리 - 인덱스 재구성/재구축</title>
			<link>https://www.sqler.com/board_Column/1124819</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 12-8. 인덱스 생성과 관리 - 인덱스 재구성/재구축을 진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 인덱스 생성과 관리 - 인덱스 재구성/재생성입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/S_iiCNmjWKk?si=QPYiXZi3OVhk3arm&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;ALTER INDEX 구문으로, 인덱스 재구성과 재생성 방법을 설명합니다. 파편화율을 기준으로 재구성과 재생성을 결정하며, 실행 방법과 예제 쿼리 및 쿼리 최적화 통계 데이터 확인 방법을 소개합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 인덱스 재구성(Reorganize) / 재구축(Rebuild)&lt;/h2&gt; &lt;p&gt;인덱스를 재구성/재구축하는 방법은 ALTER INDEX 구문에서 재구성 - REORGANIZE 명령과 재구축 - REBUILD 명령을 사용할 수 있습니다. (DBCC DBREINDEX, DBCC INDEXDEFRAG 명령은 차기 SQL Server에서 지원되지 않을 예정이니 사용하지 마시고 ALTER INDEX를 사용하세요.)&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;재구성 - REORGANIZE &amp;nbsp;vs 재구축 - REBUILD&amp;nbsp;&lt;/h3&gt; &lt;p&gt;인덱스 재구성 방법 두 가지를 비교하기 전에, 먼저 평균 파편화를 구해야 합니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;Microsoft&amp;nbsp;공식&amp;nbsp;가이드&lt;br /&gt; --https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-index-physical-stats-transact-sql?view=sql-server-2017#a-return-information-about-a-specified-table&lt;br /&gt; DECLARE&amp;nbsp;@db_id&amp;nbsp;SMALLINT;&lt;br /&gt; DECLARE&amp;nbsp;@object_id&amp;nbsp;INT;&lt;br /&gt; SET&amp;nbsp;@db_id&amp;nbsp;=&amp;nbsp;DB_ID(N&amp;#39;SQLERTestDB&amp;#39;);&amp;nbsp;&amp;nbsp;--DB명&lt;br /&gt; SET&amp;nbsp;@object_id&amp;nbsp;=&amp;nbsp;OBJECT_ID(N&amp;#39;SQLERTestDB.dbo.IndexDummy&amp;#39;);&amp;nbsp;&amp;nbsp;--테이블명&lt;br /&gt; &lt;br /&gt; IF&amp;nbsp;@db_id&amp;nbsp;IS&amp;nbsp;NULL&lt;br /&gt; BEGIN;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PRINT&amp;nbsp;N&amp;#39;Invalid&amp;nbsp;database&amp;#39;;&lt;br /&gt; END;&lt;br /&gt; ELSE&amp;nbsp;IF&amp;nbsp;@object_id&amp;nbsp;IS&amp;nbsp;NULL&lt;br /&gt; BEGIN;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PRINT&amp;nbsp;N&amp;#39;Invalid&amp;nbsp;object&amp;#39;;&lt;br /&gt; END;&lt;br /&gt; ELSE&lt;br /&gt; BEGIN;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;DB_NAME(database_id),&amp;nbsp;OBJECT_NAME(object_id),&amp;nbsp;avg_fragmentation_in_percent&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;sys.dm_db_index_physical_stats(@db_id,&amp;nbsp;@object_id,&amp;nbsp;NULL,&amp;nbsp;NULL&amp;nbsp;,&amp;nbsp;&amp;#39;LIMITED&amp;#39;)&lt;br /&gt; END;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;또는&amp;nbsp;아래&amp;nbsp;방법&amp;nbsp;수행&amp;nbsp;-&amp;nbsp;https://stackoverflow.com/a/45439047&lt;br /&gt; SELECT&amp;nbsp;dbschemas.[name]&amp;nbsp;as&amp;nbsp;&amp;#39;Schema&amp;#39;,&lt;br /&gt; dbtables.[name]&amp;nbsp;as&amp;nbsp;&amp;#39;Table&amp;#39;,&lt;br /&gt; dbindexes.[name]&amp;nbsp;as&amp;nbsp;&amp;#39;Index&amp;#39;,&lt;br /&gt; indexstats.avg_fragmentation_in_percent,&lt;br /&gt; indexstats.page_count&lt;br /&gt; FROM&amp;nbsp;sys.dm_db_index_physical_stats&amp;nbsp;(DB_ID(),&amp;nbsp;NULL,&amp;nbsp;NULL,&amp;nbsp;NULL,&amp;nbsp;NULL)&amp;nbsp;AS&amp;nbsp;indexstats&lt;br /&gt; INNER&amp;nbsp;JOIN&amp;nbsp;sys.tables&amp;nbsp;dbtables&amp;nbsp;on&amp;nbsp;dbtables.[object_id]&amp;nbsp;=&amp;nbsp;indexstats.[object_id]&lt;br /&gt; INNER&amp;nbsp;JOIN&amp;nbsp;sys.schemas&amp;nbsp;dbschemas&amp;nbsp;on&amp;nbsp;dbtables.[schema_id]&amp;nbsp;=&amp;nbsp;dbschemas.[schema_id]&lt;br /&gt; INNER&amp;nbsp;JOIN&amp;nbsp;sys.indexes&amp;nbsp;AS&amp;nbsp;dbindexes&amp;nbsp;ON&amp;nbsp;dbindexes.[object_id]&amp;nbsp;=&amp;nbsp;indexstats.[object_id]&lt;br /&gt; AND&amp;nbsp;indexstats.index_id&amp;nbsp;=&amp;nbsp;dbindexes.index_id&lt;br /&gt; WHERE&amp;nbsp;indexstats.database_id&amp;nbsp;=&amp;nbsp;DB_ID()&amp;nbsp;AND&amp;nbsp;dbtables.[name]&amp;nbsp;like&amp;nbsp;&amp;#39;%%&amp;#39;&lt;br /&gt; ORDER&amp;nbsp;BY&amp;nbsp;indexstats.avg_fragmentation_in_percent&amp;nbsp;desc&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 수행해 인덱스의 파편화율을 구합니다. 파편화율에 따라 재구성과 재구축을 결정합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;파편화율이 10% 이하면 아무 작업 하지 않음&lt;/li&gt; &lt;li&gt;10~30% 사이면 REORGANIZE 수행&lt;/li&gt; &lt;li&gt;30% 이상이면 REBUILD 수행&amp;nbsp;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;그럼, 재구성과 재구축 SQL 쿼리 구문을 살펴보겠습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;REORGANIZE 실행&lt;/h3&gt; &lt;p&gt;REORGANIZE는 인덱스 리프 레벨을 재구성합니다. 온라인으로 수행되고 REBUILD에 비해 가볍습니다. 인덱스를 재구성하는 REORGANIZE은 아래 방식으로 실행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;한&amp;nbsp;테이블의&amp;nbsp;특정&amp;nbsp;인덱스를&amp;nbsp;REORGANIZE&lt;br /&gt; ALTER&amp;nbsp;INDEX&amp;nbsp;idx_id&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;REORGANIZE;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;한&amp;nbsp;테이블의&amp;nbsp;전체&amp;nbsp;인덱스를&amp;nbsp;REORGANIZE&lt;br /&gt; ALTER&amp;nbsp;INDEX&amp;nbsp;ALL&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;REORGANIZE;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;모든&amp;nbsp;테이블의&amp;nbsp;모든&amp;nbsp;인덱스를&amp;nbsp;REORGANIZE&lt;br /&gt; Exec&amp;nbsp;sp_msforeachtable&amp;nbsp;&amp;#39;SET&amp;nbsp;QUOTED_IDENTIFIER&amp;nbsp;ON;&amp;nbsp;ALTER&amp;nbsp;INDEX&amp;nbsp;ALL&amp;nbsp;ON&amp;nbsp;?&amp;nbsp;REORGANIZE&amp;#39;;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;REBUILD 수행&lt;/h3&gt; &lt;p&gt;인덱스를 재생성합니다. 시스템 리소스를 많이 사용할 수 있으며 다른 프로세스의 쿼리 속도를 저하시킬 수 있으니 신중하게 사용하세요. 사용자가 적은 시간대를 택해 유지관리 작업으로 수행하실 것을 권장합니다.&lt;br /&gt; 인덱스를 재생성하는 REBUILD 구문은 아래처럼 실행합니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;한&amp;nbsp;테이블의&amp;nbsp;특정&amp;nbsp;인덱스를&amp;nbsp;REBUILD&lt;br /&gt; ALTER&amp;nbsp;INDEX&amp;nbsp;idx_id&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;REBUILD;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;한&amp;nbsp;테이블의&amp;nbsp;모든&amp;nbsp;인덱스를&amp;nbsp;채우기&amp;nbsp;비율과&amp;nbsp;함께&amp;nbsp;REBUILD&amp;nbsp;&lt;br /&gt; ALTER&amp;nbsp;INDEX&amp;nbsp;ALL&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;REBUILD&amp;nbsp;WITH&amp;nbsp;(FILLFACTOR&amp;nbsp;=&amp;nbsp;80);&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;모든&amp;nbsp;테이블의&amp;nbsp;모든&amp;nbsp;인덱스를&amp;nbsp;REBUILD&lt;br /&gt; Exec&amp;nbsp;sp_msforeachtable&amp;nbsp;&amp;#39;SET&amp;nbsp;QUOTED_IDENTIFIER&amp;nbsp;ON;&amp;nbsp;ALTER&amp;nbsp;INDEX&amp;nbsp;ALL&amp;nbsp;ON&amp;nbsp;?&amp;nbsp;REBUILD&amp;#39;;&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;데이터베이스의 모든 테이블 인덱스를 파편화율로 자동 재구성/재생성 수행&lt;/h3&gt; &lt;p&gt;아래 쿼리를 이용해 모든 테이블과 모든 인덱스에 자동 처리 가능합니다. SQL Server의 유지관리 작업으로 설정해 일정 주기마다 실행되도록 구성하면 유용합니다.&lt;br /&gt; 파편화율 10% 이상인 테이블을 #work_to_do 테이블에 저장하고, 커서를 사용해 #work_to_do의 개별 테이블의 파편화율을 조사해 10~30%면 재구성, 그 이상이면 재생성을 수행합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;Microsoft&amp;nbsp;&amp;nbsp;가이드&amp;nbsp;문서&amp;nbsp;참조&amp;nbsp;-&amp;nbsp;https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-index-physical-stats-transact-sql?view=sql-server-2017#a-return-information-about-a-specified-table&lt;br /&gt; --&amp;nbsp;Ensure&amp;nbsp;a&amp;nbsp;USE&amp;nbsp;&amp;lt;databasename&amp;gt;&amp;nbsp;statement&amp;nbsp;has&amp;nbsp;been&amp;nbsp;executed&amp;nbsp;first.&lt;br /&gt; SET&amp;nbsp;NOCOUNT&amp;nbsp;ON;&lt;br /&gt; &lt;br /&gt; DECLARE&amp;nbsp;@objectid&amp;nbsp;INT;&lt;br /&gt; DECLARE&amp;nbsp;@indexid&amp;nbsp;INT;&lt;br /&gt; DECLARE&amp;nbsp;@partitioncount&amp;nbsp;BIGINT;&lt;br /&gt; DECLARE&amp;nbsp;@schemaname&amp;nbsp;NVARCHAR(130);&lt;br /&gt; DECLARE&amp;nbsp;@objectname&amp;nbsp;NVARCHAR(130);&lt;br /&gt; DECLARE&amp;nbsp;@indexname&amp;nbsp;NVARCHAR(130);&lt;br /&gt; DECLARE&amp;nbsp;@partitionnum&amp;nbsp;BIGINT;&lt;br /&gt; DECLARE&amp;nbsp;@partitions&amp;nbsp;BIGINT;&lt;br /&gt; DECLARE&amp;nbsp;@frag&amp;nbsp;FLOAT;&lt;br /&gt; DECLARE&amp;nbsp;@command&amp;nbsp;NVARCHAR(4000);&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Conditionally&amp;nbsp;select&amp;nbsp;tables&amp;nbsp;and&amp;nbsp;indexes&amp;nbsp;from&amp;nbsp;the&amp;nbsp;sys.dm_db_index_physical_stats&amp;nbsp;function&lt;br /&gt; --&amp;nbsp;and&amp;nbsp;convert&amp;nbsp;object&amp;nbsp;and&amp;nbsp;index&amp;nbsp;IDs&amp;nbsp;to&amp;nbsp;names.&lt;br /&gt; SELECT&amp;nbsp;object_id&amp;nbsp;AS&amp;nbsp;objectid,&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;index_id&amp;nbsp;AS&amp;nbsp;indexid,&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;partition_number&amp;nbsp;AS&amp;nbsp;partitionnum,&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;avg_fragmentation_in_percent&amp;nbsp;AS&amp;nbsp;frag&lt;br /&gt; INTO&amp;nbsp;#work_to_do&lt;br /&gt; FROM&amp;nbsp;sys.dm_db_index_physical_stats(DB_ID(),&amp;nbsp;NULL,&amp;nbsp;NULL,&amp;nbsp;NULL,&amp;nbsp;&amp;#39;LIMITED&amp;#39;)&lt;br /&gt; WHERE&amp;nbsp;avg_fragmentation_in_percent&amp;nbsp;&amp;gt;&amp;nbsp;10.0&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AND&amp;nbsp;index_id&amp;nbsp;&amp;gt;&amp;nbsp;0;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Declare&amp;nbsp;the&amp;nbsp;cursor&amp;nbsp;for&amp;nbsp;the&amp;nbsp;list&amp;nbsp;of&amp;nbsp;partitions&amp;nbsp;to&amp;nbsp;be&amp;nbsp;processed.&lt;br /&gt; DECLARE&amp;nbsp;partitions&amp;nbsp;CURSOR&lt;br /&gt; FOR&lt;br /&gt; SELECT&amp;nbsp;*&lt;br /&gt; FROM&amp;nbsp;#work_to_do;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Open&amp;nbsp;the&amp;nbsp;cursor.&lt;br /&gt; OPEN&amp;nbsp;partitions;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Loop&amp;nbsp;through&amp;nbsp;the&amp;nbsp;partitions.&lt;br /&gt; WHILE&amp;nbsp;(1&amp;nbsp;=&amp;nbsp;1)&lt;br /&gt; BEGIN;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FETCH&amp;nbsp;NEXT&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;partitions&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INTO&amp;nbsp;@objectid,&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@indexid,&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@partitionnum,&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@frag;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IF&amp;nbsp;@@FETCH_STATUS&amp;nbsp;&amp;lt;&amp;nbsp;0&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BREAK;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;@objectname&amp;nbsp;=&amp;nbsp;QUOTENAME(o.name),&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@schemaname&amp;nbsp;=&amp;nbsp;QUOTENAME(s.name)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;sys.objects&amp;nbsp;AS&amp;nbsp;o&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INNER&amp;nbsp;JOIN&amp;nbsp;sys.schemas&amp;nbsp;AS&amp;nbsp;s&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ON&amp;nbsp;s.schema_id&amp;nbsp;=&amp;nbsp;o.schema_id&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;o.object_id&amp;nbsp;=&amp;nbsp;@objectid;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;@indexname&amp;nbsp;=&amp;nbsp;QUOTENAME(name)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;sys.indexes&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;object_id&amp;nbsp;=&amp;nbsp;@objectid&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AND&amp;nbsp;index_id&amp;nbsp;=&amp;nbsp;@indexid;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;@partitioncount&amp;nbsp;=&amp;nbsp;count(*)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;sys.partitions&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;object_id&amp;nbsp;=&amp;nbsp;@objectid&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AND&amp;nbsp;index_id&amp;nbsp;=&amp;nbsp;@indexid;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--&amp;nbsp;30&amp;nbsp;is&amp;nbsp;an&amp;nbsp;arbitrary&amp;nbsp;decision&amp;nbsp;point&amp;nbsp;at&amp;nbsp;which&amp;nbsp;to&amp;nbsp;switch&amp;nbsp;between&amp;nbsp;reorganizing&amp;nbsp;and&amp;nbsp;rebuilding.&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IF&amp;nbsp;@frag&amp;nbsp;&amp;lt;&amp;nbsp;30.0&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;@command&amp;nbsp;=&amp;nbsp;N&amp;#39;ALTER&amp;nbsp;INDEX&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;@indexname&amp;nbsp;+&amp;nbsp;N&amp;#39;&amp;nbsp;ON&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;@schemaname&amp;nbsp;+&amp;nbsp;N&amp;#39;.&amp;#39;&amp;nbsp;+&amp;nbsp;@objectname&amp;nbsp;+&amp;nbsp;N&amp;#39;&amp;nbsp;REORGANIZE&amp;#39;;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IF&amp;nbsp;@frag&amp;nbsp;&amp;gt;=&amp;nbsp;30.0&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;@command&amp;nbsp;=&amp;nbsp;N&amp;#39;ALTER&amp;nbsp;INDEX&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;@indexname&amp;nbsp;+&amp;nbsp;N&amp;#39;&amp;nbsp;ON&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;@schemaname&amp;nbsp;+&amp;nbsp;N&amp;#39;.&amp;#39;&amp;nbsp;+&amp;nbsp;@objectname&amp;nbsp;+&amp;nbsp;N&amp;#39;&amp;nbsp;REBUILD&amp;#39;;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IF&amp;nbsp;@partitioncount&amp;nbsp;&amp;gt;&amp;nbsp;1&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;@command&amp;nbsp;=&amp;nbsp;@command&amp;nbsp;+&amp;nbsp;N&amp;#39;&amp;nbsp;PARTITION=&amp;#39;&amp;nbsp;+&amp;nbsp;CAST(@partitionnum&amp;nbsp;AS&amp;nbsp;NVARCHAR(10));&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;EXEC&amp;nbsp;(@command);&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PRINT&amp;nbsp;N&amp;#39;Executed:&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;@command;&lt;br /&gt; END;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Close&amp;nbsp;and&amp;nbsp;deallocate&amp;nbsp;the&amp;nbsp;cursor.&lt;br /&gt; CLOSE&amp;nbsp;partitions;&lt;br /&gt; &lt;br /&gt; DEALLOCATE&amp;nbsp;partitions;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;Drop&amp;nbsp;the&amp;nbsp;temporary&amp;nbsp;table.&lt;br /&gt; DROP&amp;nbsp;TABLE&amp;nbsp;#work_to_do;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;br /&gt; 쿼리 최적화 통계 데이터(Query optimization statistics data)&lt;/h2&gt; &lt;p&gt;다음으로 쿼리 최적화 통계 데이터입니다. 먼저 다음 질의를 봐 보도록 하지요.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--&amp;nbsp;통계&amp;nbsp;데이터&amp;nbsp;보기&lt;br /&gt; DBCC&amp;nbsp;SHOW_STATISTICS(IndexDummy,idx_id)&lt;br /&gt; &lt;br /&gt; --통계&amp;nbsp;데이터&amp;nbsp;UPDATE&amp;nbsp;(자동&amp;nbsp;업데이트.&amp;nbsp;불필요&amp;nbsp;작업)&lt;br /&gt; UPDATE&amp;nbsp;STATISTICS&amp;nbsp;IndexDummy(idx_id)&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이전 강좌에서 몇 번 말씀드린 대로, &amp;ldquo;통계에 따라서 SQL Server 쿼리 최적화기(Query optimizer)가 인덱스를 타게 할지 여부를 결정한다&amp;rdquo;라고 말씀드렸습니다. 이때 작업 근거가 되는 정보가 바로 테이블 통계 데이터입니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; SQL Server는 테이블 통계 데이터를 인덱스와 함께 생성하고 자동으로 유지합니다. &amp;nbsp;수동으로 통계 업데이트 설정도 가능하지만, 데이터베이스 튜닝 요소로 볼 때 수동 진행은 권장하지 않습니다. 만약, 수동으로 설정할 경우 많은 모니터링이 필요합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 인덱스에 대해 좀 더 깊이 있는 공부나 SQL Server 쿼리 최적화기의 세밀한 제어, 여러 시스템 카탈로그 정보 분석을 원하시면 이런 통계 데이터 관련 정보를 참고해 보시길 바랍니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>인덱스</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124819</guid>
			<comments>https://www.sqler.com/board_Column/1124819#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:22:42 +0900</pubDate>
		</item><item>
			<title>SQL강좌: 12-7. 인덱스 생성과 관리 - 인덱스 옵션</title>
			<link>https://www.sqler.com/board_Column/1124813</link>
						<description>&lt;p&gt;안녕하세요. SQLER의 코난 김대우입니다.&amp;nbsp;&lt;br /&gt; 이번 강좌에서는, 12-7. 인덱스 생성과 관리 - 인덱스 옵션을&amp;nbsp;진행 하겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;a href=&quot;https://www.sqler.com/board_Column/1124468&quot;&gt;SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이번에 진행할 강좌는 인덱스 생성과 관리 - 인덱스 옵션입니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;iframe allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/5GWF-jx3uso?si=jDtwvnxdY_AzJDpE&quot; title=&quot;YouTube video player&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;TL;DR&lt;/h3&gt; &lt;p&gt;인덱스 생성 옵션에 대해 설명합니다. 고유 인덱스(Unique Index)는 중복 값을 허용하지 않는 기능을 제공하며, 채우기 비율(Fill Factor)은 인덱스 구조 조정과 데이터 수정 발생 시, 성능 개선을 위해 활용됩니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 인덱스를 생성하면서 여러 옵션을 이용할 수 있습니다. 색인의 구조와 탐색 패턴을 살펴보셨다면, 이런 옵션들을 이용해 더 상세하게 제어할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;그럼, 인덱스를 SQL 구문으로 생성하면서 자세히 살펴보겠습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 클러스터형 인덱스와 비클러스터형드 인덱스 생성은 앞에서 진행했으니, 고유 인덱스(Unique Index)를 짧게 살펴보고, 채우기 비율(Fill Factor)을 진행하겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;고유 인덱스(Unique Index)&lt;/h2&gt; &lt;p&gt;먼저 SQL 구문을 실행해 생성하고 살펴보겠습니다. 이 예제는 이전 강좌에서 생성한 SQLERTestDB와 IndexDummy 테이블을 재사용합니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;SQLERTestDB;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;조회&lt;br /&gt; SELECT&amp;nbsp;TOP&amp;nbsp;100&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy;&lt;br /&gt; SELECT&amp;nbsp;COUNT(*)&amp;nbsp;FROM&amp;nbsp;IndexDummy;&lt;br /&gt; &lt;br /&gt; --고유&amp;nbsp;인덱스&amp;nbsp;생성&lt;br /&gt; CREATE&amp;nbsp;UNIQUE&amp;nbsp;INDEX&amp;nbsp;idx_dummy_str&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;(dummy_str);&lt;br /&gt; &lt;br /&gt; --중복&amp;nbsp;데이터&amp;nbsp;삽입&amp;nbsp;시도-&amp;nbsp;에러&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;IndexDummy(idx,&amp;nbsp;dummy_str)&amp;nbsp;VALUES(10001,&amp;nbsp;&amp;#39;복사한_dummy_str_데이터&amp;#39;);&lt;br /&gt; --INSERT&amp;nbsp;INTO&amp;nbsp;IndexDummy(idx,&amp;nbsp;dummy_str)&amp;nbsp;VALUES(10001,&amp;nbsp;&amp;#39;2C579027-F972-4F7D-BCA6-3669575F83FE&amp;#39;);&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; 메시지&amp;nbsp;2601,&amp;nbsp;수준&amp;nbsp;14,&amp;nbsp;상태&amp;nbsp;1,&amp;nbsp;줄&amp;nbsp;13&lt;br /&gt; Cannot&amp;nbsp;insert&amp;nbsp;duplicate&amp;nbsp;key&amp;nbsp;row&amp;nbsp;in&amp;nbsp;object&amp;nbsp;&amp;#39;dbo.IndexDummy&amp;#39;&amp;nbsp;with&amp;nbsp;unique&amp;nbsp;index&amp;nbsp;&amp;#39;idx_dummy_str&amp;#39;.&amp;nbsp;The&amp;nbsp;duplicate&amp;nbsp;key&amp;nbsp;value&amp;nbsp;is&amp;nbsp;(2C579027-F972-4F7D-BCA6-3669575F83FE).&lt;br /&gt; The&amp;nbsp;statement&amp;nbsp;has&amp;nbsp;been&amp;nbsp;terminated.&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;고유 인덱스는 인덱스 기능 + 고윳값 제약 설정입니다. 고유 인덱스를 설정하면 테이블에 중복 값을 넣으려 할 경우 에러가 발생합니다. IGNORE_DUP_KEY 옵션을 이용하면, 에러를 발생시키지 않고 INSERT 구문을 무시할 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;고유 인덱스에 WITH IGNORE_DUP_KEY 옵션 적용&lt;/h3&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--인덱스&amp;nbsp;삭제&lt;br /&gt; DROP&amp;nbsp;INDEX&amp;nbsp;IndexDummy.idx_dummy_str;&lt;br /&gt; &lt;br /&gt; --유니크&amp;nbsp;인덱스&amp;nbsp;생성&amp;nbsp;-&amp;nbsp;WITH&amp;nbsp;IGNORE_DUP_KEY&lt;br /&gt; CREATE&amp;nbsp;UNIQUE&amp;nbsp;INDEX&amp;nbsp;idx_dummy_str&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;(dummy_str)&lt;br /&gt; WITH&amp;nbsp;IGNORE_DUP_KEY;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;조회&lt;br /&gt; SELECT&amp;nbsp;TOP&amp;nbsp;100&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy;&lt;br /&gt; &lt;br /&gt; --&amp;nbsp;다시&amp;nbsp;중복&amp;nbsp;데이터&amp;nbsp;삽입&amp;nbsp;시도&lt;br /&gt; INSERT&amp;nbsp;INTO&amp;nbsp;IndexDummy(idx,&amp;nbsp;dummy_str)&amp;nbsp;VALUES(10001,&amp;nbsp;&amp;#39;복사한_dummy_str_데이터&amp;#39;);&lt;br /&gt; --INSERT&amp;nbsp;INTO&amp;nbsp;IndexDummy(idx,&amp;nbsp;dummy_str)&amp;nbsp;VALUES(10001,&amp;nbsp;&amp;#39;2C579027-F972-4F7D-BCA6-3669575F83FE&amp;#39;);&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; Duplicate&amp;nbsp;key&amp;nbsp;was&amp;nbsp;ignored.&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 오류가 발생하지 않고, 결과는 무시됩니다. 대량 데이터를 추가하거나, 중복 값을 입력할 필요가 없을 경우 이렇게 IGNORE_DUP_KEY 옵션을 이용합니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 테이블에 이미 기본 키(Primary Key)가 있더라도 고윳값을 식별할 수 있는 고유 인덱스로 테이블에 추가되는 값의 고유성과 인덱스 성능을 보장받을 수 있습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;채우기 비율(Fill Factor)&lt;/h2&gt; &lt;p&gt;다음은 인덱스 성능의 중요 옵션 - 채우기 비율을 간략히 말씀드리겠습니다. 인덱스를 생성하고 데이터가 변경될 경우, 인덱스는 일정 조건에 맞춰 함께 변경됩니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 특히, 이미 인덱스의 B트리 구조가 완전히 밸런싱 되어 모든 노드 값이 채워져 있을 때, 대량의 데이터 삽입이 발생하면, B트리 구조 리밸런싱을 위해 노드를 추가하고 인덱스를 재정렬 하고 변경하면서 시스템에 부하를 줄 수 있습니다. 이런 과정을 SQL Server &amp;ldquo;페이지 분할(Page Split)&amp;rdquo;이라고 부릅니다. 이런 경우를 대비해 Fill Factor를 조절하면, 데이터 추가나 변경에 대비해 인덱스 구조에 여유를 둘 수 있습니다.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 즉, Fill Factor가 100%라면, 현재 인덱스 리프 레벨이 100%로 가득 채워져 있는 상태입니다. 적절한 수량만큼만 채우는 80% 정도로 값을 설정하면 인덱스 리프레벨은 20% 정도의 여유 공간이 생깁니다. 하지만! 인덱스 데이터 페이지가 채우기 비율만큼 늘어나기 때문에 약간의 인덱스 쿼리 속도 저하가 있습니다.&lt;br /&gt; SQL 구문 예제로 설명드리겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;USE&amp;nbsp;SQLERTestDB;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --데이터&amp;nbsp;테스트&amp;nbsp;조회&lt;br /&gt; SELECT&amp;nbsp;TOP&amp;nbsp;100&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;IndexDummy;&lt;br /&gt; SELECT&amp;nbsp;COUNT(*)&amp;nbsp;FROM&amp;nbsp;IndexDummy;&lt;br /&gt; &lt;br /&gt; --인덱스&amp;nbsp;재생성&amp;nbsp;-&amp;nbsp;WITH&amp;nbsp;DROP_EXISTING&amp;nbsp;옵션&lt;br /&gt; CREATE&amp;nbsp;CLUSTERED&amp;nbsp;INDEX&amp;nbsp;idx_id&amp;nbsp;ON&amp;nbsp;IndexDummy(idx)&lt;br /&gt; WITH&amp;nbsp;DROP_EXISTING;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --인덱스&amp;nbsp;정보&amp;nbsp;조회&lt;br /&gt; EXEC&amp;nbsp;sp_helpindex&amp;nbsp;&amp;#39;IndexDummy&amp;#39;;&lt;br /&gt; &lt;br /&gt; --평균&amp;nbsp;페이지&amp;nbsp;밀도&amp;nbsp;판단&amp;nbsp;-&amp;nbsp;Avg.&amp;nbsp;Page&amp;nbsp;Density&amp;nbsp;(full)&amp;nbsp;값&amp;nbsp;참조&lt;br /&gt; DBCC&amp;nbsp;SHOWCONTIG(IndexDummy);&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; DBCC&amp;nbsp;SHOWCONTIG&amp;nbsp;scanning&amp;nbsp;&amp;#39;IndexDummy&amp;#39;&amp;nbsp;table...&lt;br /&gt; Table:&amp;nbsp;&amp;#39;IndexDummy&amp;#39;&amp;nbsp;(1173579219);&amp;nbsp;index&amp;nbsp;ID:&amp;nbsp;1,&amp;nbsp;database&amp;nbsp;ID:&amp;nbsp;10&lt;br /&gt; TABLE&amp;nbsp;level&amp;nbsp;scan&amp;nbsp;performed.&lt;br /&gt; -&amp;nbsp;Pages&amp;nbsp;Scanned................................:&amp;nbsp;124&lt;br /&gt; -&amp;nbsp;Extents&amp;nbsp;Scanned..............................:&amp;nbsp;16&lt;br /&gt; -&amp;nbsp;Extent&amp;nbsp;Switches..............................:&amp;nbsp;15&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Pages&amp;nbsp;per&amp;nbsp;Extent........................:&amp;nbsp;7.8&lt;br /&gt; -&amp;nbsp;Scan&amp;nbsp;Density&amp;nbsp;[Best&amp;nbsp;Count:Actual&amp;nbsp;Count].......:&amp;nbsp;100.00%&amp;nbsp;[16:16]&lt;br /&gt; -&amp;nbsp;Logical&amp;nbsp;Scan&amp;nbsp;Fragmentation&amp;nbsp;..................:&amp;nbsp;0.00%&lt;br /&gt; -&amp;nbsp;Extent&amp;nbsp;Scan&amp;nbsp;Fragmentation&amp;nbsp;...................:&amp;nbsp;50.00%&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Bytes&amp;nbsp;Free&amp;nbsp;per&amp;nbsp;Page.....................:&amp;nbsp;112.1&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Page&amp;nbsp;Density&amp;nbsp;(full).....................:&amp;nbsp;98.61%&lt;br /&gt; DBCC&amp;nbsp;execution&amp;nbsp;completed.&amp;nbsp;If&amp;nbsp;DBCC&amp;nbsp;printed&amp;nbsp;error&amp;nbsp;messages,&amp;nbsp;contact&amp;nbsp;your&amp;nbsp;system&amp;nbsp;administrator.&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;기본적으로 채우기 옵션 없이 인덱스를 생성하면 페이지 밀도가 100%에 가깝게 생성됩니다. 그렇다면, 데이터를 적절히 지우거나 추가해 페이지 밀도를 조절해 보겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--하나&amp;nbsp;건너&amp;nbsp;하나씩&amp;nbsp;데이터&amp;nbsp;삭제&lt;br /&gt; BEGIN&amp;nbsp;TRAN;&lt;br /&gt; DELETE&amp;nbsp;FROM&amp;nbsp;IndexDummy&amp;nbsp;WHERE&amp;nbsp;idx&amp;nbsp;%&amp;nbsp;2&amp;nbsp;=&amp;nbsp;0;&lt;br /&gt; COMMIT&amp;nbsp;TRAN;&lt;br /&gt; &lt;br /&gt; --평균&amp;nbsp;페이지&amp;nbsp;밀도&amp;nbsp;판단.&lt;br /&gt; DBCC&amp;nbsp;SHOWCONTIG(IndexDummy);&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; DBCC&amp;nbsp;SHOWCONTIG&amp;nbsp;scanning&amp;nbsp;&amp;#39;IndexDummy&amp;#39;&amp;nbsp;table...&lt;br /&gt; Table:&amp;nbsp;&amp;#39;IndexDummy&amp;#39;&amp;nbsp;(1173579219);&amp;nbsp;index&amp;nbsp;ID:&amp;nbsp;1,&amp;nbsp;database&amp;nbsp;ID:&amp;nbsp;10&lt;br /&gt; TABLE&amp;nbsp;level&amp;nbsp;scan&amp;nbsp;performed.&lt;br /&gt; -&amp;nbsp;Pages&amp;nbsp;Scanned................................:&amp;nbsp;124&lt;br /&gt; -&amp;nbsp;Extents&amp;nbsp;Scanned..............................:&amp;nbsp;16&lt;br /&gt; -&amp;nbsp;Extent&amp;nbsp;Switches..............................:&amp;nbsp;15&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Pages&amp;nbsp;per&amp;nbsp;Extent........................:&amp;nbsp;7.8&lt;br /&gt; -&amp;nbsp;Scan&amp;nbsp;Density&amp;nbsp;[Best&amp;nbsp;Count:Actual&amp;nbsp;Count].......:&amp;nbsp;100.00%&amp;nbsp;[16:16]&lt;br /&gt; -&amp;nbsp;Logical&amp;nbsp;Scan&amp;nbsp;Fragmentation&amp;nbsp;..................:&amp;nbsp;0.00%&lt;br /&gt; -&amp;nbsp;Extent&amp;nbsp;Scan&amp;nbsp;Fragmentation&amp;nbsp;...................:&amp;nbsp;50.00%&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Bytes&amp;nbsp;Free&amp;nbsp;per&amp;nbsp;Page.....................:&amp;nbsp;4104.1&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Page&amp;nbsp;Density&amp;nbsp;(full).....................:&amp;nbsp;49.29%&lt;br /&gt; DBCC&amp;nbsp;execution&amp;nbsp;completed.&amp;nbsp;If&amp;nbsp;DBCC&amp;nbsp;printed&amp;nbsp;error&amp;nbsp;messages,&amp;nbsp;contact&amp;nbsp;your&amp;nbsp;system&amp;nbsp;administrator.&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;하나 건너 하나씩 데이터를 지우는 쿼리를 수행했고, 다시 DBCC 명령을 수행해 보면 페이지 밀도가 떨어진 것을 확인할 수 있습니다.&lt;br /&gt; 그럼 채우기 비율을 설정해 인덱스를 구성하고 다시 페이지 밀도를 체크해 보겠습니다.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--인덱스&amp;nbsp;재생성&amp;nbsp;WITH&amp;nbsp;FILLFACTOR&amp;nbsp;설정&lt;br /&gt; CREATE&amp;nbsp;CLUSTERED&amp;nbsp;INDEX&amp;nbsp;idx_id&amp;nbsp;ON&amp;nbsp;IndexDummy(idx)&lt;br /&gt; WITH&amp;nbsp;FILLFACTOR&amp;nbsp;=&amp;nbsp;80,&amp;nbsp;DROP_EXISTING;&lt;br /&gt; GO&lt;br /&gt; &lt;br /&gt; --평균&amp;nbsp;페이지&amp;nbsp;밀도&amp;nbsp;판단.&lt;br /&gt; DBCC&amp;nbsp;SHOWCONTIG(IndexDummy);&lt;br /&gt; &lt;br /&gt; 결과&lt;br /&gt; DBCC&amp;nbsp;SHOWCONTIG&amp;nbsp;scanning&amp;nbsp;&amp;#39;IndexDummy&amp;#39;&amp;nbsp;table...&lt;br /&gt; Table:&amp;nbsp;&amp;#39;IndexDummy&amp;#39;&amp;nbsp;(1173579219);&amp;nbsp;index&amp;nbsp;ID:&amp;nbsp;1,&amp;nbsp;database&amp;nbsp;ID:&amp;nbsp;10&lt;br /&gt; TABLE&amp;nbsp;level&amp;nbsp;scan&amp;nbsp;performed.&lt;br /&gt; -&amp;nbsp;Pages&amp;nbsp;Scanned................................:&amp;nbsp;76&lt;br /&gt; -&amp;nbsp;Extents&amp;nbsp;Scanned..............................:&amp;nbsp;10&lt;br /&gt; -&amp;nbsp;Extent&amp;nbsp;Switches..............................:&amp;nbsp;9&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Pages&amp;nbsp;per&amp;nbsp;Extent........................:&amp;nbsp;7.6&lt;br /&gt; -&amp;nbsp;Scan&amp;nbsp;Density&amp;nbsp;[Best&amp;nbsp;Count:Actual&amp;nbsp;Count].......:&amp;nbsp;100.00%&amp;nbsp;[10:10]&lt;br /&gt; -&amp;nbsp;Logical&amp;nbsp;Scan&amp;nbsp;Fragmentation&amp;nbsp;..................:&amp;nbsp;0.00%&lt;br /&gt; -&amp;nbsp;Extent&amp;nbsp;Scan&amp;nbsp;Fragmentation&amp;nbsp;...................:&amp;nbsp;10.00%&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Bytes&amp;nbsp;Free&amp;nbsp;per&amp;nbsp;Page.....................:&amp;nbsp;1582.8&lt;br /&gt; -&amp;nbsp;Avg.&amp;nbsp;Page&amp;nbsp;Density&amp;nbsp;(full).....................:&amp;nbsp;80.44%&lt;br /&gt; DBCC&amp;nbsp;execution&amp;nbsp;completed.&amp;nbsp;If&amp;nbsp;DBCC&amp;nbsp;printed&amp;nbsp;error&amp;nbsp;messages,&amp;nbsp;contact&amp;nbsp;your&amp;nbsp;system&amp;nbsp;administrator.&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;채우기 비율을 80으로 설정했고 확인해 보면 80%로 설정된 것을 확인 가능합니다. 채우기 비율은 현재 테이블의 데이터가 너무 적을 경우 또는 익스텐트를 사용하는 VARCHAR(MAX) 등의 데이터형이 사용될 경우 채우기 설정과 약간 다르게 생성될 수 있으니 주의하세요.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;PAD_INDEX 설정&lt;/h2&gt; &lt;p&gt;이전 강좌에서 잠시 소개해 드렸습니다. 채우기 비율 Fill Factor와 비슷한 PAD_INDEX입니다. PAD_INDEX와 FILL_FACTOR의 차이는 PAD_INDEX는 중간레벨에도 여유 공간을 두고 생성합니다.&lt;/p&gt; &lt;div code_type=&quot;Sql&quot; collapse=&quot;false&quot; editor_component=&quot;code_highlighter&quot; first_line=&quot;1&quot; highlight=&quot;&quot; nogutter=&quot;false&quot; style=&quot;font-family:&#039;DejaVu Sans Mono&#039;, &#039;Courier New&#039;, Courier, monospace !important; border:#666 1px dotted;border-left:#2AE 5px solid;padding:5px;background:#FAFAFA url(&#039;./modules/editor/components/code_highlighter/component_icon.gif&#039;) no-repeat top right;&quot; title=&quot;&quot;&gt;--PAD_INDEX&amp;nbsp;추가&amp;nbsp;-&amp;nbsp;인덱스&amp;nbsp;재생성&lt;br /&gt; CREATE&amp;nbsp;CLUSTERED&amp;nbsp;INDEX&amp;nbsp;idx_id&amp;nbsp;ON&amp;nbsp;IndexDummy&amp;nbsp;(idx)&lt;br /&gt; WITH&amp;nbsp;FILLFACTOR&amp;nbsp;=&amp;nbsp;80,&amp;nbsp;PAD_INDEX,&amp;nbsp;DROP_EXISTING;&lt;br /&gt; GO&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;이렇게 PAD_INDEX 옵션을 추가할 수 있습니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; 인덱스를 생성할 때 데이터 삽입과 수정, 삭제 비율을 고려해 FILL_FACTOR와 PAD_INDEX를 적절히 구성하세요. 이후 SQL 유지 관리 계획(Maintenance Plan)을 통해 주기적으로 인덱스를 유지보수 할 경우, 생성 시 설정한 FILL_FACTOR와 PAD_INDEX 값으로 인덱스를 재구성하거나 재생성합니다.&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;SQL 강좌 책 구매&lt;/h2&gt; &lt;p&gt;강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;책구매 링크:&amp;nbsp;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;챗GPT와 함께하는 마이크로소프트 SQL Server 2022&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://bookk.co.kr/bookStore/64ec562e1d03458e7daeb5dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;책구매링크.png&quot; rel=&quot;xe_gallery&quot; src=&quot;https://www.sqler.com/files/attach/images/2023/09/04/fb62c8feb65d54356099e8a4bee6f881.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
						<category>데이터베이스 개발자 Tip &amp; 강좌</category>			<category>SQL서버</category>			<category>SQL강좌</category><category>튜토리얼</category><category>인덱스</category>			<dc:creator>코난(김대우)</dc:creator>
			<guid isPermaLink="true">https://www.sqler.com/board_Column/1124813</guid>
			<comments>https://www.sqler.com/board_Column/1124813#comment</comments>			<pubDate>Fri, 18 Aug 2023 17:21:56 +0900</pubDate>
		</item>	</channel>
</rss>
