<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>glory_95.log</title>
        <link>https://velog.io/</link>
        <description>힘들더라도 꾸준히!</description>
        <lastBuildDate>Tue, 12 Sep 2023 06:19:12 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>glory_95.log</title>
            <url>https://velog.velcdn.com/images/glory_95/profile/54731d0b-d1cc-4752-95c1-ee0b40c87c27/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. glory_95.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/glory_95" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[PostgreSQL] 재귀/계층 쿼리 Recursive]]></title>
            <link>https://velog.io/@glory_95/SQL-%EC%A0%95%EB%A6%AC%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@glory_95/SQL-%EC%A0%95%EB%A6%AC%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Tue, 12 Sep 2023 06:19:12 GMT</pubDate>
            <description><![CDATA[<p>PostgreSQL에서 WITH RECURSIVE 구문을 사용하여 java의 for문의 반복문처럼 사용이 가능하다.</p>
<p>재귀적 쿼리인데 이는 보통 테이블 데이터가 계층형일때 많이 사용된다.</p>
<pre><code class="language-sql">with recursive 뷰명 as(
    초기 SQL

    union all(or union)

    반복할 SQL(+반복을 멈출 where절 포함)

)select * from 뷰명;</code></pre>
<p>원리</p>
<ol>
<li><p>초기 SQL을 실행하면 실행한 결과셋은 recursive문을 선언할때 기재한 뷰에 담긴다.</p>
</li>
<li><p>반복할 SQL의 from 절에 뷰명을 이용해서 처리하거나 한다. 이는 상황에 따라 다르지만 주로 뷰명을 from절에 두고 반복문을 돌리는 것이 일반적이다.</p>
</li>
<li><p>union 혹은 union all 연산을 한다.(경우에따라 다름 마이너스도 가능)</p>
</li>
<li><p>반복할 SQL에서 단하나의 레코드가 나오지 않을때 recursive문을 탈출한다.</p>
</li>
<li><p>recursive문을 탈출하였으면 뷰명에 연산된 결과셋이 다시 담기게되고 뷰처럼 조회할 수 있다.</p>
</li>
</ol>
<p>활용</p>
<pre><code class="language-sql">WITH RECURSIVE random_values(random_value, row_num) AS (
    SELECT random() AS random_value, 1 AS row_num
    UNION ALL
    SELECT random(), row_num + 1
    FROM random_values
    WHERE row_num &lt; 10
)
SELECT * FROM random_values;</code></pre>
<p>랜덤값을 총 10회 출력하는 쿼리문을 작성해보았다.
이에대한 결과값은 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/cecaa99d-4767-42e4-b1ad-84a3f8d070e6/image.png" alt=""></p>
<p>그럼 단순히 숫자를 1씩 늘려가면 반복문을 짜기 보다는 이를 조금 더 활용해서 계층형 구조의 데이터에서 어떻게 활용을 하는지 보자.</p>
<p>먼저 테스트 하기위해 테이블에 아래의 데이터를 insert 했다고 가정하자.</p>
<pre><code class="language-sql">create table recursive_test(group_id numeric, parent_id numeric);

insert into recursive_test values(0, null);
insert into recursive_test values(1, 0);
insert into recursive_test values(2, 1);
insert into recursive_test values(3, 1);
insert into recursive_test values(4, 1);
insert into recursive_test values(5, 2);
insert into recursive_test values(6, 2);
insert into recursive_test values(7, 2);
insert into recursive_test values(8, 5);
insert into recursive_test values(9, 5);
insert into recursive_test values(10, 3);
insert into recursive_test values(11, 3);
insert into recursive_test values(12, 3);
insert into recursive_test values(13, 9);
insert into recursive_test values(14, 9);</code></pre>
<p>또한 계층형 쿼리를 짜기 위해서 기본적인 문법은 아래와 같다.</p>
<pre><code class="language-sql">with recursive Alias_VIEW([그룹컬럼],[부모컬럼]) as (
    select 그룹컬럼, 부모컬럼
    from 그룹테이블
    where 그룹컬럼시작조건

    union all

    select 그룹컬럼, 부모컬럼
    from 그룹테이블, Alias_VIEW
    where 그룹번호 = 부모 번호 &lt; 역순 &gt;
) select 그룹컬럼, 부모컬럼 from Alias_VIEW;</code></pre>
<p>여기서 union all 기준으로 앞의 쿼리는 계층의 시작의 기준점으로 보면된다
최종적으로는 데이터의 맨 앞에 위치하게 된다</p>
<p>그렇다면 group_id 가 13인 데이터의 부모를 조회하고 또 그 데이터의 부모를 반복해서 조회하는 쿼리를 짜는 쿼리는 아래와 같다.</p>
<pre><code class="language-sql">with recursive childlist(group_id,parent_id, level) as (
        select group_id, parent_id, 0    
        from recursive_test rt
        where group_id = &#39;13&#39;
        union all 
        select c.group_id,c.parent_id, p.level+1 
        from recursive_test c, childlist p
        where c.group_id = p.parent_id
    ) select *from childlist;</code></pre>
<ul>
<li>13의 부모인 9,</li>
<li>9 의 부모인 5,</li>
<li>5 의 부모인 2,</li>
<li>2 의 부모인 1,</li>
<li>1 의 부모인 0</li>
</ul>
<p>결국 parent_id가 9 5 2 1 0 가 조회된다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/8afe2d37-1143-491a-8ef9-4c0bd272d418/image.png" alt=""></p>
<p>그렇다면 자식을 반복으로 조회하는 쿼리는 아래와 같다.</p>
<pre><code class="language-sql">with recursive childlist(group_id,parent_id, level) as (
    select group_id, parent_id, 0    
    from recursive_test rt
    where group_id = &#39;5&#39;
    union all 
    select c.group_id,c.parent_id, p.level+1 
    from recursive_test c, childlist p
    where c.parent_id = p.group_id
) select *from childlist;</code></pre>
<ul>
<li>5 의 자신의 5,</li>
<li>5 의 자식인 8,</li>
<li>5 의 자식인 9,</li>
<li>9 의 자식인 13,</li>
<li>9 의 자식인 14 </li>
</ul>
<p>즉, 자식인 group_id가 5 8 9 13 14 조회된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux 기본활용]]></title>
            <link>https://velog.io/@glory_95/DE-Linux-%EA%B8%B0%EB%B3%B8%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@glory_95/DE-Linux-%EA%B8%B0%EB%B3%B8%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Mon, 11 Sep 2023 12:25:27 GMT</pubDate>
            <description><![CDATA[<h1 id="linux-기본명령어">Linux 기본명령어</h1>
<h2 id="man-파일시스템-명령어">man, 파일시스템 명령어</h2>
<h3 id="man">man</h3>
<ul>
<li>원하는 명령어의 설명을 볼 수 있다. 특정 명령어의 사용방법을 확인할 수 있다.</li>
<li>운영체제의 기본 명령어가 아닌경우, -help, --help,의 파라미터로 설명을 제공하는 명령어들도 있다.</li>
<li>설명이 한눈에 안들어온다면, vi key로 이동, 검색을 할 수 있다.</li>
</ul>
<h3 id="help-parameter-help">help parameter(-help)</h3>
<ul>
<li>리눅스 기본 명령어도 지원을 하는 경우가 잇다. 하지만, 기본 명령어는 man이 기본이다.</li>
</ul>
<h3 id="리눅스에서-경로를-표시하는-방법">리눅스에서 경로를 표시하는 방법</h3>
<ul>
<li>/ : root, 시스템의 가장 시작 또는 디렉토리를 구분하는 구분자</li>
<li>~ : home,로그인한 유저의 home 경로, 환경변수로 바꿀수 있다.</li>
<li>.. : 상위 디렉토리</li>
<li>. : 현재 디렉토리</li>
<li>&#39;-&#39; : 이전 위치</li>
</ul>
<h3 id="pwd">pwd</h3>
<ul>
<li>print Work Directory 의 약자</li>
<li>현재 터미널이 위치한 디렉토리 경로를 볼 수 있다.</li>
</ul>
<h3 id="ls">ls</h3>
<p>= list segments의 약자</p>
<ul>
<li><p>디렉토리의 모든 파일 정보를 보여줌</p>
<blockquote>
<p>ls -al : 숨김파일과 파일의 모든 정보를 표시한다.
ll 이라는 alias로 편하게 사용하기도 한다.</p>
</blockquote>
<blockquote>
<p>ls -il : 파일 또는 디렉토리의 inode number을 표시한다. 
inode란 리눅스에서 파일 또는 디렉토리의 고유 식별 부호, 파일 이름이 바뀌어도 유지된다.</p>
</blockquote>
</li>
</ul>
<h3 id="cd">cd</h3>
<ul>
<li>Change Directory의 약자</li>
<li>지정한 디렉토리로 이동</li>
<li>기본은 현재 위치부터 상대 경로로 이동, root(/)부터 모든 경로를 입력하면 절대 경로로 이동한다.</li>
</ul>
<h3 id="mkdir">mkdir</h3>
<p>= make directory의 약자</p>
<ul>
<li>새 디렉토리를 만든다</li>
<li>기본은 상대경로로 생성된다.</li>
<li>root부터 모든 경로를 입력하면 절대 경로에 디렉토리를 생성한다.</li>
</ul>
<h3 id="rm">rm</h3>
<ul>
<li>Remove</li>
<li>지정한 파일 또는 디렉토리를 지운다.</li>
<li>지울것인지 한 번 물어본다</li>
<li>-f 옵션으로 강제로 지운다.</li>
<li>-r 옵션으로 디렉토리와 디렉토리 안의 모든 내용을 지울 수 있다.</li>
</ul>
<h3 id="rmdir">rmdir</h3>
<ul>
<li>remove directory</li>
<li>디렉토리를 삭제한다.</li>
<li>rm -r 명령어로 대신할 수 있다.</li>
</ul>
<h3 id="df">df</h3>
<ul>
<li>disk filesystem</li>
<li>디스크 공간에 대한 정보를 볼 수 있다.</li>
<li>-h : human readable 옵션과 함께 많이 쓴다.</li>
</ul>
<h3 id="du">du</h3>
<ul>
<li>Disk Usage</li>
<li>df와 반대로 디스크 사용량, 사용률을 볼 수 있다.</li>
<li>-h : human readable 옵션과 함께 많이 쓴다.</li>
<li>-s : summary 해당 경로 하위의 총합을 보여준다.</li>
<li>-d : max-depth를 지정해서 해당 depth만큼 펼쳐서 보여준다.</li>
</ul>
<h3 id="chmod">chmod</h3>
<ul>
<li>권한을 변경하는 명령어</li>
</ul>
<p>hmod 명령어는 디렉토리나 파일의 읽기, 쓰기, 실행 권한을 변경할 수 있다.</p>
<p>OS에 로그인한 사용자와 디렉토리나 파일의 소유자 같은 경우 chmod로 권한을 변경한다.</p>
<p>먼저, chmod로 권한을 변경하는 방법은 두 가지이다.</p>
<ul>
<li><p>+, -, = 기호를 통해 권한 유형을 표기하여 변경하는 Symbolic method 방법</p>
</li>
<li><p>rwx를 3bit로 해석(8진수)하여 3자리 숫자로 표기하는 Absolute form 방법</p>
</li>
</ul>
<p><strong>Symbolic method 방법</strong></p>
<blockquote>
</blockquote>
<p>이 방법은 액세스 클래스(Access class), 연산자(Operator), 액세스 타입(Access Type)으로 구분한다.</p>
<ul>
<li>액세스 클래스 : u (user), g (group), o (other), a (all)</li>
<li>연산자 : + (add access), - (remove access), = (set exact access)</li>
<li>액세스 타입 : r (read), w (write), x (execute)</li>
</ul>
<p>명령어 chmod 뒤에 변경할 권한을 입력한다.</p>
<p>액세스 클래스, 연산자, 액세스 타입 순서로 조건에 따라 조합하여 입력한다.</p>
<pre><code>chmod g-r filename    # 그룹의 읽기 권한을 제거한다.
chmod g+r filename    # 그룹의 읽기 권한을 부여한다.
chmod g-w filename    # 그룹의 쓰기 권한을 제거한다.
chmod g+w filename    # 그룹의 쓰기 권한을 부여한다.
chmod g-x filename    # 그룹의 실행 권한을 제거한다.
chmod g+x filename    # 그룹의 실행 권한을 부여한다.
chmod o-r filename    # 다른 사용자의 읽기 권한을 제거한다.
chmod o+r filename    # 다른 사용자의 읽기 권한을 부여한다.
chmod o-w filename    # 다른 사용자의 쓰기 권한을 제거한다.
chmod o+w filename    # 다른 사용자의 쓰기 권한을 부여한다.
chmod o-x filename    # 다른 사용자의 실행 권한을 제거한다.
chmod o+x filename    # 다른 사용자의 실행 권한을 부여한다.
chmod u+x filename    # 소유자의 실행 권한을 부여한다.</code></pre><p>또한, 연산자를 사용하여 다중 권한 부여 및 제거가 가능하다.</p>
<pre><code>#초기 filename의 권한이 ----------이라 가정하고 순서대로 명령을 했을 때
chmod a=rw filename # -rw-rw-rw-
chmod u= filename # ----rw-rw-
chmod a+rx filename # -r-xrwxrwx
chmod go-wx filename # -r-x-r--r--
chmod a= filename # ----------
chmod u+rwx filename # -rwx------</code></pre><p><strong>Absolute form 방법</strong></p>
<p>소유자, 그룹, 다른 사용자의 권한을 r, w, x 순서로 8진수로 해석하여 3자리로 표현한다.</p>
<ul>
<li><p>r (read) : 4</p>
</li>
<li><p>w (write) : 2</p>
</li>
<li><p>x (Ececute) : 1</p>
</li>
</ul>
<p>부여하고 싶은 권한의 수를 더함으로써 표현하는 것이 쉬울 것이다.</p>
<pre><code># filename의 권한을 -rwxrwxrwx로 하고 싶다면
chmod 777 filename

# filename의 권한을 ----------로 하고 싶다면
chmod 000 filename

# filename의 권한을 -r--r--r--로 하고 싶다면
chmod 444 filename

# filename의 권한을 --w--w--w-로 하고 싶다면
chmod 222 filename

# filename의 권한을 ---x--x--x로 하고 싶다면
chmod 111 filename

# filename의 권한을 -r-x-w--wx로 하고 싶다면
chmod 523 filename</code></pre><h2 id="파일-관리를-위한-명령어">파일 관리를 위한 명령어</h2>
<h3 id="touch">touch</h3>
<ul>
<li>touch 명령어는 파일의 생성과 파일의 날짜, 시간을 변경하는 명령어이다.</li>
<li>옵션 없이 사용할 경우 서버의 현재시간으로 변경된다.</li>
<li>파일이 존재하지 않을 경우 크기가 0인 파일을 생성하며, 한번에 여러개의 파일을 만들수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/glory_95/post/c3eb6922-dc94-4050-bb68-ec4bf60fd244/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/f9192372-abc8-4745-9729-7d46c3a597f4/image.png" alt=""></p>
<h3 id="cat">cat</h3>
<ul>
<li>파일 내용을 출력한다.</li>
<li>다른 명령어와 함께 사용하면 유용하다.</li>
</ul>
<h3 id="head">head</h3>
<ul>
<li>파일 또는 파이프된 데이터의 시작점을 볼 수 있다.</li>
</ul>
<h3 id="tail">tail</h3>
<ul>
<li>head와 반대로 마지막행부터 지정한 행까지 내용을 출력한다.</li>
<li>tail -f $filename : 실시간으로 append 되는 내용을 확인할 수 있다. 로그를 실시간으로 볼 때 자주 활용된다.</li>
</ul>
<h3 id="comm">comm</h3>
<ul>
<li>compare의 약자</li>
<li>두 파일을 라인별로 비교한다.</li>
<li>옵션과 함께 사용한다.</li>
</ul>
<h3 id="cmp">cmp</h3>
<ul>
<li>두 파일을 바이트 단위로 비교한 결과를 stdout에 프린트한다.</li>
</ul>
<h3 id="diff">diff</h3>
<ul>
<li>differnce의 약자</li>
<li>두 파일을 라인별로 비교해서 차이점만 보여준다.</li>
<li>symbol로 어떤 차이인지 표시한다.<blockquote>
<p>a : add
c : change
d : delete</p>
</blockquote>
</li>
</ul>
<h3 id="less">less</h3>
<ul>
<li>터미널 세션에 프린트하지 않고 파일 내용을 볼 수 있다.</li>
<li>vi 처럼 파일 전체를 여는것이 아니라 보고있는 부분만 열어서 파일이 큰 경우, vi에 비해 빠르게 열어 내용을 확인할 수 있다.</li>
<li>양방향 탐색이 가능하므로 more보다 편리하다.</li>
</ul>
<h3 id="ln">ln</h3>
<ul>
<li>심볼릭 링크를 만든다.</li>
<li>심볼릭 링크란? 
  : 절대 경로 또는 상대 경로의 형태로 된 다른 파일이나 디렉토리에 대한 참조를 포함하고 있는 특별한 종류의 파일</li>
<li>개인적으로 나는 어떠한 경로를 변수로 지정한듯한 느낌을 받음<blockquote>
<p>ln -s $경로이름 $변수이름</p>
</blockquote>
</li>
</ul>
<h3 id="alias">alias</h3>
<ul>
<li>다른 문자열에 대체하는 단어를 저장한다.</li>
<li>주로 복잡한 명령어의 약어를 지칭할 때 쓰임</li>
<li>환경변수와는 다르다.<blockquote>
<p>alias hellocmd = &quot;echo hello $@&quot;</p>
</blockquote>
</li>
</ul>
<h3 id="cp">cp</h3>
<ul>
<li>copy의 약어</li>
<li>파일이나 디렉토리 복사</li>
<li>-r 옵션으로 디렉토리 복사</li>
<li>cp [옵션][복사 할 디렉토리/파일][복사 될 디렉토리/파일]<blockquote>
<p>-i : 복사될 파일이 이름이 이미 존재할 경우, 사용자에게 덮어 쓰기 여부를 묻는다.</p>
</blockquote>
</li>
<li>b : 복사될 파일이 이름이 이미 존재할 경우, 백업파일을 생성한다.</li>
<li>f : 복사 될 파일이 이름이 이미 존재 할 경우, 강제로 덮어쓰기 한다.</li>
<li>r : 하위 디렉토리 까지 모두 복사한다.</li>
<li>a : 원본 파일의 속성, 링크 정보까지 모두 복사한다.</li>
<li>p : 원본 파일의 소유자, 그룹, 권한 등의 정보까지 모두 복사한다.</li>
<li>v : 복사 진행 상태를 출력한다.</li>
</ul>
<h3 id="mv">mv</h3>
<ul>
<li>move의 약어</li>
<li>파일이나 디렉토리를 이동</li>
<li>mv [옵션] [이동시킬 디렉토리/파일] [이동 될 위치]</li>
<li>mv 명령어는 [이동시킬 디렉토리/파일] [이동될 위치] 두 인자를 필수로 갖는다.</li>
<li>경로를 지정하지 않는다면 현 위치를 디폴트로 설정한다.</li>
<li>이동시킬 때 새로운 이름을 지정할 수 있다.</li>
<li>현재 위치에 이름만 바꿔서 이동시키는 식으로 파일의 이름을 바꾸기로 응용할 수 있다.</li>
</ul>
<blockquote>
<p>-b : 이동시킬 파일이 이미 존재하면 백업파일을 만든다.
-i : 이동시킬 파일이 이미 존재하면 사용자에게 덮어쓰기 여부를 묻는다.
-f : 이동시킬 파일이 이미 존재하면 강제로 덮어쓰기 한다.
-n : 이동시킬 파일이 이미 존재하면 덮어쓰기 하지 않는다.
-r : 하위 디렉토리까지 모두 이동한다.
-v : 이동 진행 상태를 출력한다.</p>
</blockquote>
<h2 id="검색에-사용하는-명령어">검색에 사용하는 명령어</h2>
<h3 id="find">find</h3>
<ul>
<li><p>파일을 검색할때 사용</p>
</li>
<li><p>find . -name $filename</p>
<blockquote>
<p>현재 경로에서 $filename의 이름을 가진 파일이나 디렉토리를 찾음</p>
</blockquote>
<h3 id="which">which</h3>
<ul>
<li>$PATH에 등록된 경로 중에서 주어진 이름의 실행 파일 위치를 찾는다.</li>
<li>사용하고 있는 명령어가 설치된 위치를 찾는데 유용</li>
</ul>
<h3 id="grep">grep</h3>
<ul>
<li>대량의 파일에서 주어진 텍스트 또는 정규표현식 패턴에 일치하는 텍스트를 찾는 명렁어</li>
<li>파이프와 함께 다양한 명령어와 조합하여 사용한다.</li>
</ul>
<h3 id="sed">sed</h3>
<ul>
<li>텍스트를 필터링하거나 변환하는 스트림 에디터</li>
<li>sed &#39;s/old_world/new_world/g&#39; target_file<blockquote>
<p>target_file에서 old_world 를 new_world로 모두 교체한 결과를 출력</p>
</blockquote>
</li>
<li>vi 에서도 :%s/old_word/new_world/g 를 이용하여 string을 교체할 수 있다.</li>
</ul>
<h3 id="uname">uname</h3>
<ul>
<li>이름,버전,기타 시스템 정보를 확인할 수 있다.</li>
<li>uname-a</li>
</ul>
<h3 id="ps">ps</h3>
<ul>
<li>현재 실행중인 프로세스를 볼 수 있다.</li>
<li>어떤 프로세스에 문제가 있는지, 내가 실행한 어플리케이션 프로세스의 상태를 보는데 사용할 수 있다.<blockquote>
<p>가장 중요하고 가장 많이 쓰이는 명령어니, 필요할 때마다 구글에 검색해서 보기</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h3 id="kill">kill</h3>
<ul>
<li>process에 signal을 전달한다.</li>
<li>프로세스를 종료하는 명령어</li>
</ul>
<h3 id="shutdown">shutdown</h3>
<ul>
<li>시스템 종료</li>
</ul>
<h3 id="halt">halt</h3>
<ul>
<li>시스템 강제종료</li>
</ul>
<h3 id="reboot">reboot</h3>
<ul>
<li>시스템 재시작</li>
</ul>
<h2 id="네트워크-활용을-위한-명령어">네트워크 활용을 위한 명령어</h2>
<h3 id="ss">ss</h3>
<ul>
<li>socket status의 약어</li>
<li>네트워크, 소켓의 사용을 쉽게 확인할 수 있다. 주로 열려있는 포트를 확인할 때 사용</li>
<li>내용이 긴 경우 pipe() 해서 less 또는 grep 등과 함께 사용</li>
</ul>
<h2 id="io관련-명령어">I/O관련 명령어</h2>
<h3 id="echo">echo</h3>
<ul>
<li>터미널 콘솔에 텍스트를 출력한다.</li>
<li>echo $(command)로 다른 명령어의 결과를 확인할 수 있다.</li>
</ul>
<h3 id="history">history</h3>
<ul>
<li>지나간 터미널 명령어 기록을 보여준다</li>
<li>로그아웃 하거나 세션을 종료하면 다시 볼 수 없다.</li>
<li>history 에서 확인한 명령어의 숫자를 !number 형태로 다시 불러올 수 있다.</li>
</ul>
<h3 id="redirection">redirection</h3>
<p><img src="https://velog.velcdn.com/images/glory_95/post/a4776a50-ddbe-4a1e-bf17-cce6745719d0/image.png" alt=""></p>
<h3 id="stdout-stderror">stdout, stderror</h3>
<p><img src="https://velog.velcdn.com/images/glory_95/post/59f6e4e1-b965-471a-9ba6-38bb9e06eaa6/image.png" alt=""></p>
<h2 id="vi-명령어">Vi 명령어</h2>
<h3 id="vi에서-이동하기">vi에서 이동하기</h3>
<ul>
<li><p>이동모드 </p>
</li>
<li><ul>
<li><blockquote>
<p>커서가 어디에 있던지, esc를 누르면 이동 모드가 됨. 편집할 수 없음</p>
</blockquote>
</li>
</ul>
</li>
<li><ul>
<li><blockquote>
<p>vi를 쓰면 수시로 esc를 누르는 습관이 필요</p>
</blockquote>
</li>
</ul>
</li>
<li><p>라인 숫자 같이보기</p>
</li>
<li><ul>
<li><blockquote>
<p>set number 입력</p>
</blockquote>
</li>
</ul>
</li>
<li><ul>
<li><blockquote>
<p>set nonumber 로 number 모드해체</p>
</blockquote>
</li>
</ul>
</li>
<li><p>커서 이동 명령키
h : 한문자 왼쪽으로 커서이동
j : 한문자 아래쪽으러 커서이동
k : 한문자 위쪽으로 커서이동
l : 한문자 오른쪽으로 커서이동
w : 다음 단어 첫 문자로 커서이동
b : 이전단어 첫 문자로 커서이동</p>
</li>
<li><p>행 이동 명령키
gg : 첫 행으로 이동
g : 마지막 행으로 이동
^ : 현재 행의 첫 문자로 이동
$ : 현재 행의 마지막 문자로 이동
:n 타이핑한 숫자n에 해당하는 행으로 이동
숫자 n 누르고 g : 해당 숫자만큼 아래로 행 이동
숫자 n 하고 엔터 : 현재커서의 행으로 부터 +n만큼 행이동</p>
</li>
<li><p>문자 검색을 이용한 이동(정규식 이용가능)
/문자열 : 커서 다음부터 문자열 검색, enter 누르면 커서이동
?문자열 : 커서 이전으로 문자열 검색, enter 누르면 커서 이동
n : 검색반복
N : 역방향으로 검색반복</p>
</li>
</ul>
<h3 id="vi에서-편집하기">vi에서 편집하기</h3>
<ul>
<li><p>입력관련된 명령어
i : 현재 커서 위치에 글자 삽입 가능. i 를 누르고 난 이후에 쓰는 글은 커서 위치에 쓰여짐
I : 현재 줄 처음 글자에 삽입
a : 현재 커서 다음위치에 추가
A : 현재 줄 마지막 글자에 추가
o : 아랫 줄에 추가
O : 윗 줄에 추가
s : 현재 커서 글자 지우고 입력 모드로 전환
r : 현재 커서 글자지우고 한글자 입력받아 바꾼뒤 명령모드로 들어감</p>
</li>
<li><p>삭제 관련된 명령어
x : 현재 커서 위치 문자 삭제
X : 현재 커서 위치 이전 문자 삭제
dw : 현재 커서 위치 단어 삭제, 숫자 dw로 쓰면 숫자만큼의 단어가 삭제됨
db : 현재 커서 위치 이전 단어 삭제
dd : 현재 커서 위치 줄 삭제, 숫자 dd 로 쓰면 숫자만큼의 줄이 삭제됨
d^ : 현재 줄에서 현재 커서 위치 이전 문자열을 마지막 문자까지 삭제
d0 : 현재 줄에서 현재 커서 위치 이전 문자열을 긑까지 삭제
d$ : 현재 줄에서 현재 커서 위치 이전까지 삭제</p>
</li>
<li><p>복사 붙여넣기
y : 복사, w,b,^,0,$ 등 다른 이동 표현과 함께 쓰면 그만큼 복사가 됨
yw : 현재 커서 이후 단어 복사, 숫자 yw로 쓰면 숫자만큼의 단어가 복사됨
yb : 현재 커서 이전단어 복사, 숫자 yb로 쓰면 숫자만큼의 단어가 복사됨
yy : 현재 줄 복사, 숫자 yy로 쓰면 숫자만큼의 줄이 복사됨
p : 복사된 항목을 현재 커서 위치 이후에 붙여 넣기, 삭제된 항목도 붙여넣기 가능
P : 복사된 항목을 현재 커서 위치 이전에 붙여 넣기, 삭제된 항목도 붙여넣기 가능</p>
</li>
<li><p>undo, redo
u : esc를 누른 명령모드에서 누르면, undo
Ctrl + r : esc를 누른 명령모드에서 누르면, redo</p>
</li>
</ul>
<h3 id="여러-파일-한번에-열고-파일을-이동하기">여러 파일 한번에 열고, 파일을 이동하기</h3>
<ul>
<li><p>vi file1 file2 file3 명령을 사용하면 동시에 여러 소스코드 파일을 열 수 있음
:n : 다음 버퍼 파일로 이동
:N : 이전 버퍼 파일로 이동
:ls : 현재 열려있는 버퍼의 리스트를 보여줌
:b숫자 : 숫자에 해당하는 버퍼로 이동
:bd숫자 : 숫자에 해당하는 버퍼를 삭제
:bw : 현재 버퍼를 삭제</p>
</li>
<li><p>vi 안에서 새로운 파일 열기
:e [tab] 또는 $filename : 해당 파일을 현재 vi 창에서 새로운 버퍼로 연다
:cd [tab] 또는 $filename : 해당 디렉토리로 이동한다. :e로 다음 파일을 찾을 때 적용</p>
</li>
<li><p>화면 분할해서 보기
:split : 현재 열린 파일과 같은 파일을 수평으로 분할해서 하나 더 연다.
:split $file : 새로운 파일을 현재 위치에 열고 현재 열린 파일은 수평으로 분할해서 연다.
:vsplit : 현재 열린 파일과 같은 파일을 수직으로 분할해서 하나 더 연다
:vsplit $filename : 새로운 파일을 현재 위치에 열고 현재 열린 파일은 수직으로 분할해서 연다.</p>
</li>
<li><p>화면 분할 상태에서 윈도우 이동하기
Ctrl+w,j : 아래 윈도우로 이동
Ctrl+w,k : 위 윈도우로 이동
Ctrl+w,l : 오른쪽 윈도우로 이동
Ctrl+w,h : 왼쪽 윈도우로 이동</p>
</li>
<li><p>화면 분할 상태에서 창 크기 조절하기 - 좌우
Ctrl+w,= : 모두 균일한 상태로 이동
Ctrl+w,&gt; : 오른쪽으로 1칸 확장
Ctrl+w,$num&gt; : 오른쪽으로 $num칸 확장
Ctrl+w,&lt; : 왼쪽으로 1칸 확장
Ctrl+w,$num&lt; 왼쪽으로 $num 칸 확장</p>
</li>
<li><p>화면 분할 상태에서 창 크기 조절하기 - 위아래
Ctrl+w,= : 모든 균일한 상태로 이동
Ctrl+w,+ : 위로 1칸 확장
Ctrl+w,$num+ : 위로 num칸 확장
Ctrl+w,- : 아래로 1칸 확장
Ctrl+w,$num- : 아래로 num칸 확장
Ctrl+w,_ : 해당 윈도우가 위아래로 모든 칸을 차지</p>
</li>
</ul>
<h3 id="환경변수의-이해">환경변수의 이해</h3>
<ul>
<li><p>환경변수
: 운영체제 수준에서 선언하는 변수
운영체제 해당 환경에서 실행되는 프로세스가 모두 참조할 수 있다.
대표적으로 다음과 같은 경우에 사용한다.</p>
<ol>
<li>변수에 자주 사용하는 경로를 지정한다.</li>
<li>기존에 있는 변수를 이용한 새로운 변수를 저장한다.</li>
<li>프로세스가 구동중에 참조할 값을 미리 환경변수에 할당하고 프로세스를 실행한다.</li>
</ol>
</li>
<li><p>환경변수를 임시로 선언하는법
export 환경변수명=값 : 값을 환경변수로 임시 선언</p>
<blockquote>
<p>이 경우 시스템 재부팅 또는 로그아웃을 하면 환경 변수 값이 사라지게 된다.</p>
</blockquote>
</li>
<li><p>환경변수를 유저레벨로 선언하는 법
환경변수를 특정 유저에게만 영구적으로 적용하고 싶은 경우에는 ~/.bash_profile 파일을 수정한다.
~/.bash_profile은 user가 처음 login 할 때 수행된다.
단, bash shell로 접속했을 때만 동작한다. sh 또는 zsh로 접속하면 동작하지 않는다.</p>
</li>
</ul>
<blockquote>
<p>vi ~/.bash_profile
exprot LECTURE=&quot;fastcampus&quot;
exho $LECTURE</p>
</blockquote>
<ul>
<li><p>환경변수를 영구히 선언하는 법
환경변수를 모든 유저에게만 영구적으로 적용하고 싶은 경우에는 /etc/profile 파일을 수정한다.</p>
<blockquote>
<p>sudo vi /etc/profile
export LECTURE=&#39;data&#39;
echo $LETURE</p>
</blockquote>
<p>운영체제가 명령어의 실행파일을 찾는 경로
절대/상대 경로 없이, 단독으로 명령어를 수행할 수 있다는 것은 해당 명령어의 실행파일이 운영체제의 $PATH에 등록된 디렉토리들 중에 포함되어 있다는 의미이다.</p>
</li>
</ul>
<h3 id="shell-script-활용하기">shell script 활용하기</h3>
<ul>
<li>shell script란?
Shell script는 unix shell의 command line interpreter가 실행할 수 있는 명령어를 의미한다.</li>
</ul>
<p>파일 맨 위에 다음과 같은 표시가 있다면 shell script 파일이라고 할 수 있다.</p>
<blockquote>
<p>#!/bin/sh : /bin/sh(bourne shell)를 사용하는 shell script
#!/bin/bash : /bin/bash를 사용하는 bash shell script
#!/bin/zsh : /bin/zsh 를 사용하는 zshell shell script
#!는 shebang(쉬뱅) 이라고 읽는다</p>
</blockquote>
<ul>
<li>shell script 실행하는 법
./$FILENAME을 이용하여 실행
실행이 안된다면? -&gt; 로그인한 user에게 +x 권한이 있는지 확인한다.</li>
</ul>
<h2 id="shell-script-실습">shell script 실습</h2>
<h3 id="변수">변수</h3>
<ul>
<li><p>영문,숫자,_만 사용가능</p>
</li>
<li><p>Unix shell 의 변수 명은 대문자로 작성하는 것이 convention 이다.</p>
</li>
<li><p>변수명  = 변수값 으로 변수 선언 가능</p>
<blockquote>
<p>$변수명 : 변수사용
readonly 변수명 : 읽기전용 변수로 선언 (읽기 전용 변수 값을 바꾸려고 시도하면 에러발생)
unset 변수명 : 변수할당해제</p>
</blockquote>
</li>
<li><p>Script 내에서 선언한 변수 뿐만 아니라, 환경변수, 쉘별수(접속한 shell에서 export로 선언한 변수)도 $변수로 읽어올수있다.</p>
</li>
</ul>
<h3 id="특수목적-변수">특수목적 변수</h3>
<p>$$ : 현재 shell의 프로세스 아이디
$0 : 현재 Script의 파일이름
$n : Script실행시 넘겨준 n번째 인자
$# : Script에 넣어준 인자의 개수
$* : 모든 인자를 &quot;&quot;로 감싸서 반환
$@ : 각 인자를 &quot;&quot;로 감싸서 반환
$? : 마지막으로 실행된 명령어의 종료상태
$! : 마지막 백그라운드의 명령어의 프로세스 아이디</p>
<h3 id="조건문---if">조건문 - if</h3>
<ul>
<li>if 는 expression을 이용해서 자유롭게 조건을 넣는다.</li>
</ul>
<pre><code class="language-bash">if[condition]; then
    ${script}
elif[condition]; then
    ${elif script}
else[condition]; then
    ${script}
fi</code></pre>
<ul>
<li>if는 항상 fi로 닫는다</li>
<li>조건 뒤에는 ;then 으로 다음 수행을 알려준다.</li>
<li>elif, else는 선택적으로 사용한다.</li>
</ul>
<pre><code class="language-bash">OPTION=&quot;${1}&quot;
case ${OPTION} in
        -f) FILE=&quot;${2}&quot;
                echo &quot;FILE name is $FILE&quot;
                ;;
        -d) DIR=&quot;${2}&quot;
                echo &quot;Dir name is $DIR&quot;
                ;;
        [0-9]) NUM=&quot;${1}&quot;
                echo &quot;num is $NUM&quot;
                ;;
        *)
                echo &quot;`basename ${0}`: usage: [-f file] | [-d directory]&quot;
                exit  1
                ;;
esac</code></pre>
<ul>
<li>case는 항상 esac로 닫는다</li>
<li>예시에 넣은 OPTION은 상관 x</li>
<li>*)는 defalut, 위의 어떤 조건도 아닐 때 수행한다.</li>
</ul>
<h3 id="연산자">연산자</h3>
<ul>
<li>기본연산자 
연산을 위해서는 외부 프로그램을 이용해야 한다.
대표적으로 awk/expr 이 있다</li>
</ul>
<blockquote>
<p>val = <code>expr 2 + 2</code>
 echo &quot;Total value : $val&quot;
 &gt; Total Value : 4</p>
</blockquote>
<ul>
<li><p>산술연산자
<img src="https://velog.velcdn.com/images/glory_95/post/b387523e-b674-4022-9121-14c08c9730cb/image.png" alt=""></p>
</li>
<li><p>관계 연산자
<img src="https://velog.velcdn.com/images/glory_95/post/c1abf693-4f82-4546-a968-e37f96de73af/image.png" alt=""></p>
</li>
<li><p>부울 연산자
<img src="https://velog.velcdn.com/images/glory_95/post/7d483988-169c-4b63-974f-8d282d53c0fe/image.png" alt=""></p>
</li>
<li><p>반복문 
<img src="https://velog.velcdn.com/images/glory_95/post/be8c840d-5aaf-40ab-9b4e-19710bcfce41/image.png" alt=""></p>
</li>
</ul>
<h3 id="quoting-mechanism">Quoting Mechanism</h3>
<ul>
<li>Metacharacters</li>
</ul>
<p><img src="https://velog.velcdn.com/images/glory_95/post/029460d6-7552-45c6-9f4a-c731912ab335/image.png" alt=""></p>
<h3 id="shell-substitution">Shell Substitution</h3>
<p><img src="https://velog.velcdn.com/images/glory_95/post/92faf58b-7dbb-4b8a-a35e-43ed4d1ba5bc/image.png" alt=""></p>
<h3 id="funtion">funtion</h3>
<p><img src="https://velog.velcdn.com/images/glory_95/post/0ca9ed1b-abf0-4b42-87b8-20f23d5e78d2/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS 활용]]></title>
            <link>https://velog.io/@glory_95/DE-AWS-%ED%99%9C%EC%9A%A9%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@glory_95/DE-AWS-%ED%99%9C%EC%9A%A9%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Wed, 06 Sep 2023 13:56:07 GMT</pubDate>
            <description><![CDATA[<h1 id="aws-활용에-관한-기초개념">AWS 활용에 관한 기초개념</h1>
<h2 id="vpc란">VPC란?</h2>
<p>네트워크는 옛날에는 랜선을 꽂아 인터넷이 가능했고 이것을 네트워크라 부른다.
VPC는 랜선을 꽂는등 물리적인 망이 아닌 논리적으로 분리한 가상의 네트워크이다
AWS 환경에서 네트워크를 구분할때 사용하는 가장 최소한의 단위를 말한다.</p>
<ul>
<li>VPC(virtual Private Cloud) 는 논리적으로 분리한 네트워크로 AWS 환경내의 네트워크 최소단위.</li>
<li>사용자의 AWS 계정 전용 가상 네트워크, 하나의 리전에 대해 계정 당 하나의 VPC를 받는다.</li>
<li>아마존 EC2와 같은 AWS리소스를 VPC 에서 실행할 수 있다.</li>
<li>VPC에서 실행된 AWS 리소스는 다른 리소스 혹은 인터넷에 연결될 수 있다.</li>
</ul>
<h2 id="subnet-이란">subnet 이란?</h2>
<p><img src="https://velog.velcdn.com/images/glory_95/post/95c46fa0-f080-46b7-a14d-02a71caf6fac/image.png" alt=""></p>
<ul>
<li><p>서브넷은 VPC의 분할된 IP주소 범위이다. VPC <strong>CIDR</strong>블럭을 서브넷으로 지정한다. 지정된 서브넷으로 AWS 리소스를 실행할 수 있다.</p>
</li>
<li><p>각 서브넷은 단일 가용 영역 내에서만 존재해야 하며, 여러 영역으로 확장할 수 없다.</p>
<blockquote>
<p>유저 A의 VPC의 가용영역 A의 서브넷1만 존재할 수 있다. 서브넷1과 서브넷4를 함께 가지는것은 불가능하다.</p>
</blockquote>
</li>
<li><p>별도의 가용영역에서 인스턴스를 시작함으로써, 단일 영역에서 장애가 발생할 경우 애플리케이션을 보호할 수 있다.</p>
<blockquote>
<p>유저 A의 VPC의 거용영역의 서브넷1이 장애가 발생하여 서버가 죽는 상황이 오면, 설정을 통해 가용영역 B의 서브넷2가 실행이 될 수 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="cidr이란">CIDR이란?</h2>
<ul>
<li>클래스없는 도메인간 라우팅 기법</li>
<li>CIDR을 이용하여 network 파트와 host파트를 구분할 수 있으며, 특정 host가 어떤 network에 포함되는지 빠르게 확인 가능하다.</li>
<li>IPv4는 8비트가 4번 등장하는 구조로 되어 있으며, 이런 IPv4뒤에 /24와 같이 / 를 이용하여 CIDR를 표현할 수 있다. 즉, /24의 경우 앞의 24 비트를 network 파트로 이용하고 뒤 8비트를 host파트로 이용하는 것을 의미한다.</li>
<li>192.168.1.1/24의 경우 앞의 24비트에 해당하는 192.168.1 가 network파트에 해당된다.</li>
</ul>
<p>192.168.1.0 ~ 192.168.1.255 가 동일한 network 파트에 속한다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/ae8af331-d53b-4fae-bafd-9773faf421ed/image.png" alt=""></p>
<p>해당이미지를 보면 CIDR을 보면 /16 이다.
이말은 즉 172.31.0.0/16 중이 한자리에 8비트 즉 .를 기준으로 2자리인 172.31 까지가 network파트 이며, 172.31 뒤에 0~255까지는 같은 네트워크를 사용한다고 보면 된다.</p>
<h2 id="aws에서-subnet마다-예약된-ip주소">AWS에서 subnet마다 예약된 IP주소</h2>
<ul>
<li>subnet의 몇몇 IP는 특정용도를 위해 subnet 생성과 함께 예약된다.</li>
<li>예를들어 10.0.0.0/24 대역으로 CIDR블럭을 생성한다면, 아래ip는 사용자의 AWS리소스의 ip로 사용할 수 없다.<blockquote>
<p>10.0.0.0 : Network address
10.0.0.1 : VPC router 에서 사용됨
10.0.0.2 : DNS 서버로 사용됨
10.0.0.3 : 미래에 AWS에서 필요한 경우 사용하기 위해 남겨둠
10.0.0.255 : Network broadcast 주소</p>
</blockquote>
</li>
</ul>
<h2 id="internet-gateway">Internet Gateway</h2>
<ul>
<li>Internet Gateway는 VPC와 인터넷을 연결해주는 하나의 관문</li>
<li>VPC와 Internet 간의 통신을 가능하게 해준다.
subnet의 라우팅 테이블에 172.31.0.0/16 에 매칭되지 않은 ip의 경우 0.0.0.0/0에 해당되는 Internet Gateway로 라우팅 된다.<br><img src="https://velog.velcdn.com/images/glory_95/post/4f3f681a-d931-42e5-8c61-cd4385876a07/image.png" alt=""></li>
</ul>
<h2 id="nat-gateway">NAT Gateway</h2>
<ul>
<li>NAT Gateway는 프라이빗 서브넷이 인터넷과 통신하기 위한 아웃바운드 인스턴스이다.</li>
<li>프라이빗 네트워크가 외부에서 요청되는 인바운드는 필요없더라도, 아웃바운드 트래픽만 허용되어야 하는 경우 사용된다.</li>
<li>NAT Gateway는 프라이빗 서브넷에서 외부로 요청하는 트래픽을 받아 Internet Gateway와 연결한다.<blockquote>
<p>풀어서 말하자면, 외부에서의 트래픽 및 데이터를 받아와야 할 때 사용되는 GateWay이다.</p>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/glory_95/post/0765284e-bbac-47b8-8c09-1b292da2e9f9/image.png" alt=""></p>
<h2 id="security-group--network-acl">Security Group &amp; Network ACL</h2>
<p>ACL 과 Security Group(보안그룹)은 방화벽과 같은 역할을 하며, 트래픽에 대한 보안정책을 설정할 수 있다.</p>
<p><strong>보안그룹</strong></p>
<ul>
<li>인스턴스 기준으로 적용</li>
<li>룰에 대한 허용 규칙만 적용</li>
<li>아웃바운드 요청에 대한 응답 자동 허용</li>
</ul>
<p><strong>ACL</strong></p>
<ul>
<li>서브넷 기준 적용</li>
<li>룰에 대한 허용 및 거부 규칙 적용</li>
<li>아웃바운드 요청에 대한 응답 규칙 적용필요</li>
</ul>
<p><img src="https://velog.velcdn.com/images/glory_95/post/31a4ece6-dc1b-4df1-8082-ad62e3e461a4/image.png" alt=""></p>
<p>해당 본문에 대해 쉽고 잘 설명해준 블로그 참고
출처 : <a href="https://medium.com/harrythegreat/aws-%EA%B0%80%EC%9E%A5%EC%89%BD%EA%B2%8C-vpc-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-71eef95a7098">https://medium.com/harrythegreat/aws-%EA%B0%80%EC%9E%A5%EC%89%BD%EA%B2%8C-vpc-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-71eef95a7098</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 자료구조 Map Interface]]></title>
            <link>https://velog.io/@glory_95/or96m106</link>
            <guid>https://velog.io/@glory_95/or96m106</guid>
            <pubDate>Mon, 10 Jul 2023 07:01:04 GMT</pubDate>
            <description><![CDATA[<h1 id="map-interface">Map Interface</h1>
<p>: Map은 중복을 허용하지 않는 Key와 중복이 가능한 Value가 각각 쌍을 이루어 저장되는 자료구조이다. </p>
<h2 id="map-자료구조의-특징">Map 자료구조의 특징</h2>
<ul>
<li>중복 : 중복 불가 , index가 순차적 Key로 유일성을 가짐</li>
<li>순서 : 보장 불가 </li>
<li>정렬 : 정렬 불가 </li>
<li>동기화 (Thread-Safe) : 동기화 불가능, 불안전함</li>
</ul>
<p>삽입 / 삭제 / 조회 연산이 광장히 빠르지만,</p>
<p>순서를 보장하지 않고, 정렬이 불가하다는 단점을 가지고 있다.</p>
<p>이러한 단점을 보완하기 위해서 자바에서는 HashMap , LinkedHashMap, TreeMap 세 가지의 클래스를 지원한다.</p>
<h3 id="hashmap">HashMap</h3>
<ul>
<li>해시함수를 이용한 Map임</li>
<li>삽입 / 삭제 / 조회 연산의 O(1)을 보장하는 아주 빠른 자료구조</li>
<li>삽입 데이터의 순서를 보장하지 않음</li>
<li>정렬이 불가함
<img src="https://velog.velcdn.com/images/glory_95/post/fc31c5ef-5034-4440-8552-2adcfcf0802a/image.png" alt=""></li>
</ul>
<h3 id="linkedhashmap">LinkedHashMap</h3>
<ul>
<li>삽입 / 삭제가 맵보다 느림</li>
<li>삽입 순서를 보장함</li>
<li>정렬은 불가함</li>
<li>주요 메서드는 HashMap과 같다</li>
</ul>
<h3 id="treemap">TreeMap</h3>
<ul>
<li>삽입 / 삭제가 굉장히 느림,</li>
<li>삽입순서를 보장함</li>
<li>Map이지만 유일하게 정렬이 가능함.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/glory_95/post/d8a33571-f287-47ba-b3c3-9f040c17ec07/image.png" alt=""><img src="https://velog.velcdn.com/images/glory_95/post/e44e6e7b-b12e-4c0e-9f90-0a4a48a6faa4/image.png" alt=""><img src="https://velog.velcdn.com/images/glory_95/post/d8d17818-8a45-4ba6-83ef-b39de4913fe8/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 자료구조 List Interface]]></title>
            <link>https://velog.io/@glory_95/JAVA-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-List-Interface</link>
            <guid>https://velog.io/@glory_95/JAVA-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-List-Interface</guid>
            <pubDate>Thu, 06 Jul 2023 07:52:25 GMT</pubDate>
            <description><![CDATA[<h1 id="list-interface">List Interface</h1>
<p>: 자료들을 순차적으로 나열한 자료구조, 인덱스로 관리하며 중복해서 객체 저장이 가능하다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/47b4efb8-7427-4b52-991b-83d7d7aef7ab/image.png" alt=""></p>
<h2 id="list-vs-array">List VS Array</h2>
<p>리스트와 배열은 비슷해보이지만 어떤 데이터를 다룰것인가에 대해서 확연히 사용방안이 다르다.</p>
<h3 id="공통점">공통점</h3>
<ol>
<li>동일한 특성의 데이터들을 묶는다</li>
<li>반복문내에 변수를 이용하여 하나의 묶음 데이터들을 모두 접근할 수 있다.</li>
</ol>
<h3 id="list">List</h3>
<ol>
<li><p>리스트의 길이가 가변적이다. 이를 동적 할당(dynamic allocation)이라고 한다.</p>
</li>
<li><p>데이터들이 연속적으로 나열된다.</p>
</li>
<li><p>데이터(element) 사이에 빈 공간을 허용하지 않는다.</p>
</li>
</ol>
<h3 id="array">Array</h3>
<ol>
<li><p>처음 선언한 배열의 크기(길이)는 변경할 수 없다. 이를 정적 할당(static allocation)이라고 한다.</p>
</li>
<li><p>메모리에 연속적으로 나열되어 할당된다.</p>
</li>
<li><p>index에 위치한 하나의 데이터(element)를 삭제하더라도 해당 index에는 빈공간으로 계속 남는다. </p>
</li>
</ol>
<h2 id="list-구현클래스">List 구현클래스</h2>
<p>: List는 인터페이스이다. 즉 이를 구현하는 구현클래스는 크게 5가지로 나뉜다.
ArrayList, LinkedList, Vector, Stack으로 나누어지며, 제일 많이 사용이되고 있는 ArrayList, LinkedList를 다뤄보려고 한다.</p>
<hr>
<h3 id="arraylist">ArrayList</h3>
<p>ArrayList는 기본적으로 배열을 사용한다. 하지만 일반 배열과 차이점이 존재한다.
일반 배열은 처음에 메모리를 할당할 때 크기를 지정해주어야 하지만,
ArrayList는 크기를 지정하지 않고 동적으로 값을 삽입하고 삭제할 수 있다.</p>
<h4 id="조회">조회</h4>
<p>ArrayList는 각 데이터의 index를 가지고 있고 무작위 접근이 가능하기 때문에, 해당 index의 데이터를 한번에 가져올 수 있다.</p>
<h4 id="데이터-삽입과-삭제">데이터 삽입과 삭제</h4>
<p>데이터의 삽입과 삭제시 ArrayList는 그만큼 위치를 맞춰주어야 한다.
예를들면 5개의 데이터가 있을 때 맨 앞의 2를 삭제했다면 나머지 뒤의 4개를 앞으로 한칸씩 이동해야 한다.
<strong>삽입과 삭제가 많다면 ArrayList는 비효율적이다.</strong></p>
<hr>
<h3 id="linkedlist">LinkedList</h3>
<p>LinkedList는 내부적으로 양방향의 연결 리스트로 구성되어 있어 참조하려는 원소에 따라 처음부터 정방향 또는 역순으로 순회 가능 (배열의 단점을 보완하기 위해 LinkedList가 고안되었다.)</p>
<h4 id="조회-1">조회</h4>
<p>LinkedList는 순차적 접근이기 때문에 검색의 속도가 느리다.</p>
<h4 id="데이터-삽입과-삭제-1">데이터 삽입과 삭제</h4>
<p>LinkedList는 데이터를 추가·삭제시 가리키고 있는 주소값만 변경해주면 되기 때문에 ArrayList에 비해 상당히 효율적이다.
예를들면 2번째 값을 삭제하면 1번째 노드가 3번째 노드를 가리키게 하기만 하면 된다.</p>
<hr>
<h3 id="arraylist-vs-linkedlist">ArrayList vs LinkedList</h3>
<p>이처럼 조회시에는 ArrayList가 우위에 있지만,
삽입/삭제 시에는 LinkedList가 뛰어난 성능을 보여준다.</p>
<p>소량의 데이터를 가지고 사용할 때는 사실 큰 차이가 없지만,
정적인 데이터를 활용하면서 조회가 빈번하다면 ArrayList를 사용하는 것이 좋고,
동적으로 추가/삭제 요구사항이 빈번하다면 LinkedList를 사용하는 것이 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 정렬(Sort)]]></title>
            <link>https://velog.io/@glory_95/Algorithm-%EC%A0%95%EB%A0%ACSort</link>
            <guid>https://velog.io/@glory_95/Algorithm-%EC%A0%95%EB%A0%ACSort</guid>
            <pubDate>Thu, 29 Jun 2023 04:48:34 GMT</pubDate>
            <description><![CDATA[<h1 id="정렬sort">정렬(Sort)</h1>
<p>정렬은 데이터를 정해진 기준에 따라 배치해 의미 있는 구조로 재설정하는 것을 말한다.</p>
<h2 id="안정정렬과-불안정-정렬">안정정렬과 불안정 정렬</h2>
<h3 id="안정정렬">안정정렬</h3>
<p>정렬을 수행하고 난 뒤에도 같은 key값을 가진 원소들의 순서가 유지되는 정렬
<img src="https://velog.velcdn.com/images/glory_95/post/44e822f0-25fe-4cb5-83c4-41974ef255f4/image.png" alt=""></p>
<h3 id="불안정-정렬">불안정 정렬</h3>
<p>정렬을 수행하고 난 뒤에도 같은 key값을 가진 원소들의 순서가 보장되지가 않는다.
<img src="https://velog.velcdn.com/images/glory_95/post/e9343648-a5cb-4bb5-8448-8fd1907f8e37/image.png" alt=""></p>
<h2 id="정렬-알고리즘의-종류">정렬 알고리즘의 종류</h2>
<h3 id="1-버블정렬">1. 버블정렬</h3>
<p>데이터의 인접 요소끼리 비교하고, swap 연산을 수행하며 정렬하는 방식</p>
<p>시간복잡도를 계산하면,O(n^2) 이다. 또한, Bubble Sort는 정렬이 돼있던 안돼있던, 2개의 원소를 비교하기 때문에 최선, 평균, 최악의 경우 모두 시간복잡도가 O(n^2) 으로 동일하다.</p>
<blockquote>
<p>버블 정렬 과정</p>
</blockquote>
<ol>
<li>비교 연산이 필요한 루프 범위를 설정</li>
<li>인접한 두 개의 데이터  값을 비교한다</li>
<li>Swap조건(내림차순 / 오름차순)에 부합하면 Swap한다.</li>
<li>루프 범위가 끝날 때까지 2~3번 과정을 반복한다.</li>
<li>정렬 영역을 설정한다. 다음 루프를 실행할 때는 이 영역을 제외한다.</li>
<li>비교 대상이 없을 때까지 1~5번 과정을 반복
<img src="https://velog.velcdn.com/images/glory_95/post/51d2b743-1844-4795-a711-1f815f20ac90/image.gif" alt=""></li>
</ol>
<h4 id="장점">장점</h4>
<ul>
<li>구현이 매우 간단하고, 소스코드가 직관적이다.</li>
<li>정렬하고자 하는 배열 안에서 교환하는 방식이므로, 다른 메모리 공간을 필요로 하지 않다. =&gt; 제자리 정렬(in-place sorting)</li>
<li>안정 정렬(Stable Sort) 이다.</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li>시간복잡도가 최악, 최선, 평균 모두 O(n^2)으로, 굉장히 비효율적이다.</li>
<li>정렬 돼있지 않은 원소가 정렬 됐을때의 자리로 가기 위해서, 교환 연산(swap)이 많이 일어나게 된다.</li>
</ul>
<h3 id="2-선택정렬">2. 선택정렬</h3>
<p>대상 데이터에서 최대나 최소 데이터를 데이터가 나열된 순으로 찾아가며 선택하는 방법이다.
선택 정렬은 구현 방법이 복잡하며, 시간 복잡도도 O(n^2)로 효율적이지 않아 코팅테스트에서는 많이사용되지 않는다</p>
<p>선택정렬은 최솟값 또는 최댓값을 찾고, 남은 정렬 부분의 가장 앞에 있는 데이터와 swap하는것이 선택정렬의 핵심이다/</p>
<blockquote>
<p>선택 정렬 과정</p>
</blockquote>
<ol>
<li>남은 정렬부분에서 최소값 또는 최대값을 찾는다.</li>
<li>남은 정렬 부분에서 가장 앞에 있는 데이터와 선택된 데이터를 swap 한다.</li>
<li>가장 앞에 있는 데이터의 위치를 변경해 남은 정렬 부분의 범위를 축소한다.</li>
<li>전체 데이터 크기만큼 index가 커질때 까지, 즉 남은 정렬 부분이 없을때 까지 반복한다.
<img src="https://velog.velcdn.com/images/glory_95/post/79dde014-3c15-4622-979d-91dc442b9dae/image.gif" alt=""></li>
</ol>
<h4 id="장점-1">장점</h4>
<ul>
<li>선택정렬 또한 버블정렬과 마찬가지로 구현이 쉬운편에 속하는 정렬법이다.</li>
<li>정렬을 위한 비교 횟수는 많지만 실제로 교환하는 횟수는 적기 때문에 많은 교환이 일어나야 하는 자료상태에서 효율적으로 사용될 수 있다.</li>
<li>버블정렬과 비교했을 때, 똑같이 O(n^2)이라는 시간복잡도를 갖지만, 실제로 시간을 측정해보면 버블정렬에 비해서는 조금 더 빠른 정렬 방식이다.</li>
<li>안정 정렬(Stable Sort) 이다.</li>
</ul>
<h4 id="단점-1">단점</h4>
<ul>
<li>선택정렬 또한 항상 O(n^2)이라는 시간복잡도를 갖기 때문에 시간이 오래걸리는 정렬 방식이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 큐(Queue)]]></title>
            <link>https://velog.io/@glory_95/Algorithm-%ED%81%90Queue</link>
            <guid>https://velog.io/@glory_95/Algorithm-%ED%81%90Queue</guid>
            <pubDate>Thu, 22 Jun 2023 02:25:32 GMT</pubDate>
            <description><![CDATA[<h2 id="큐queue">큐(Queue)</h2>
<p>큐(queue)는 스택과 다르게 먼저 들어온 데이터가 먼저 나가는 자료구조로 선입선출(FIFO : First-in First-out) 방식으로 삽입과 삭제는 FIFO 방식으로 진행된다. 삽입은 큐(queue)의 후단에서, 삭제는 전단에서 진행된다.</p>
<p>이에따라 세 가지 제약이 존재한다.</p>
<ul>
<li>데이터는 스택의 끝에만 삽입할 수 있다.</li>
<li>데이터는 스택의 앞에서만 읽을 수 있다.</li>
<li>데이터는 스택의 앞에서만 삭제할 수 있다.</li>
</ul>
<h2 id="연산-메서드">연산 메서드</h2>
<p>스택(Stack)과 데이터를 삽입 / 삭제 / 조회 하는 메서드들이 다르다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/b6f47235-4695-4a1a-a234-1f0938958600/image.png" alt=""></p>
<h2 id="활용사례">활용사례</h2>
<p><img src="https://velog.velcdn.com/images/glory_95/post/4a933bc7-876f-433a-a099-a97314473a58/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 스택(Stack)]]></title>
            <link>https://velog.io/@glory_95/Algorithm-Stack-Heap</link>
            <guid>https://velog.io/@glory_95/Algorithm-Stack-Heap</guid>
            <pubDate>Tue, 20 Jun 2023 02:49:38 GMT</pubDate>
            <description><![CDATA[<h1 id="스택stack">스택(Stack)</h1>
<p>스택은 한쪽 끝에서만 데이터를 넣고 뺄 수 있는 제한적으로 접근할 수 있는 후입선출(Last-In-First-Out) 형태의 선형 자료구조이다.</p>
<p>기본적으로 Stack 클래스는 내부에서 최상위 타입 배열인 Object[] 배열을 사용하여 데이터를 관리하고 있다.</p>
<h2 id="작동원리">작동원리</h2>
<p><strong>스택</strong>은 기본적으로 후입선출(나중에 들어온 데이터가 가장 먼저 나가는) 구조로 이루어져 있다.
식당에 쌓여있는 접시들이 좋은 예입니다. 순서대로 쌓인 접시가 스택 구조와 같다.
접시가 필요하면 제일 위에 있는 접시부터 사용하며 가장 아래 있는 접시는 마지막에 사용된다.
<img src="https://velog.velcdn.com/images/glory_95/post/00b0e365-da24-4b21-a0cb-e73830afddad/image.png" alt=""></p>
<p>스택은 LIFO (Last In First Out)순서를 따른다.</p>
<p>LIFO : 마지막으로 들어온 값이 처음으로 나가는 것
FILO : 처음 들어온 값이 마지막에 나가는 것</p>
<p>스택은 완전히 꽉 찼을 때 Overflow 상태라고 하며 완전히 비어 있으면 Underflow 상태라고 한다.
삽입(Push)과 제거(Pop)는 모두 Top이라는 스택의 한쪽 끝에서만 일어난다.</p>
<h2 id="연산-메서드">연산 메서드</h2>
<h3 id="push">push</h3>
<p>스택 맨위에 항목을 삽입</p>
<h3 id="pop">pop</h3>
<p>스택 맨위에 항목 삭제</p>
<h3 id="peek">peek</h3>
<p>스택의 맨 위(top)를 표시</p>
<h3 id="isempty">isEmpty</h3>
<p>스택이 비어있는지 확인</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/385629ed-1a8d-4616-83e3-dffa056895dd/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 입출력 BufferedReader / BufferedWriter]]></title>
            <link>https://velog.io/@glory_95/Algorithm-%EC%9E%85%EC%B6%9C%EB%A0%A5-BufferedReader-BufferedWriter</link>
            <guid>https://velog.io/@glory_95/Algorithm-%EC%9E%85%EC%B6%9C%EB%A0%A5-BufferedReader-BufferedWriter</guid>
            <pubDate>Sun, 11 Jun 2023 09:53:51 GMT</pubDate>
            <description><![CDATA[<h2 id="bufferedreader--bufferedwriter">BufferedReader / BufferedWriter</h2>
<p>BufferedReader / BufferedWriter는 버퍼를 이용해서 읽고 쓰는 메서드이다. 이 메서드는 버퍼를 이용하므로 Scanner보다 입력의 효율이 좋고 System.println보다 출력의 효율이 비교할 수 없을 정도로 좋아진다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/5f7e6fcf-a1eb-4b3e-85f3-f093d250a193/image.png" alt=""></p>
<p>버퍼를 사용하지 않는 입력같은 경우에는 입력이 키를 누르는 즉시 바로 전달이된다고 한다.
하지만 버퍼를 사용하면 입력값의 한 문자씩 버퍼에 저장되어 전송하는데, 한 번 거쳐가므로 효율이 더 나쁜것 처럼 보이지만 사실이 아니다.</p>
<p>하드디스크의 원해 속도는 엄청 느리다. 뿐만아니라, 키보드나 모니터와 같은 외부장치와의 데이터 입출력은 생각보다 시간이 걸리는 작업이다.</p>
<p>때문에 데이터를 만든 즉시 바로 보내는것보다 데이터를 한 군데에 모아서 한꺼번에 보내는것이 효율적이고 빠르다</p>
<p>예시로, 공사장에 필요한 벽돌을 옮기는 작업을 한다고 생각해보면 벽돌 하나씩 옮기는게 효율적인가 아니면 수레에 한번에 담아서 옮기는게 빠른가 생각해보면 이해가 편할것이다.</p>
<h3 id="bufferedreader">BufferedReader</h3>
<p>알고리즘 문제를 풀기 위해서 값을 입력받을때, Scanner를 이용해 입력을 받는다.
Scanner는 띄어쓰기와 엔터를 경계로 입력 값을 인식하기 때문에 가공할 필요가 없어 사용하기 편리하다.</p>
<p>반면에 BufferedReader는 엔터만 경계로 인식하고 받은 데이터가 String으로 고정되어있기 때문에, 데이터를 따로 가공해야 하는 경우가 빈번하여 번거롭지만, Scanner에 비해서 상대적으로 빠르기 때문에 사용한다.</p>
<h4 id="사용방법">사용방법</h4>
<p>BufferedReader의 readLine()을 사용하면 데이터를 라인 단위로 읽을 수 있다.
readLine 함수의 리턴 값은 String으로 고정되기 때문에 String이 아닌 다른 타입으로 입력을 받으려면 형변환을 꼭 해줘야 한다.</p>
<p>그렇다면 한 줄에 공백을 기준으로 데이터를 분리하여 읽으려면 어떻게 해야할까?
Scanner는 공백단위로도 끊어주기 때문에 고려하지 않아도 되는 사항이였지만, BufferedReader를 사용하려면 StringTokenizer의 nextToken함수를 이용하거나 string클래스의 split함수를 이용하는 방법이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 시간복잡도]]></title>
            <link>https://velog.io/@glory_95/Algorithm-%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84</link>
            <guid>https://velog.io/@glory_95/Algorithm-%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84</guid>
            <pubDate>Tue, 06 Jun 2023 09:19:30 GMT</pubDate>
            <description><![CDATA[<h2 id="시간복잡도">시간복잡도</h2>
<p>주어진 문제를 해결하기 위한 연산 횟수를 말한다.
일반적으로 수행시간은 1억 번의 연산을 1초의 시간으로 간주하여 예측한다.</p>
<h2 id="시간-복잡도-유형">시간 복잡도 유형</h2>
<p>Big-O(빅-오) : 최악일 때의 연산 횟수를 나타낸 표기법
Big-Ω(빅-오메가) : 최선일 때의 연산횟수를 나타낸 표기법
Big-θ(빅-세타) : 보통일 때의 연산 횟수를 나타낸 표기법</p>
<h3 id="big-ω빅-오메가를-고려한-경우">Big-Ω(빅-오메가)를 고려한 경우</h3>
<p>결과를 반환하는 데 최선의 경우 1초, 평균적으로 1분, 최악의 경우 1시간이 걸리는 알고리즘을 구현했고, 최선의 경우를 고려한다고 가정하겠다.</p>
<p>이 알고리즘을 100번 실행한다면, 최선의 경우 100초가 걸린다.</p>
<p>만약 실제로 걸린 시간이 1시간을 훌쩍 넘겼다면, ‘어디에서 문제가 발생한 거지?’란 의문이 생긴다.</p>
<p>최선의 경우만 고려하였으니, 어디에서 문제가 발생했는지 알아내기 위해서는 로직의 많은 부분을 파악해야 하므로 문제를 파악하는 데 많은 시간이 필요하다.</p>
<h3 id="big-θ빅-세타를-고려한-경우">Big-θ(빅-세타)를 고려한 경우</h3>
<p>알고리즘을 100번 실행할 때 100분의 시간이 소요된다고 생각했는데, 최악의 경우가 몇 개 발생하여 300분이 넘게 걸렸다면 최선의 경우를 고려한 것과 같은 고민을 하게 된다.</p>
<h3 id="big-o빅-오를-고려한-경우">Big-O(빅-오)를 고려한 경우</h3>
<p>극단적인 예이지만, 위와 같이 최악의 경우가 발생하지 않기를 바라며 시간을 계산하는 것보다는 ‘최악의 경우도 고려하여 대비’하는 것이 바람직하다.</p>
<p>Big-O 표기법은 ‘입력값의 변화에 따라 연산을 실행할 때, 연산 횟수에 비해 시간이 얼마만큼 걸리는가?’를 표기하는 방법이다.</p>
<p><strong>“최소한 특정 시간 이상이 걸린다” 혹은 “이 정도 시간이 걸린다”를 고려하는 것보다 “이 정도 시간까지 걸릴 수 있다”를 고려해야 그에 맞는 대응이 가능하다.</strong></p>
<h2 id="big-o-표기법의-종류">Big-O 표기법의 종류</h2>
<h3 id="o1">O(1)</h3>
<p>O(1)는 일정한 복잡도(constant complexity)라고 하며, 입력값이 증가하더라도 시간이 늘어나지 않는다.
다시 말해 입력값의 크기와 관계없이, 즉시 출력값을 얻어낼 수 있다는 의미이다.</p>
<h3 id="on">O(n)</h3>
<p>O(n)은 선형 복잡도(linear complexity)라고 부르며, 입력값이 증가함에 따라 시간 또한 같은 비율로 증가하는 것을 의미한다.</p>
<p>예를 들어 입력값이 1일 때 1초의 시간이 걸리고, 입력값을 100배로 증가시켰을 때 1초의 100배인 100초가 걸리는 알고리즘을 구현했다면, 그 알고리즘은 O(n)의 시간 복잡도를 가진다고 할 수 있다.</p>
<h3 id="olog-n">O(log n)</h3>
<p>O(log n)은 로그 복잡도(logarithmic complexity)라고 부르며, Big-O표기법중 O(1) 다음으로 빠른 시간 복잡도를 가진다.</p>
<p>매번 숫자를 제시할 때마다 경우의 수가 절반이 줄어들기 때문에 최악의 경우에도 7번이면 원하는 숫자를 찾아낼 수 있게 된다.</p>
<h3 id="on2">O(n2)</h3>
<p>O(n2)은 2차 복잡도(quadratic complexity)라고 부르며, 입력값이 증가함에 따라 시간이 n의 제곱수의 비율로 증가하는 것을 의미한다.</p>
<p>예를 들어 입력값이 1일 경우 1초가 걸리던 알고리즘에 5라는 값을 주었더니 25초가 걸리게 된다면, 이 알고리즘의 시간 복잡도는 O(n2)라고 표현한다.</p>
<h3 id="o2n">O(2n)</h3>
<p>O(2n)은 기하급수적 복잡도(exponential complexity)라고 부르며, Big-O 표기법 중 가장 느린 시간 복잡도를 가진다.</p>
<p>종이를 42번 접으면 그 두께가 지구에서 달까지의 거리보다 커진다는 이야기를 들어보신 적 있으신가?</p>
<p>고작 42번 만에 얇은 종이가 그만한 두께를 가질 수 있는 것은, 매번 접힐 때마다 두께가 2배 로 늘어나기 때문이다.</p>
<p>구현한 알고리즘의 시간 복잡도가 O(2n)이라면 다른 접근 방식을 고민해 보는 것이 좋다.</p>
<h3 id="시간복잡도-도출-기준">시간복잡도 도출 기준</h3>
<ul>
<li>상수는 시간 복잡도 계산에서 제외한다.</li>
<li>가장 많이 중첩된 반복문의 수행 횟수가 시간 복잡도의 기준이 된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DBMS 아키텍처] DBMS와 버퍼]]></title>
            <link>https://velog.io/@glory_95/DBMS-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-DBMS%EC%99%80-%EB%B2%84%ED%8D%BC</link>
            <guid>https://velog.io/@glory_95/DBMS-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-DBMS%EC%99%80-%EB%B2%84%ED%8D%BC</guid>
            <pubDate>Thu, 13 Apr 2023 01:31:02 GMT</pubDate>
            <description><![CDATA[<h1 id="dbms와-버퍼">DBMS와 버퍼</h1>
<p>버퍼는 성능에 굉장히 중요한 영향을 미친다.
메모리는 한정된 희소 자원인 반면 데이터베이스가 메모리에 저장하고자 하는 데이터는 굉장히 많다.
따라서, 데이터를 버퍼에 어떠한 식으로 확보할 것인가 하는 부분에서 트레이드오프가 발생한다.</p>
<h2 id="1-기억장치의-계층">1. 기억장치의 계층</h2>
<p><img src="https://velog.velcdn.com/images/glory_95/post/6f2ca1c5-f4ab-430d-9752-f3a4952068fd/image.png" alt=""></p>
<p>일반적으로 기억장치는 기억비용에 따라 1차에서 3차까지의 계층으로 분류된다.
많은 데이터를 영속적으로 저장하려 하면 속도를 잃고, 속도를 얻고자 하면 많은 데이터를 영속적으로 저장하기 힘들다는 트레이드 오프가 발생한다.</p>
<blockquote>
<p>기억비용 : 데이터를 저장하는데 소모되는 비용</p>
</blockquote>
<h2 id="2-dbms와-기억장치의-관계">2. DBMS와 기억장치의 관계</h2>
<p>DBMS는 데이터를 저장하는것을 목적으로 하는 미들웨어이다.
DBMS가 사용하는 대표적인 기억장치는 2가지가 있다.</p>
<h3 id="하드디스크hdd">하드디스크(HDD)</h3>
<ul>
<li>DBMS가 데이터를 저장하는 매체(저장소)는 현재 대부분 HDD다.</li>
<li>용량, 비용, 성능의 관점에서 대부분 하드디스크를 채택하고 있다</li>
<li>하드디스크는 기억장치 계층에서 가운데 있는 2차 기억장치로 분류된다.</li>
<li>2차 기억장치는 그렇게 좋은 장점도 없지만, 그렇게 나쁜 단점도 없는 매채다.</li>
<li>DB는 대부분의 시스템에서 범용적으로 사용하는 미들웨어이므로, 어떤 상황에서도</li>
<li>평균적인 수치를 가지는 매체를 선택하는 것이 자연스럽다.</li>
<li>그렇다고 해서 DBMS가 데이터를 디스크 이외에 장소에 저장하지 않는다는 뜻은 아니다.</li>
</ul>
<h3 id="메모리">메모리</h3>
<ul>
<li>메모리는 디스크에 비해 기억비용이 굉장히 비싸다.</li>
<li>따라서 하드웨어 1대에 탑재할 수 있는 양이 크지않다.</li>
<li>일반적인 DB서버에 경우 탑재되는 메모리의 양은 한두 자리 정도다</li>
<li>상용 시스템의 DB 내부 데이터를 모두 메모리에 올리는 것은 불가능하다.</li>
</ul>
<h3 id="버퍼를-활용한-속도-향상">버퍼를 활용한 속도 향상</h3>
<p>그렇지만 DBMS가 일부라도 데이터를 메모리에 올리는 것은 성능 향상 때문이다.
메모리는 가장 빠른 1차 기억장치다. 따라서 자주 접근하는 데이터를 메모리 위에 올려둔다면, 같은 SQL 구문을 실행한다고 해도 디스크에서 데이터를 가져올 필요 없이 곧바로 메모리에서 읽어 빠르게 데이터를 검색할 수 있다.</p>
<p>디스크 접근을 줄일 수 있다면 굉장히 큰 폭의 성능 향상이 가능하다.
SQL구문의 실행 시간을 대부분 저장소 I/O에 사용하기 때문이다.</p>
<p>이렇게 <strong>성능 향상을 목적으로 데이터를 저장하는 메모리를 버퍼 또는 캐시</strong>라고 부른다.
버퍼는 완충제라는 의미인데 사용자와 저장소 사이에서 SQL구문의 디스크 접근을 줄여주는 역할을 하므로 붙은 이름이다.</p>
<p>캐시 역시 사용자와 저장소 사이에서 데이터 전송 지연을 완화시켜주는 것이다.
모두 물리적인 매체로 메모리가 사용되는 경우가 많다, 따라서 하디드스크 위에 있는 데이터에 접근하는 것보다 훨씬 빠르다.</p>
<p>이러한 <strong>고속 접근이 가능한 버퍼에 데이터를 어떻게, 어느 정도의 기간동안 올릴지를 관리하는 것이 DBMS의 버퍼 매니저다.</strong></p>
<h2 id="3-메모리-위에-있는-두-개의-버퍼">3. 메모리 위에 있는 두 개의 버퍼</h2>
<p>DBMS가 데이터를 유지하기 위해 사용하는 메모리는 두 종류가 있다.</p>
<ul>
<li>데이터 캐시</li>
<li>로그 버퍼</li>
</ul>
<p>대부분의 DBMS는 이러한 두 개의 역할을 하는 메모리 영역을 가지고 있다.</p>
<h3 id="데이터-캐시">데이터 캐시</h3>
<p>데이터 캐시는 디스크에 있는 데이터의 일부를 메모리에 유지하기 위해 사용하는 메모리영역이다.
내가 실행한 select 구문에서 선택하고 싶은 데이터가 데이터 캐시에 있다면 디스크와 같은 저속 저장소에 접근하지 않고 처리가 수행되기 때문에 빠르게 응답한다.
반대로 버퍼에서 데이터를 찾을 수 없다면 저속 저장소까지 데이터를 가지러 가야하기 때문에 SQL구문의 응답속도가 느려진다.</p>
<h3 id="로그버퍼">로그버퍼</h3>
<p>로그 버퍼는 갱신처리(select, delete, update, merge)와 관련이 있다.
DBMS는 갱신과 관련된 SQL 구문을 사용자로부터 받으면, 곧바로 저장소에 있는 데이터를 변경하지 않는다.
로그 버퍼 위에 변경 정보를 보내고 이후 디스크에 변경을 수행한다.(갱신 처리는 비동기로)
DBMS가 이러한 시점 차이를 두는 이유는 성능을 높이기 위해서다.
=&gt; 성능을 향상시키기 위한 방법인데 갱신을 할 때도 상당한 시간이 소모되기 때문에 저장소 변경이 끝날 때까지 기다리면 사용자는 장기간 대기해야 한다. 따라서 사용자에게 해당 SQL구문이 &#39;끝났다&#39;라고 통지하고, 내부적으로 관련된 처리를 계속 수행하는 것이다.</p>
<blockquote>
<p>동기 vs 비동기 
<strong>동기 방식</strong>은 서버에서 요청을 보냈을 때 응답이 돌아와야 다음 동작을 수행할 수 있다. 즉 A작업이 모두 진행 될때까지 B작업은 대기해야한다. 
<strong>비동기 방식</strong>은 반대로 요청을 보냈을 때 응답 상태와 상관없이 다음 동작을 수행 할 수 있다. 즉 A작업이 시작하면 동시에 B작업이 실행된다. A작업은 결과값이 나오는대로 출력된다.</p>
</blockquote>
<h2 id="4-메모리의-성질이-초래하는-트레이드오프">4. 메모리의 성질이 초래하는 트레이드오프</h2>
<p>메모리가 가진 단점은 가격이 비싸서 보유할 수 있는 데이터양이 적은것 뿐만아니라, 이외의 몇가지 단점이 더 있다.</p>
<h3 id="휘발성">휘발성</h3>
<p>메모리에는 데이터의 영속성이 없다. 하드웨어의 전원을 꺼버리면 메모리 위에 올라가 있는 데이터가 모두 사라진다. 이러한 성질을 휘발성이라고 한다.</p>
<p>DBMS을 껏다 켜면 버퍼위의 모든 데이터가 사라진다. 따라서 DBMS에 어떤 장애가 발생해서 프로세스다운이 일어나면(서버가 죽으면) 메모리 위에 있는 모든 데이터는 날아간다.</p>
<h3 id="휘발성의-위험성">휘발성의 위험성</h3>
<p>휘발성의 가장 큰 문제점은 장애가 발생했을 때 메모리에 있는 데이터가 모두 사라져버려 데이터 부정합을 발생시키는 것이다. 데이터 캐시라면 장애로 인한 메모리 위의 데이터가 사라져버려도, 원본 데이터는 디스크 위에 남아있으므로 아무 문제가 없다.</p>
<p>하지만 로그 버퍼 위에 존재하는 데이터가 디스크 위의 로그 파일에 반영되기 전 장애가 발생해 사라져 버리면 해당 데이터가 완전히 사라져서 복구조차 불가능해진다. 이는 사용자가 수행했던 갱신 정보가 사라진다는 의미이다.</p>
<p>이러한 문제를 회피하고자 DBMS는 커밋 시점에 반드시 갱신 정보를 로그파일에 씀으로써, 장애가 발생해도 정합성을 유지할 수 있게 한다.</p>
<blockquote>
<p>커밋(Commit)이란 갱신 처리를 확정하는 것으로 DBMS는 커밋된 데이터를 영속화 함
커밋 때는 반드시 디스크에 동기 접근이 일어남. 여기에서 또다시 트레이드오프가 모습을 드러냄
디스크에 동기 처리를 한다면 데이터 정합성은 높아지고 성능이 낮아진다.
반대로 성능을 높이러면 데이터의 정합성이 낮아진다</p>
</blockquote>
<h2 id="5-시스템-특성에-따른-트레이드-오프">5. 시스템 특성에 따른 트레이드 오프</h2>
<h3 id="데이터-캐시와-로그-버퍼의-크기">데이터 캐시와 로그 버퍼의 크기</h3>
<p>DBMS를 보면 데이터 캐시에 비해 로그 버퍼의 초깃값이 굉장히 작다.</p>
<p>이렇게 할당한 이유는 DB가 기본적으로 검색을 메인으로 처리한다고 가정하기 때문이다.
갱신 처리에 값비싼 메모리를 많이 사용하는 것보다는, 자주 검색하는 데이터를 캐시에 올려놓는 것이 좋다고 생각하기 때문이다.</p>
<p>왜냐하면, 데이터베이스의 데이터를 검색할 때 레코드가 수백만에서 수천만 건에 달하는 경우 많지만, 갱신 처리를 할 때는 갱신 대상이 많아 봤자 트랜잭션마다 한 건 에서 수만 건 정도밖에 안되기 때문이다.</p>
<h3 id="검색-vs-갱신">검색 vs 갱신</h3>
<p>우리는 검색과 갱신 중에서 어떤 것이 더 우선되어야 하는가라는 트레이드오프에 직면한다.
메모리라는 비깐 희소 자원으로 위해 어떤 것을 우선하여 지킬지, 어떤 것을 버릴지를 판단해야 한다.</p>
<h2 id="6-추가적인-메모리-영역-워킹-메모리">6. 추가적인 메모리 영역 &#39;워킹 메모리&#39;</h2>
<h3 id="언제-사용될까">언제 사용될까?</h3>
<p>DBMS는 메모리 영역을 하나 더 가지고 있는데 정렬 또는 해시 관련 처리에 사용되는 작업용 영역으로 워킹 메모리라고 부른다.</p>
<p>정렬은 ORDER BY구, 집합 연산, 윈도우 함수 등의 기능을 사용할 때 실행된다.</p>
<p>해시는 주로 테이블의 결합에서 해시 결합이 사용되는 때 실행된다.</p>
<p>이 작업용 메모리 영역은 SQL에서 정렬 또는 해시가 필요한 때 사용되고, 종료되면 해제되는 <strong>임시영역</strong>으로, 일반적으로는 데이터 캐시와 로그 버퍼와는 다른 영역으로 관리되는 경우가 많다.</p>
<p>이 영역이 성능적으로 중요한 이유는 만약 이 영역이 다루려는 데이터양보다 작아 부족해지는 경우 대부분의 DBMS가 저장소를 사용하기 때문이다. 이는 OS 동작에서 말하는 스왑과 같은 것이다.</p>
<h3 id="저장소가-부족하면-무슨-일이-일어날까">저장소가 부족하면 무슨 일이 일어날까?</h3>
<p>저장소는 메모리에 비해서 굉장히 느리다. 따라서 그런 곳에 접근하게 되면 전체적인 속도가 느려진다.</p>
<p>이 영역은 여러 개의 SQL 구문들이 공유해서 사용하므로, 하나의 SQL 구문을 실행하고 있을 때는
메모리가 잘 들어가지만 여러 개의 SQL 구문을 동시에 실행하면 메모리가 넘치는 경우가 있다.</p>
<p>하나가 있을 때의 성질뿐만 아니라, 여러 개가 있을 때의 성질도 주의해야 한다는 것이 컨트롤하기 힘든 성능 문제이다.</p>
<p>DBMS는 메모리가 부족하더라도 무언가를 처리하려고 계속 노력하는 미들웨어라고 생각할 수 있다.</p>
<p>DB는 메모리가 부족하다는 이유로 SQL 구문에 오류를 절대 발생시키지 않는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSSQL] 저장 프로시저 CRUD]]></title>
            <link>https://velog.io/@glory_95/MSSQL-%EC%A0%80%EC%9E%A5-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-CRUD</link>
            <guid>https://velog.io/@glory_95/MSSQL-%EC%A0%80%EC%9E%A5-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-CRUD</guid>
            <pubDate>Tue, 11 Apr 2023 09:05:30 GMT</pubDate>
            <description><![CDATA[<h1 id="프로시저-생성">프로시저 생성</h1>
<h2 id="기본문법">기본문법</h2>
<p>CREATE PROCEDURE 스키마 명.프로시저 명으로 시작하고, AS BEGIN 과 END 사이에 원하는 쿼리를 입력한다.</p>
<pre><code class="language-sql">CREATE PROCEDURE schema_name.Procedure_name
AS
  BEGIN
      SELECT 1
  END </code></pre>
<p>프로시저를 호출할 때 프로시저명과 CREATE와 AS 사이로 매개변수를 지정할 수 있다.</p>
<pre><code class="language-sql">CREATE PROCEDURE schema_name.Procedure_name 
    @site NVARCHAR(500),
    @name NVARCHAR(100),
AS
  BEGIN
      SELECT @site
  END </code></pre>
<h1 id="프로시저-수정">프로시저 수정</h1>
<h2 id="기본문법-1">기본문법</h2>
<p>프로시저를 수정하기 위해서는 생성문에서 CREATE 를 ALTER 로 변경해 주면된다.</p>
<pre><code class="language-sql">ALTER PROCEDURE schema_name.Procedure_name 
    @site NVARCHAR(500),
    @name NVARCHAR(100)
AS
  BEGIN
      SELECT 1
  END</code></pre>
<h1 id="프로시저-조회">프로시저 조회</h1>
<h2 id="sp_helptext">sp_helptext</h2>
<p>sp_helptext 는 객체생성 구문을 텍스트/표 형식으로 결과에 표기한다.</p>
<pre><code class="language-sql">sp_helptext schema_name.Procedure_name</code></pre>
<p><img src="https://velog.velcdn.com/images/glory_95/post/04f83b61-554e-4544-815f-52b8ce0776a7/image.png" alt=""></p>
<p>실제 데이터베이스에서 프로시저를 검색했을때, 빨간 밑줄이 쳐져서 에러라고 생각할수도 있지만 실제로 실행을 하게되면 위의 그림처럼 text라는 한 컬럼에 한줄당 하나의 row데이터로 나열된다.</p>
<p>해당 row데이터 즉, Text칼럼의 값을 그대로 복사하여 쿼리를 실행하면 리턴값을 확인할 수 있다.</p>
<h1 id="프로시저-삭제">프로시저 삭제</h1>
<h2 id="drop">DROP</h2>
<p>프로시저를 삭제하기 위해서는 DROP 구문을 사용한다.</p>
<pre><code class="language-sql">DROP PROCEDURE Schema_Name.Procedure_Name</code></pre>
<h1 id="프로시저-실행방법">프로시저 실행방법</h1>
<h2 id="매개변수가-없을-때">매개변수가 없을 때</h2>
<p>exec 구문을 사용하여 프로시저를 호출한다.</p>
<pre><code class="language-sql">exec Schema_Name.Procedure_Name</code></pre>
<h2 id="매개변수가-있을-때">매개변수가 있을 때</h2>
<p>변수를 선언 및 값을 할당한 후 SP 호출에서 사용할 수 있다.</p>
<pre><code class="language-sql">DECLARE @site NVARCHAR(500)
DECLARE @name NVARCHAR(100)

SET @site = &#39;velog.io&#39;
SET @name = &#39;@glory_95&#39;

exec Schema_Name.Procedure_Name @site, @name</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[GIT 매뉴얼]]></title>
            <link>https://velog.io/@glory_95/GIT</link>
            <guid>https://velog.io/@glory_95/GIT</guid>
            <pubDate>Mon, 10 Apr 2023 05:31:52 GMT</pubDate>
            <description><![CDATA[<h1 id="깃git-이란">깃(Git) 이란?</h1>
<p><strong>Git은 여러 사람들이 프로젝트에서 협업할 수 있도록 도와준다</strong>
<strong>Git은 프로젝트의 시간과 차원을 자유롭게 넘나들수 있도록 해준다.</strong></p>
<ul>
<li>시간 - 프로젝트의 버전을 과거로 되돌리거나 특정 내역을 취소할 수 있습니다.</li>
<li>차원 - 프로젝트의 여러 모드를 쉽게 전환하고 관리할 수 있습니다.</li>
</ul>
<h2 id="이클립스에서도-터미널-창-열기">이클립스에서도 터미널 창 열기</h2>
<p>window &gt;&gt; show window &gt;&gt; other... &gt;&gt; Terminal &gt;&gt; Terminal 선택 &gt;&gt; Open</p>
<p>창이 열린 후 Terminal 창의 Open a Terminal 아이콘 클릭</p>
<p>다양한 터미널 사용 가능, 여기서 우리는 Git Bash를 사용할 예정!</p>
<p>Choose terminal: 에서 Git Bash를 선택 &gt;&gt; OK 클릭</p>
<h2 id="현재-작업위치와-작업위치-이동하기">현재 작업위치와 작업위치 이동하기</h2>
<p>터미널 창이 열리면 <code>C:\Users\각자 컴퓨터에 설정한 이름들</code> 위치에 있을 것이다.</p>
<p>혹시 모르니까 현재 작업위치를 확인한다.</p>
<pre><code class="language-bash">$ pwd</code></pre>
<p>경로를 확인한 후 작업위치로 이동을 한다.</p>
<pre><code class="language-bash">$ cd # c드라이브로 이동 C:\Users\각자 컴퓨터에 설정한 이름들
$ cd [폴더 이름] # 해당 디렉토리로 이동
$ cd bigdata # 현재폴더의 하위폴더인 bigdata 폴더로 이동
$ cd &quot;C:\bigdata\02.backend\1.java\BookRental&quot; # &quot;작업위치 경로&quot;
$ cd .. # 상위 폴더로 이동

$ mkdir [현재 경로에 생성할 디렉토리명] # 디렉토리 생성
$ mkdir test1 # 현재 위치에 test1 디렉토리 생성

$ ls # 현재 디렉토리 폴더, 파일을 보여줌

$ touch index.txt # 현재 위치에 index.txt 파일 생성</code></pre>
<h2 id="git-설정--프로젝트-관리-시작하기">Git 설정 &amp; 프로젝트 관리 시작하기</h2>
<p><strong>1. Git 최초 설정</strong></p>
<p>Git 전역으로 사용자 이름과 이메일 주소 설정 - 나중에 협업할 때 누가 했는 지 알기 위해서 하는 것이라 생각하면 된다. Github 계정과는 별개이다.</p>
<pre><code class="language-bash">$ git config --global [user.name](http://user.name/) &quot;(본인 이름)&quot;
$ git config --global user.email &quot;(본인 이메일)&quot;

$ git config --global user.name # 이름 설정 확인
$ git config --global user.email # 이메일 설정 확인</code></pre>
<p><strong>2. 기본 브랜치명 변경</strong> 
아마도 master로 되어 있는 경우가 있을 것이다.
master가 노예제를 연상시킨다는 이유로 main으로 변경하는 것을 권유하고 있다.</p>
<pre><code class="language-bash">$ git config --global init.defaultBranch main</code></pre>
<p><strong>3. 프로젝트 생성 및 관리 시작</strong></p>
<p>적당한 위치에 원하는 이름으로 폴더 생성</p>
<pre><code class="language-bash">$ git init # .git 폴더 생성 (숨긴 파일 보기를 하면 .git 폴더를 볼 수 있음)</code></pre>
<p>모든 작업(파일 생성, 수정)마다 파일을 저장하기!</p>
<pre><code class="language-bash">$ git status # 파일 상태 확인하기</code></pre>
<h2 id="git의-관리에서-특정-파일폴더를-배제해야-할-경우">Git의 관리에서 특정 파일/폴더를 배제해야 할 경우</h2>
<p>포함할 필요가 없을 때 → 자동으로 생성 또는 다운로드 되는 파일들</p>
<p>포함하지 말아야 할 때 → 보안상 민감한 정보를 담은 파일</p>
<p>이럴 때는 어떻게 해야될까? <strong><strong>.gitignore파일을 사용하여 배제할 요소를 지정</strong></strong>할 수 있다.</p>
<p>.gitignore파일 생성 → 파일에 배제할 파일을 적는다.  </p>
<pre><code class="language-bash">$ git status 
# 파일 상태 확인, .gitignore파일에 index.txt를 적었으면 index.txt는 배제되어 있다.</code></pre>
<p>gitignore 형식은 여기서 자세히 볼 수 있다. <a href="https://git-scm.com/docs/gitignore">https://git-scm.com/docs/gitignore</a></p>
<h2 id="gitignore-파일-생성">.gitignore 파일 생성**</h2>
<ol>
<li><p>원하는 repository 폴더로 이동(.gitignore는 ****프로젝트의 상위 디렉터리에 저장해야한다.)</p>
</li>
<li><p>해당 위치에 파일을 생성 &amp; 편집</p>
<pre><code class="language-bash"> $ vim .gitignore</code></pre>
<p> 위의 명령어를 입력을 하면 파일 편집기가 나온다.</p>
<p> <strong>a</strong>를 눌러서 작성을 시작한다.</p>
<p> <a href="https://www.toptal.com/developers/gitignore"><strong>gitignore.io</strong></a></p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/glory_95/post/6708e4fb-7f59-44bf-961d-3d45beaea35a/image.png" alt=""></p>
<p>gitignore을 만들어주는 사이트에서 개발하려는 프로젝트에 맞는 &#39;운영체제, 개발환경(IDE), 프로그래밍 언어&#39; 를 입력 후 생성 한다.</p>
<p><img src="https://velog.velcdn.com/images/glory_95/post/1bc244fc-fa37-48b7-8002-0c4f13ea56ff/image.png" alt=""></p>
<p>생성된 코드를 복사하여 붙여넣는다.
<strong>esc key</strong>를 눌러서, 명령입력 모드로 전환한 후 <strong>:wp</strong>를 통해 입력한 내용을 저장한다.</p>
<h2 id="git의-공간">Git의 공간</h2>
<p><img src="https://velog.velcdn.com/images/glory_95/post/06e19de5-84cd-4fa6-b1ea-d62c80cd25ef/image.png" alt=""></p>
<p>Working directory</p>
<ul>
<li>untracked : Add된 적 없는 파일, ignore 된 파일</li>
<li>tracked : Add된 적 있고 변경내역이 있는 파일, Git의 관리대상에 정식으로 등록됨을 의미한다.</li>
<li><code>git add</code> 명령어로 Staging area로 이동</li>
</ul>
<p>Staging area</p>
<ul>
<li>커밋을 위한 준비 단계<ul>
<li>예시 : 작업을 위해 선택된 파일들</li>
</ul>
</li>
<li><code>git commit</code> 명령어로 repository로 이동</li>
</ul>
<p>Repository</p>
<ul>
<li><code>.git directory</code>라고도 불림</li>
<li>커밋된 상태</li>
</ul>
<h2 id="프로젝트의-변경사항들을-commit하기">프로젝트의 변경사항들을 commit하기</h2>
<pre><code class="language-bash">$ git add 파일명.확장자 # 원하는 파일을 Staging area로 담기.
$ git add . # 모든 파일을 Staging area로 담기.
$ git commit # 위의 과정들을 하면서 중간에 git status로 상태를 확인한다.</code></pre>
<p>git commit을 하면 Vi 입력 모드로 진입을 한다.</p>
<p>커밋 메시지를 작성을 하면 된다.</p>
<p>좀 더 간단하게 커밋 메시지를 작성할 수 있는 방법이 있다.</p>
<pre><code class="language-bash">$ git commit -m &quot;COMMIT” # 커밋 메시지까지 함께 작성하면 된다.
$ git log # 위치한 브랜치에서 커밋한 내용들을 확인할 수 있다. 종료는 :q하면 된다.
$ git diff #파일의 추가, 변경, 삭제의 자세한 내역을 살펴볼 수 있다.</code></pre>
<p>add와 commit 한번에 하기</p>
<pre><code class="language-bash">$ git commit -am &quot;(메시지)” # untracked 파일이 없을 때 가능</code></pre>
<h2 id="git에서-과거로-돌아가는-두-방식">Git에서 과거로 돌아가는 두 방식</h2>
<ul>
<li><strong>reset</strong> : 원하는 시점으로 돌아간 뒤 이후 내역들을 지운다.  origin에 올리지 않고 로컬에 커밋이 머물렀다면, 올라갔어도 나만 해당 브랜치를 사용한다면 reset를 쓰셔도 좋습니다.</li>
<li><strong>revert</strong> : 되돌리기 원하는 시점의 커밋을 거꾸로 실행합니다. 커밋의 내용을 되돌리는 커밋을 새로 만듭니다</li>
</ul>
<p><img src="https://velog.velcdn.com/images/glory_95/post/dd23c57a-2a00-47e5-8286-97dea6d46559/image.png" alt=""></p>
<pre><code class="language-bash">$ git reset --hard (돌아갈 커밋 해시) 
# git log를 통해 커밋 해시 복사, 뒤에 커밋 해시가 없으면 마지막 커밋 가리킨다.</code></pre>
<p>reset의 세 가지 옵션</p>
<ul>
<li><p>-soft: <code>repository</code>에서 <code>staging area</code>로 이동</p>
</li>
<li><p>-mixed (default): <code>repository</code>에서 <code>working directory</code>로 이동</p>
</li>
<li><p>-hard: 수정사항 완전히 삭제</p>
<pre><code class="language-bash">  $ git revert (되돌릴 커밋 해시) # :wq로 커밋 메시지 저장
  $ git revert --continue # 충돌이 생겼을 때 충돌이 일어난 부분 수정하고 하면 된다.
  $ git revert --no-commit (되돌릴  커밋 해시) 
  # 커밋을 하지않고 revert하기, 
  # 원하는 다른 작업을 추가한 다음 함께 커밋, 
  # 취소하려면 git reset --hard</code></pre>
</li>
</ul>
<h2 id="branch-생성--이동--삭제하기이름-바꾸기">Branch 생성 / 이동 / 삭제하기/이름 바꾸기</h2>
<pre><code class="language-bash">$ git branch develop # develop이라는 브랜치 생성
$ git branch # 브랜치 목록 확인
$ git switch develop # checkout 명령어가 Git 2.23 버전부터 switch, restore로 분리되었다.
$ git switch -c save # 브랜치 생성과 동시에 이동하기, 기존의 git checkout -b (새 브랜치명)
$ git branch -d (삭제할 브랜치명)
# 지워질 브랜치에만 있는 내용의 커밋이 있을 경우
# (다른 브랜치로 가져오지 않은 내용이 있는 브랜치를 지울 때)
# -d 대신 -D(대문자)로 강제 삭제해야 한다.
$ git branch -m (기존 브랜치명) (새 브랜치명) # 브랜치 이름 바꾸기</code></pre>
<h2 id="여러-branch의-내역-편리하게-보기">여러 Branch의 내역 편리하게 보기</h2>
<pre><code class="language-bash">$ git log --all --decorate --oneline --graph</code></pre>
<h2 id="branch-합치는-두가지-방식">Branch 합치는 두가지 방식</h2>
<ul>
<li><strong>merge</strong> : 두 브랜치를 한 커밋에 이어붙인다.<ul>
<li>브랜치 사용내역을 남길 필요가 있을 때 적합한 방식이다.</li>
</ul>
</li>
<li><strong>rebase</strong> : 브랜치를 다른 브랜치에 이어붙인다.<ul>
<li>한 줄로 깔끔히 정리된 내역을 유지하기 원할 때 적합하다.</li>
<li>이미 팀원과 공유된 커밋들에 대해서는 사용하지 않는 것이 좋다.
<img src="https://velog.velcdn.com/images/glory_95/post/7400bb80-0aa0-4ec2-a606-ac67442bbcac/image.png" alt=""></li>
</ul>
</li>
</ul>
<p>노란색을 main브랜치, 분홍색을 develop브랜치로 가정</p>
<p>develop 브랜치를 main 브랜치로 <strong>merge</strong>하기위해서는 main브랜치로 이동한다.</p>
<pre><code class="language-bash">$ git merge develop # :wq로 자동입력된 커밋 메시지 저장하여 마무리
$ git branch -d develop # 병합된 브랜치는 삭제</code></pre>
<p>merge도 하나의 커밋이기때문에 merge하기 전 해당 브랜치의 마지막 시점으로 reset하면 되돌리기 가능하다.</p>
<p>develop 브랜치를 main 브랜치로 <strong>rebase</strong>하기위해서는 develop 브랜치로 이동한다.</p>
<pre><code class="language-bash">$ git rebase main</code></pre>
<p>main 브랜치로 이동후 아래 명령어로 develop의 시점으로 fast-forward</p>
<pre><code class="language-bash">$ git merge new-teams
$ git branch -d develop # 병합된 브랜치는 삭제</code></pre>
<h2 id="브랜치-간-충돌">브랜치 간 충돌</h2>
<p>파일의 같은 위치에 다른 내용이 입력된 상황</p>
<ol>
<li>merge 충돌 해결</li>
</ol>
<ul>
<li>오류 메시지와 <code>git status</code> 확인</li>
<li>자바에서 해당 부분 확인</li>
<li>해결 가능 시 충돌 부분을 수정한 뒤 <code>git add .</code>, <code>git commit</code>으로 병합 완료</li>
</ul>
<pre><code class="language-bash">git merge --abort # 당장 충돌 해결이 어려울 경우 아래 명령어로 merge중단</code></pre>
<ol>
<li>rebase 충돌 해결</li>
</ol>
<ul>
<li>오류 메시지와 <code>git status</code> 확인</li>
<li>자바에서 해당 부분 확인</li>
<li>충돌 부분을 수정한 뒤 <code>git add .</code> 아래 명령어로 계속</li>
</ul>
<pre><code class="language-bash">$ git rebase --continue # 충돌이 모두 해결될 때까지 반복
$ git rebase --abort # 당장 충돌 해결이 어려울 경우 아래 명령어로 rebase중단</code></pre>
<h2 id="이클립스에서-충돌-해결-절차">이클립스에서 충돌 해결 절차</h2>
<p><a href="https://confluence.curvc.com/pages/releaseview.action?pageId=6162682">https://confluence.curvc.com/pages/releaseview.action?pageId=6162682</a> 참고</p>
<h2 id="personal-access-token-만들기">Personal access token 만들기</h2>
<p>이것을 하는 이유는? </p>
<p>Git Hub에서 ID/PW기반의 Basic Authentication 인증을 금지하고, ID/Personal Access Token 방식의 Token Authentication 인증을 요구하고 있다.</p>
<ul>
<li>우측 상단의 프로필 - <code>Settings</code></li>
<li><code>Developer Settings</code></li>
<li><code>Personal access tokens</code> - <code>Generate new token</code></li>
<li><code>repo</code> 및 원하는 기능에 체크, 기간 설정 뒤 <code>Generate token</code></li>
<li>토큰 안전한 곳에 보관해 둘 것</li>
</ul>
<h2 id="토큰-컴퓨터에-저장하기---윈도우일-경우">토큰 컴퓨터에 저장하기 - 윈도우일 경우</h2>
<ul>
<li><code>Windows 자격 증명 관리자</code></li>
<li><code>Windows 자격 증명</code> 선택</li>
<li><code>git:https://github.com</code> 자격 정보 생성</li>
<li>사용자명과 토큰 붙여넣기</li>
</ul>
<h2 id="레포지토리에서-협업할-팀원-추가하기">레포지토리에서 협업할 팀원 추가하기</h2>
<p><code>Settings</code> - <code>Collaborators</code> - <code>Add people</code></p>
<h2 id="로컬에-원격-저장소-추가-후-푸시">로컬에 원격 저장소 추가 후 푸시</h2>
<pre><code class="language-bash">$ git remote add origin (원격 저장소 주소) # 로컬의 Git 저장소에 원격 저장소로의 연결 추가
$ git branch -M main
$ git push -u origin main 
# 로컬 저장소의 커밋 내역들 원격으로 push(업로드)
# -u 또는 --set-upstream : 현재 브랜치와 명시된 원격 브랜치 기본 연결
$ git remote # 원격 목록 보기
$ git remote remove (origin 등 원격 이름) # 원격 지우기(로컬 프로젝트와의 연결만 없애는 것)</code></pre>
<h2 id="github에서-프로젝트-다운받기">GitHub에서 프로젝트 다운받기</h2>
<p>터미널이나 Git Bash에서 대상 폴더 이동후</p>
<pre><code class="language-bash">$ git clone (원격 저장소 주소) # Git 관리내역 포함 다운로드</code></pre>
<h2 id="push-pull">push, pull</h2>
<pre><code class="language-bash">$ git push
$ git push &lt;저장소명&gt; &lt;브랜치명&gt;
$ git pull
$ git pull &lt;저장소명&gt; &lt;브랜치명&gt;</code></pre>
<h2 id="pull-할-것이-있을-때-push를-한다면">pull 할 것이 있을 때 push를 한다면?</h2>
<p>원격에 먼저 적용된 새 버전이 있으므로 적용이 안된다.</p>
<p>pull해서 원격의 버전을 받아온 다음 push가 가능하다.</p>
<ul>
<li><p><code>git pull --no-rebase</code> - <strong>merge</strong> 방식</p>
<p>  충돌 부분을 수정한 뒤 <code>git add .</code>, <code>git commit</code>으로 병합 완료</p>
</li>
<li><p><code>git pull --rebase</code> - <strong>rebase</strong> 방식 → pull 상의 rebase는 다름 (협업시 사용 OK)</p>
<p>  충돌 부분을 수정하고 <code>git add .</code> 를 한다. <code>git rebase --continue</code> 를 한다.</p>
</li>
</ul>
<h2 id="로컬의-내역-강제-push하기">로컬의 내역 강제 push하기</h2>
<ol>
<li><p>로컬의 내역 충돌 전으로 <code>reset</code></p>
</li>
<li><p>아래 명령어로 원격에 강제 적용</p>
</li>
</ol>
<pre><code class="language-bash">$ git push --force</code></pre>
<h2 id="로컬에서-브랜치-만들어-원격에-push-해보기">로컬에서 브랜치 만들어 원격에 push 해보기</h2>
<p>브랜치를 만든 후 원격에 push를 하면 대상을 명시하라는 메시지가 나타난다.</p>
<pre><code class="language-bash">$ git push -u origin save # 원격의 브랜치 명시 및 기본 설정
$ git branch --all # 로컬과 원격의 브랜치 확인
$ git config --global push.default current 
# 항상 현재 브랜치를 기준으로 git push 명령어가 작동</code></pre>
<h2 id="원격의-브랜치-로컬에-받아오기">원격의 브랜치 로컬에 받아오기</h2>
<pre><code class="language-bash">$ git fetch # 원격의 변경사항 확인
$ git switch -t origin/save # 로컬에 같은 이름의 브랜치를 생성하여 연결하고 switch</code></pre>
<pre><code class="language-bash">$ git push (원격 이름) 0.--delete (원격의 브랜치명)</code></pre>
<h2 id="리모트-저장소-확인하기-추가하기-push하기">리모트 저장소 확인하기, 추가하기, push하기</h2>
<pre><code class="language-bash">git remote -v # 리모트 저장소 확인
git remote add [단축 이름] [URL] # 리모트 저장소 추가
git push [remote-name] [branch-name] # 리모트에 push</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DBMS 아키텍처] DBMS의 구조]]></title>
            <link>https://velog.io/@glory_95/DBMS-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</link>
            <guid>https://velog.io/@glory_95/DBMS-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</guid>
            <pubDate>Mon, 10 Apr 2023 04:36:27 GMT</pubDate>
            <description><![CDATA[<h1 id="dbms-아키텍처의-구조-및-개요">DBMS 아키텍처의 구조 및 개요</h1>
<p>현재 사용되는 RDB(Relational Database) 제품은 굉장히 많다.
한국에서는 Oracle, SQL Server, DB2, PostgreSQL, MySQL 등이 많이 사용된다.
상용되고 있는 RDB들의 내부 아키텍처들이 조금씩 다르지만 RDS로써 기능을 제공한다는 목적은 같다. 
즉, 관계 모델이라는 수학적인 이론을 바탕으로 결국 기본적인 구조 자체는 모두 같다. 이러한 공통적인 구조를 이해한다면, 각각의 DBMS가 가지는 특징도 쉽게 이해를 할 수 있다. 
<img src="https://velog.velcdn.com/images/glory_95/post/51190453-2bfd-4e5e-9382-05284b13a994/image.jpg" alt=""></p>
<p>해당 그림은 데이터베이스 사용자와의 인터페이스를 나타낸다.
전달된 SQL 구문은 중간에 위치한 DBMS를 통해 다양한 처리를 수행하고, 저장 장치에 있는 데이터에 접근해서 데이터를 읽고 쓴다.
일반적인 DBMS 아키텍처는 위와 같은 구조를 가지고 있다. DBMS 내부의 기능을 알아보자.</p>
<h2 id="1-쿼리-평가-엔진">1. 쿼리 평가 엔진</h2>
<ul>
<li>사용자로부터 입력받은  SQL 구문을 분석하여, 실행 계획(Explain Plan, 어떤 순서로 데이터에 접근하는지)을 결정한다.</li>
<li>실행 계획을 기반으로 데이터에 접근하는 방법을 접근 메서드(Access Method)라고 한다.</li>
<li>성능과 깊은 관련이 있는 DBMS의 핵심 기능을 담당하는 모듈이다.</li>
</ul>
<h2 id="2-버퍼-매니저">2. 버퍼 매니저</h2>
<ul>
<li>DBMS는 버퍼라는 메모리 영역을 확보하는데, 이를 관리한다.</li>
<li>디스크 용량 매니저와 연동되어 작동한다.<blockquote>
<p>버퍼란, 임시 저장 공간을 의미한다. 임시 저장 공간이라고 해서 쌩뚱맞게 보일 수 있지만 정확히 말하면 A와 B가 서로 입출력을 수행하는데에 있어서 속도차이를 극복하기 위해 사용하는 임시 저장 공간을 의미 한다.</p>
</blockquote>
</li>
</ul>
<h2 id="3-디스크-용량-매니저">3. 디스크 용량 매니저</h2>
<ul>
<li>가장 많은 데이터를 다루는 소프트웨어</li>
<li>어디에 어떻게 데이터를 저장할지를 관리하며, 데이터의 읽고 쓰기(I/O)를 제어한다.</li>
</ul>
<h2 id="4-트랜잭션-매니저와-락-매니저">4. 트랜잭션 매니저와 락 매니저</h2>
<ul>
<li>수백에서 수천명의 사람이 동시에 DB에 접근하여 사용하게되는데, 이때 각각의 처리는 DBMS 내부에서 트랙잭션이라는 단위로 관리된다.</li>
<li>트랜잭션의 정합성을 유지하면서 실행시키고, 필요한 경우 데이터에 락을 걸어 다른 사람의 요청을 대기시킨다.<blockquote>
<p>정합성 : 어떤 데이터들이 값이 서로 일치함.
무결성 : 데이터 값이 정확한 상태</p>
</blockquote>
</li>
</ul>
<h2 id="5-리커버리-매니저">5. 리커버리 매니저</h2>
<ul>
<li>시스템의 장애를 대비한다.</li>
<li>데이터를 정기적으로 백업하고, 문제가 일어났을 때 데이터를 복구한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSSQL] 저장 프로시저의 개요]]></title>
            <link>https://velog.io/@glory_95/MSSQL-%EC%A0%80%EC%9E%A5-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-Stroed-Procedure</link>
            <guid>https://velog.io/@glory_95/MSSQL-%EC%A0%80%EC%9E%A5-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-Stroed-Procedure</guid>
            <pubDate>Fri, 07 Apr 2023 01:17:48 GMT</pubDate>
            <description><![CDATA[<h2 id="스토어드-프로시저stored-procedure-란">스토어드 프로시저(Stored Procedure) 란?</h2>
<blockquote>
<p>일련의 쿼리를 마치 하나의 함수 처럼 실행하기 위한 쿼리의 집합이다.</p>
</blockquote>
<p>DB에 대한 작업을 정리한 절차를 RDBMS(관계형 데이터 베이스 관리 시스템)에 저장한 쿼리의 집합이다. 영구저장모듈이라고도 불린다. 여러 쿼리를 하나의 함수로 묶은 것이다.</p>
<ul>
<li>SQL Server에서 제공되는 프로그래밍 기능. 쿼리문의 집합</li>
<li>어떠한 동작을 일괄 처리하기 위한 용도로 사용.</li>
<li>자주 사용되는 일반적인 쿼리를 모듈화시켜서 필요할 때마다 호출</li>
<li>테이블처럼 각 데이터베이스 내부에 저장</li>
</ul>
<h2 id="일반-쿼리문-저장프로시저의-작동방식-비교">일반 쿼리문, 저장프로시저의 작동방식 비교</h2>
<h3 id="일반-쿼리문-작동방식">일반 쿼리문 작동방식</h3>
<p><img src="https://velog.velcdn.com/images/glory_95/post/dabc946b-b833-47ca-b87f-80f0c059d7f0/image.png" alt="">
위의 그림은 일반적인 쿼리문을 최초 실행시에 동작하는 프로세스이다.
예를들어 아래와 같은 쿼리를 작성하여 실행한다고 가정하자.</p>
<pre><code class="language-sql">SELECT name FROM user;</code></pre>
<p><strong>구문분석</strong>
입력된 sql 쿼리문을 분석하여 오류가 없는지 검사한다.
만약 오타가 존재할시, 해당 단계에서 에러메세지가 출력된다.</p>
<p><strong>개체 이름 확인</strong>
user라는 테이블이 현재 데이터베이스에 있는지 확인을 한다.
존재한다면, 해당 테이블에 SELECT 한 칼럼이 있는지 확인할 것이다.</p>
<p><strong>사용권한 확인</strong>
현재 쿼리를 수행하는 주체인 사용자가 해당 테이블에 접근할 권한이 있는지 확인한다.</p>
<p><strong>최적화</strong>
해당 쿼리문이 가장 좋은 성능을 낼 수 있는 경로를 결정한다. 인덱스 사용여부에 따라 경로가 결정된다고 보면된다.</p>
<p><strong>컴파일 및 실행계획 등록</strong>
다음은 최적화된 결과를 바탕으로 컴파일 및 실행 계획 등록 단계에서 해당 실행계획 결과를 메모리(캐시)에 등록한다. 그리고 컴파일된 결과를 실행한다.</p>
<p>단 한줄의 쿼리를 실행을 할 때에도 이렇게나 많은 절차를 가지게 된다.
만약 최초로 해당 쿼리를 실행한 후, 재실행을 하게되면 아래 프로세스처럼 동작하게 된다.
여러 과정이 생략되다 보니 시간이 단축되게 될 것이다.
<img src="https://velog.velcdn.com/images/glory_95/post/ba1b46cc-be7f-4dd3-af8f-db3e6d0222b0/image.png" alt=""></p>
<p><strong>여기서 중요한점은 만약에 메모리(캐시)에 쿼리 전체가 한글자도 틀리지 않고 같아야 한다는 것이다.</strong></p>
<blockquote>
<p>실제로 업무 중에, 데이터를 추출하는 작업을 할 때에 수백만 개의 로우 데이터를 조회하는 질의를 작성 후 실행하였을 때 5분이라는 시간이 걸렸지만, 추출이 완료되고 다시 실행하였을 때 몇 초도 안 걸렸던 경험이 생각이 난다. 또한, 칼럼 명의 별칭만 다르게 했을 뿐인데 다시 몇 분이 소요되기도 하였다.</p>
</blockquote>
<h3 id="저장프로시저">저장프로시저</h3>
<h4 id="저장프로시저의-정의">저장프로시저의 정의</h4>
<p><img src="https://velog.velcdn.com/images/glory_95/post/09f4e21e-ad41-424f-8791-ee5942b99d53/image.png" alt="">
<strong>먼저 저장 프로시저를 정의 했을때 작동방식을 알아보자.</strong></p>
<ol>
<li><p>일단 먼저 해당 저장 프로시저에서 구문 오류가 있는 지를 파악하는 과정을 거친다.</p>
</li>
<li><p>다음은 지연된 이름 확인(deferred name resolution) 과정을 거치게 되는데 이는 저장 프로시저의 특징중 하나이니 잘 기억해두자. 추가로, 저장 프로시저를 정하는 시점에서 해당 개체(ex. 테이블)가 존재하지 않아도 상관없다. 프로시저 실행 당시에 테이블 존재 여부를 확인한다. 그런데 테이블의 열이름이 틀리면 오류가 발생된다.</p>
</li>
</ol>
<ol start="3">
<li><p>다음은 생성권한은 확인하는 단계인데 사용자가 저장 프로시저를 생성할 권한이 있는지를 확인하는 과정이다.</p>
</li>
<li><p>마지막으로 시스템 테이블 등록을 진행한다. 저장 프로시저의 이름과 코드가 관련 시스템 테이블에 등록되는 과정이다.</p>
</li>
</ol>
<h4 id="저장프로시저의-첫-실행">저장프로시저의 첫 실행</h4>
<p>구문분석 단계가 빠지는 것만 빼면 일반적인 쿼리문 수행단계와 동일하다.  일단 정의 단계에서 구문분석은 끝났기때문에 따로 구문분석을 하지 않는다.앞서 정의시에 지연된 이름 확인이란게 있었는데, 실제로 해당 개체가 유효한지를 개체이름 확인 단계에서 진행하게 된다. 다시 말해서 저장 프로시저의 실행 시에만 해당 개체가 존재하면 실행이 된다. 추가로, 저장프로시저의 정의할때 생성권한을 확인했다면 실행시에는 사용권한을 확인하는 권한의 분리가 이루어진다.
<img src="https://velog.velcdn.com/images/glory_95/post/1d87a9f4-135b-4546-b933-6f04007b7114/image.png" alt=""></p>
<h4 id="이후의-저장프로시저의-재실행">이후의 저장프로시저의 재실행</h4>
<p>이후에 두번째 실행 부터는 메모리(캐시)에 있는 것을 그대로 가져와 재사용하게 되어 수행시간을 많이 단축한다.
<img src="https://velog.velcdn.com/images/glory_95/post/90c9520e-b943-4958-8c7a-22ca71e1108d/image.png" alt=""></p>
<p><strong>주의사항</strong>
그렇다면 저장 프로시저는 과연 만능의 성능을 자랑할까? 대부분의 경우에는 성능이 향상되나 항상 그렇지는 않다.
저장 프로시저의 첫 실행시 최적화 단계를 수행할때 인덱스를 사용할지 안할지를 결정하게 되는데, 인덱스를 사용한다고 항상 수행결과가 빨라지지 않는다.</p>
<p><strong>만약에 가져올 데이터가 다량인데 인덱스를 사용하면 오히려 성능이 바빠지게 될 것이다.</strong>
저장 프로시저는 첫번째 수행 시에 최적화가 이루어져서 인덱스 사용여부가 결정되어 버린다.
만약에 첫번째 수행때 데이터를 몇건만 가져오도록 파라미터가 설정되어 있다면, 인덱스를 사용하도록 최적화되어 컴파일 됐을 것이다.</p>
<p>그런데 두번째 수행에서 많은 건수의 데이터를 가져오도록 파라미터가 들어가면..?
<strong>일반 쿼리문이었다면 파라미터가 달라졌으니 다시 최적화되어 컴파일 되겠지만 저장 프로시저는 그냥 인덱스를 사용하는 프로시저를 실행시켜 버릴 것이다.</strong></p>
<h2 id="저장프로시저의-장단점">저장프로시저의 장단점</h2>
<h3 id="장점">장점</h3>
<h4 id="서버클라이언트-네트워크-트래픽-감소">서버/클라이언트 네트워크 트래픽 감소</h4>
<p>프로시저의 명령은 단일 일괄 처리 코드로 실행된다. 따라서 프로시저를 실행할 호출만 네트워크에서 전송되기 때문에 서버와 클라이언트 간의 네트워크 트래픽이 크게 줄어들 수 있다.
즉, 저장 프로시저를 쓰게 된다면 단 한 번의 요청으로 여러 SQL문을 실행할 수 있으므로, 네트워크에 대한 부하를 줄일 수 있다.</p>
<h4 id="보안-강화">보안 강화</h4>
<p>여러 사용자 및 클라이언트 프로그램이 기본 데이터베이스 개체에 대한 직접적인 사용 권한이 없는 경우에도 프로시저를 통해 이러한 기본 개체에 대해 작업을 수행할 수 있다. 프로시저는 수행되는 프로세스 및 작업을 제어하고 기본 데이터베이스 개체를 보호한다. 따라서 개별 개체 수준에서 사용 권한을 부여할 필요가 없으며 보안 계층이 간소화된다.</p>
<p>즉,사용자별로 테이블에 권한을 주는게 아닌 저장 프로시저에만 접근 권한을 주는 방식으로 보안을 강화할 수 있다. 실제 테이블에 접근하여 다양한 조작을 하는 것은 위험하기 때문에 실무에서는 실제로 개발자에게는 sp권한만 주는 방식을 많이 사용한다고 한다.</p>
<h4 id="성능-향상">성능 향상</h4>
<p>기본적으로 프로시저는 처음 실행될 때 컴파일되며 이후 실행에 다시 사용되는 실행 계획을 만든다. 쿼리 프로세서는 새 계획을 만들 필요가 없으므로 일반적으로 프로시저 처리 시간이 줄어든다.</p>
<p>프로시저에서 참조하는 테이블이나 데이터가 크게 변경된 경우에는 미리 컴파일된 계획으로 인해 실제로 프로시저 실행 속도가 느려질 수 있다. 이 경우 프로시저를 다시 컴파일하고 새 실행 계획을 강제 적용하면 성능을 향상시킬 수 있다.</p>
<h4 id="유지보수-및-재활용-측면에서-좋다">유지보수 및 재활용 측면에서 좋다.</h4>
<p>C#, Java등으로 만들어진 응용프로그램에서 직접 SQL문을 호출하지 않고 저장 프로시저의 이름을 호출하도록 설정하여 사용하는 경우가 많은데, 이때 개발자는 수정요건이 발생할때 코드 내 SQL문을 건드리는게 아니라 SP 파일만 수정하면 되기 때문에 유지보수 측면에서 유리해진다. </p>
<p>또한 한번 저장 프로시저를 생성해 놓으면, 언제든 실행이 가능하기 때문에 재활용 측면에서 매우 좋다.</p>
<h3 id="단점">단점</h3>
<h4 id="낮은-처리-성능">낮은 처리 성능</h4>
<ul>
<li>문자, 숫자열 연산에 SP를 사용하면 오히려 c, java보다 느린 성능을 보일 수 있다.</li>
</ul>
<h4 id="유지보수">유지보수</h4>
<ul>
<li>개발된 프로시저가 여러 곳에서 사용 될 경우 수정했을 때 영향의 분석이 어렵다(별도의 Description 사용).</li>
<li>배포, 버전 관리 등에 대한 이력 관리가 힘들다.</li>
<li>APP에서 SP를 호출하여 사용하는 경우 문제가 생겨도 해당 이슈에 대한 추적이 힘들다(별도의 에러 테이블 사용).</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>