대용량 데이터베이스 솔루션 조광원 선생님 동영상 강의를 구했다. 책으로만 보기엔 너무 힘들어서...


비록 좀 오래된 강의라 화질이 좋진 않지만 도움이 되겠지? 

  [ 비밀번호 관리 ]


  : 데이터베이스에서 항상 기밀로 유지해야 한다.

    -> 비밀번호 관리 정책이 있어야 한다.

    

    - 사용자 암호를 관리하기 위해서는 profile을 사용한다.

      - profile 생성 구문 형식 )

          create profile 프로파일명 limit

            옵션1,

            옵션2, .....

    

      - 사용자에게 profile을 적용하는 방법 )

          - 기존유저일 경우 : ALTER USER

          - 새로추가하는 유저일 경우 : CREATE USER

          명령을 이용해서 profile을 적용할 수 있다.

    

    - [  암호 관리 유형  ] 

      

      - 1)비밀번호 입력 횟수 제한하는 방법 : 제한횟수 이상의 로그인 시도시 사용자 계정을 lock 시킴.

      

      - 2)비밀번호의 유효기간을 설정하는 방법    

          : 유효기간이 지나면 암호를 재설정하여 사용하도록 함.

      

      - 3)비밀번호의 재사용 금지 방법

          : 암호 재설정시 기존에 사용한 암호를 다시 사용할 수 없도록 하는 방법.


      - 4)복잡한 암호 설정 방법을 사용

          : 0자 이상, 특수문자 포함 등을 포함시켜 패스워드를 생성하게 하는 패스워드 설정 정책

          -> 오라클에서 제공하는 함수를 사용해서 복잡한 암호를 사용하도록 설정할 수 있다.

          -> (password_verify_function 함수) 

*/


-- 1)비밀번호 입력 횟수를 제한하는 profile을 생성

create profile profile_test limit

  FAILED_LOGIN_ATTEMPTS 3 -- 3번 시도 실패하면 

  PASSWORD_LOCK_TIME 5; -- 5일간 패스워드에 lock을 검


-- 만든 profile을 HR(기존에 있는 사용자) 계정에 적용하기

alter user hr profile profile_test;

-- 3번 로그인 실패시 5일 lock이 걸리게 됨


-- lock을 풀어주는 방법

alter user hr account unlock;


-- 다시 lock을 걸기

alter user hr account lock;


-- 사용자 계정에 lock이 걸렸는지 확인해 보기(dba_users에서...)

select username, account_status AS lock유무, to_char(lock_date,'yy/mm/dd hh24:mi') AS 잠긴날짜,

       profile AS 적용된profile

from dba_users

where username = 'HR';





-- 2)profile에 유효기간 설정하기 

create profile profile_test2 limit

  FAILED_LOGIN_ATTEMPTS 3

  PASSWORD_LOCK_TIME 5

  password_life_time 90 -- 90일동안 패스워드가 유효할 수 있도록 설정함

  password_grace_time 5; -- 90일 지난 다음 유예기간을 설정할 수 있음

  -- 이 유예기간 동안은 로그인할 때마다 경고메시지가 뜨게됨

  -- 이때의 5일은 90일 다음날부터 카운트되는 것이 아닌, 사용자가 90일이 지나고

  -- 최초로 로그인을 시도한 날부터 카운트 되게 됨.



-- dba가 계정을 만료시키는 방법)

  --  alter user 사용자ID password expire;

  

  

-- 3)비밀번호 재사용을 금지시키는 방법)

create profile profile_test3 limit

  password_reuse_time 30 -- 설정했던 패스워드를 30일간은 사용할 수 없음

  password_reuse_max unlimit; 

  

create profile profile_test4 limit

  password_reuse_time unlimit

  password_reuse_max 3; -- 지금 사용하는 비밀번호를 3번 바껴야 다시 해당 비밀번호를 사용할 수 있게 됨

  

  -- password_reuse_time과 password_reuse_max는 서로 상호 베타여서 하나가 값이 있으면 하나는 unlimit으로 되어야 한다.!!

  



  [ DB 사용자 관리(생성,변경,삭제) 및 사용자 정보 알아보기 ]


  - 사용자 계정 : 논리적인 의미

  

  - SYS계정

      : 데이터베이스내의 모든 권한을 갖는 최상위 레벨의 사용자

      

  - SYSTEM 계정

      : SYS 사용자로부터 "DBA권한"을 받은 사용자

      . 새로운 사용자를 추가, 변경, 삭제할 수 있다.

      . 사용자별 공간할당, 패스워드관리, 세션관리 등을 할 수 있다.

      . 데이터베이스 오브젝트(테이블, 뷰, 트리거...)는 "사용자별로" 생성된다.

      . 데이터베이스 오브젝트를 생성한 사용자를 그 오브젝트의 소유자(owner)라 한다.




--[ 사용자 생성 ]

--  : dba권한을 가진 사용자만 가능하다.

-- 형식 ) create user 사용자ID identified by 패스워드


--        해당 사용자가 생성하는 객체가 저장될 테이블 스페이스도 지정할 수 있다.


--        create user 사용자ID identified by 패스워드 default tablespace 테이블스페이스명

--        temporary tablespace temp /*정렬을 위한 temporary tablespace도 생성 가능*/

--        quota 20M on appl_data quota 10M on system; /*tablespace 용량 할당*/


-- 테이블스페이스를 지정하지 않으면, 기본적으로 system tablespace를 사용하게 된다.

create user user1 identified by user1

  default tablespace test_1;

  

-- 사용자 정보 검색 : dba_users에서 검색

select username from dba_users;

select * from dba_users;


/*

  [ 사용자 변경 ]

  - 패스워드 변경 >

      alter user 사용자명 identified by 바꿀비밀번호;

  

  - 사용자의 테이블스페이스 변경>

      alter user 사용자명 default tablespace 바꿀테이블스페이스명;

      

  - 사용가능 용량 변경

      alter user 사용자명 quota 10M on 테이블스페이스명; 

  



alter user user1 identified by 1234;

alter user user1 quota 10 on test_1;


-- 전체 사용자에 대한 정보를 검색할 때

  -- 테이블스페이스 정보, 패스워드, 아이디를 포함해 사용자의 정보를 볼 수 있다.

select * from dba_users;

-- 현재 로그인한 사용자에 대한 정보만을 검색할 때

select * from user_users;



  [ 사용자 제거 ]

  형식 ) 

        drop user 사용자ID;

        

        -- 해당사용자가 가지고 있는 객체(뷰,트리거 등)도 전부 삭제하는 방법(cascade)

          -- 잘 사용하지 않는다.(신중하게 해야한다. 대부분 위 방법으로 삭제한다.)

        drop user 사용자ID cascade;

*/

create user user2 identified by user2;

select * from dba_users;


-- 사용자 제거

drop user user2;


select username from dba_users where username = 'user2';


-- 현재 자신의 계정에 대한 정보를 검색할 때

select * from user_users;



  [ 사용자 공간 사용 정보 알아보는 방법 ]

  

    - 사용자 공간 정보 알아보기 위한 딕셔너리 : user_ts_quotas, dba_ts_quotas

*/

select * from USER_TS_QUOTAS;


select * from SYS.DBA_TS_QUOTAS;

-- MAX_BYTES 항목이 -1인 값의 의미는 최대 용량 제한이 없음을 의미(unlimited)





  [ 사용자의 세션 정보를 알아보는 딕셔너리 ]

  -> v$session

  현재 접속중인 사용자들의 세션 정보를 알 수 있다.


select sid, serial#, username, program from v$session;

-- program : 어떤 프로그램을 통해 접속했는지

-- username : 사용자ID


-- HR에 접속한 것의 세션을 끊어버리기

-- 세션을 중지시키기 : alter system kill session 'SID,SERIALNUM';

alter system kill session '93,275';

select sid, serial#, username, program from v$session;


/*

  [ 인덱스(Index)의 개념/종류/주의사항/활용,관리 ]

  

  1. 인덱스(Index)란???

    : 어떤 데이터가 HDD(하드디스크)의 어디에 있는지 위치 정보를 가진 주소록과 같은 개념.

    -> (데이터 - 위치주소(ROWID)) 쌍으로 저장하고 관리됨

    

    - 목적)

      : 빠르게 쿼리 검색을 하오기 위함

      

    데이터 위치 정보(주소) : ROWID -> 총 10Byte

*/

-- 데이터 튜플의 rowid를 검색해 보기

select rowid, empno, ename from scott.emp where empno = 7521;

-- 결과 : 

/*

  ROWID             EMPNO   ENAME

AAAE+3AAEAAAAFfAAC   7521    WARD

*/

-- [ ROWID의 구조 ] : AAAE+3AAEAAAAFfAAC

/*

  -AAAE+3 : 데이터 오브젝트의 번호

  -AAE : 파일 번호

  -AAAAFf : 블럭 번호

  -AAC : ROW(튜플) 번호

*/


/*

  2. [ 인덱스의 생성 원리 ]

  

    : 전체 테이블을 스캔(Table Full Scan) -> PGA내의 Sort Area에서 정렬(Sort) 공간 부족시 Temporary tablespace 이용해 정렬

                                        -> 정렬한 데이터를 기반으로 HDD Block에 기록

    -> 인덱스는 데이터가 ""정렬"" 되어 들어간다!!

*/


/*

  3. [ 인덱스 구조와 작동 원리(B-TREE 인덱스 기준) ]

  

    : 테이블(Table)과 인덱스(Index)의 비교

    - 테이블은 컬럼이 여러개, 데이터가 "정렬되지 않고" 입력된 순서대로 들어간다.

                            vs

    - 인덱스(Index)는 컬럼이 "Key컬럼(사용자가 인덱스를 지정하라고 지정한 컬럼)"과 "ROWID컬럼" 두개로 이루어져 있다.

      (오름차순, 내림차순으로 정렬 가능)

*/

select * from emp where empno = 7902; -- 를 찾을 때

/*

  데이터 파일의 블록이 10만개가 있다고 할 때 sql문을 수행한다면,

  1) 서버 프로세스가 구문파싱 과정을 마친 후 DB Buffer 캐시에 empno가 7902인 정보가 있는지를 먼저 확인한다.

  2) 해당 정보가 캐시에 없다면 디스크 파일에서 7902정보를 가진 블럭을 찾아서 DB Buffer 캐시로 가져온 뒤 해당 정보를 사용자에게 보여줌

  이 경우에

    - Index가 없는 경우 -> 7902정보가 디스크 어떤 블럭에 있는지 모름으로 10만개 전부 DB Buffer 캐시로 복사한 뒤 Full Scan으로 찾게 됨.

    - Index가 있는 경우 -> where절의 조건으로 준 컬럼이 Index의 Key로 생성되어 있는지 확인한 뒤, 인덱스에 먼저 가서 7902정보가

                          어떤 ROWID를 가지고 있는지 확인한 뒤 해당 ROWID에 있는 블럭만 찾아가서 db Buffer 캐시에 복사하게 됨.

*/


/*

  4. [ 인덱스의 종류 ]

    1) B-TREE 인덱스(Index)

        : OLTP(Online Transaction Processing : 실시간 트랜잭션 처리)

          -> 실시간으로 데이터 입력과 수정이 일어나는 환경에 많이 사용함.

        

    2) BITMAP 인덱스(Index)

        : OLAP(Online Analytical Processing : 온라인 분석 처리)

          -> 대량의 데이터를 한꺼번에 입력한 뒤 주로 분석이나 통계 정보를 출력할 때 많이 사용함.

          -> 데이터 값의 종류가 적고 동일한 데이터가 많을 경우에 많이 사용함

        

        (1) [ B-Tree 인덱스 ]

          B : binary, balance 의 약자

          

              ROOT block(branch block에 대한 정보)

               |

            Branch Block(Left Block에 대한 정보)

               |

              Leaf Block(실제 데이터들의 주소)

          

        (1-1) [ B-Tree 인덱스의 종류 ]

          (A) Unique Index  

              : 인덱스 안에 있는 컬럼Key값에 중복되는 데이터가 없다.(성능이 좋음)

              -> 마치 Unique 제약조건과 유사하다. 따라서, Unique 제약조건 사용시에도 자동으로 UNIQUE INDEX가 생성된다.

또한, 기본키를 생성해도 오라클은 자동으로 UNIQUE INDEX를 생성하게 되는데 이때 UNIQUE나 기본키 객체명과 동일하게 생성된다. 


              - 생성 방법)

                SQL > create unique index 인덱스명

                      on 테이블명(key로지정할컬럼명 1 ASC|DESC, 컬럼명2...);

                ASC : 오름차순 정렬(기본값)

                DESC : 내림차순 정렬

                

                EX)

                -- dept테이블과 같은 테이블 하나 생성

                SQL > create table dept2 as select * from dept;

               

                -- dname을 key로하는 unique index를 생성

                SQL > create unique index idx_dept2_dname on dept2(dname); 

                -- 튜플 하나 추가

                SQL > insert into dept2 values(50,'개발부','서울');

                -- 위의 추가한 튜플과 dname값이 일치하는 다른 튜플을 하나 추가할라하면 unique인덱스이기 때문에

                -- 에러가 발생한다.

                SQL > insert into dept2 values(60,'개발부','인천');

                -- 이미 들어가 있는 dname이기 때문!!

            

            (B) Non Unique Index 

                : 중복되는 데이터가 들어가야 하는 경움(key로 지정한 필드의 중복된 값이 들어갈 수 있다.)

                

                - 생성 문법)

                SQL > create index 인덱스명 on 테이블명(컬럼명1 ASC|DESC, 컬럼명2....);

                

                EX)

                   -- 테스트용 테이블 새로 생성

                   SQL > create table dept3 as select * from dept;

                

                   -- dname을 Key로하는 Non-Unique index 생성

                   SQL > create index idx_dept3 on dept3(dname);

                 

                   SQL > insert into dept3 values(50,'개발부','서울');

                 

                   -- 중복되는 dname을 가진 튜플이 삽입이 가능하다.

                   SQL > insert into dept3 values(60,'개발부','인천');


            (C) FBI 인덱스( Function Based Index ) : 함수기반 인덱스

              : - 인덱스는 where절에 오는 조건 컬럼이나 조인에 쓰이는 컬럼으로 만들어야 한다.

                - 인덱스를 사용하려면 where절의 조건을 절대로 다른 형태로 가공해서 사용하면 안된다.

                

                예를들자면)

                  where절의 조건이 sal + 100 > 200 이러한 조건일 경우

                  단순히 index컬럼을 sal로만 지정하게 되면 인덱스가 적용되지 않고 검색쿼리가 수행되게 됨

                  -> 따라서, 인덱스도 테이블명(sal+100)의 형태로 "함수기반 인덱스"로 사용해야 함

                  

                  EX)

                    SQL > create index idx_dept_fbi on emp(sal+100);

                    -- 이때, emp테이블에는 sal+100 컬럼은 없지만 인덱스를 만들 때 저 연산을 수행해서 인덱스를 만듬

                    

                    (주의 사항)

                    - 임시적인 해결책은 될 수 있어도 근본적인 처방은 아니다.

                    - sal + 100을 인덱스로 생성했는데 쿼리 조건이 변경되면 인덱스를 다시 생성해야 한다.

                    - FBI는 기존의 인덱스를 활용할 수 없다.(단점)

              

              (D) Descending Index : 내림차순으로 인덱스를 생성한다.

                    : 큰 값을 많이 조회하는 SQL에 생성하는 것이 좋다.

                    ex) 최근 날짜부터 조회, 회사 매출 조회

                    

                    SQL > create index idx_emp_sal on emp(sal desc);

                    

                    (주의사항)

                      : 하나의 메뉴에 오름차순과 내림차순을 한번에 조회할 경우

                      -> 오름차순, 내림차순 두 개의 인덱스를 만들면 DML의 성능에 악영향을 미침

                      -> 이때는, 힌트를 사용한다.(아래나 위에서부터 읽도록 할 수 있다.)

                

              (E) 결합 인덱스(Composite Index) 

                  : 인덱스 생성시에 두개 이상의 컬럼을 합쳐서 인덱스를 생성하는 인덱스

                  -> 주로 where 절의 조건이 되는 컬럼이 2개 이상으로 and로 연결되는 경우 사용된다.

                  -> 잘못 생성하게 되면 성능에 영향을 미칠 수 있다.

                    (컬럼의 순서에 따라 효율에 차이가 있다.) -> 보통, 자주 사용하는 컬럼을 앞에 위치시키는 것이 좋다.

                    

                    생성 방식)

                      SQL > create index 인덱스명 on 테이블명(컬럼명1, 컬럼명2);

                      

                    EX) (성별, 이름) 두개의 컬럼으로 인덱스를 생성하는 경우

                      SQL > create index idx_emp_composite on emp(gender,dname);

                      

                      -- 생성된 인덱스는 정렬되어 데이터를 저장시키게 되는데

                      -- 이때, 인덱스 생성시 기술한 컬럼순으로 정렬이 된다. 

                      -- 즉, gender(성별)을 기준으로 asc로 정렬한 뒤 같은 성별일 때

                      -- dname을 asc로 정렬해 인덱스를 생성하는 것

                      

                      -- 생성된 인덱스가 어떤 모습으로 저장되어 있는지 검색해 보자.

                      EX) emp테이블의 empno와 deptno 두개의 컬럼을 조건으로 하는 인덱스 생성

                          SQL > create table emp3 as select * from emp;

                          SQL > create index idx_emp3_composite on emp3(deptno,empno);

                          

                          -- 정렬된 상태로 저장되어있는 인덱스 모습을 보기

                          SQL > select * from emp3 where empno > 0 and deptno > '0';

                        


                          

                          -- 이때, 검색 쿼리가 deptno가 20이면서 empno가 7902인 사원정보를 검색한다면

                          SQL > select * from emp3 where deptno = 20 and empno = 7902;

                          

                          -- 인덱스 생성시 dept 컬럼을 앞에 기술했기 때문에 dept=20을 먼저 찾기위해

                          -- 4번 검사를 하고 이때 20이 나옴으로 empno 7369검사(1번) 다음 deptno 검사 1번

                          -- 다시 empno 검사(1번) 식으로해서 최종 찾는 데이터까지

                          -- 총 9번의 검사를 해 찾게된다.

                          

                          -- 이런식으로 검사가 이루어지기 때문에 주의할 사항이 생기는데

                          (deptno, empno)로 생성할지 (empno, deptno)로 생성할지에 따라 검사 효율이 다르게 나타날 수 있다.

                          

                          이때는 평균적인 검사 효율을 어느정도 계산을 해 바서 인덱스를 생성하는 것이 중요하다!!(신중히 생성하자)

       

       

        (2-1) [ BITMAP 인덱스의 종류 ]

            : 데이터 값의 종류가 적고 동일한 데이터가 많을 경우에 많이 사용된다.

            

            Bitmap Index를 생성하려면 데이터의 변경량이 적어야 하고, 값의 종류도 적은 곳이 좋다.

            일반적으로 OLAP환경에서 많이 생성하게 되는대

            

            Bitmap Index는 어떤 데이터가 어디에 있다는 지도정보(MAP)를 Bit로 표기하게 된다.

            데이터가 존재하는 곳은 1로 표시하고, 데이터가 없는 곳은 0으로 표기한다.

            정보를 찾을 때 1인 값만 찾게 된다!

            

            SQL > create bitmap index 인덱스명 on 테이블명(컬럼);

            

            bitmap index를 생성하면 성별 컬럼 값의 종류대로 map이 생성된다.

            남자 : 1 0 1 0 0 -> 남자데이터가 1,3번 튜플에 있다.

            여자 : 0 1 0 1 1 -> 여자데이터가 2,4,5 튜플에 있다.

            

            이때 문제되는게

            bitmap index사용하고 있는 상태에서 만약 컬럼 값이 새로 하나 더 생긴다면?

            기존의 Bitmap Index를 전부 수정해야한다.

            

            -> B-Tree Index는 관련 블럭만 벽여되지만 Bitmap Index는 모든 맵을 다 수정해야 한다는 문제점!

            -> Bitmap Index는 블럭 단위로 lock을 설정해서 같은 블럭에 들어있는 다른 데이터도 수정작업이 안되는 경우가

               종종 발생한다.

                       

*/


/*

  5. [ 인덱스 주의사항 ]

    

    - 인덱스를 사용하면 무조건 효율이 좋을까? NO

   

    -> [ 인덱스는 DML에 취약 ]

    근거)

      1) INSERT 작업의 경우

        : "index split"현상이 발생할 수 있다.

        - Index Split이란? : 인덱스의 Block들이 하나에서 두개로 나누어지는 현상

        -> 인덱스는 데이터가 순서대로 정렬되어 저장되게 되는데, 기존 블럭에 여유 공간이 없는 상황에서

           그 블럭에 새로운 데이터가 입력되어야 하는 경우

           오라클은 기존 블럭의 내용 중 일부를 새 블럭에다가 기록한 다음 기존 블럭에 빈 공간을 만들어서

           새로운 데이터를 추가하게 된다.

           --> 따라서, 성능면에서 매우 불리하다.

           a)Index Split은 새로운 블럭을 할당 받고 key를 옮기는 복잡한 작업을 수행

           b)Index Split이 이루어지는 동안 해당 블럭에 대해 키 값이 변경되면 안되므로 DML이 블로킹된다.

            enq:TX-index contention 대기 이벤트 발생(RAC-gc current split)

      

      2) DELETE 작업의 경우

        : 일반적인 테이블에서 데이터가 delete될 경우 해당 위치 데이터가 지워지고 그 공간을 사용 가능하다.

                        vs

          하지만, Index에서 데이터가 delete될 경우 -> "데이터는 지워지지 않고, 사용하지 않는다는 의미의 표시만 해두게 된다!"

            --> 즉, 테이블에 2만건의 데이터가 있었는데 1만건을 삭제해도 Index에는 데이터가 2만건이 존재한다는 말이된다.

            -> 인덱스를 사용해도 수행속도를 기대하기는 힘들다.

            

      3) UPDATE 작업의 경우

        : 인덱스에는 UPDATE란 작업이 존재하지 않기 때문에

          기존의 데이터를 DELETE한 다음 새로운 값의 데이터를 INSERT하는 두번의 과정으로 작업이 발생하는데

          따라서, 다른 DML작업보다 더 큰 부하를 주게 된다.

   


[ 최종적으로 인덱스 생성시 고려해야할 사항 ]


1 일반적으로 테이블 전체 로우 수의 15%이하의 데이터를 조회할 때 인덱스를 생성한다.


2 테이블 건수가 상당히 적다면 굳이 인덱스를 만들 필요가 없다. -> 테이블 건수가 적으면 인덱스를 경유하기보다 테이블 전체를 스캔하는 것이 더 빠르다.


3 인덱스 생성시 컬럼은 유일성 정도가 좋거나 범위가 넓은 값을 가진 컬럼을 지정하는 것이 좋다. (NULL값을 많이 갖는 컬럼은 피하는 것이 좋다.)


4 결합 인덱스 생성시에는 컬럼의 순서가 중요하다.

-> 보통, 자주 사용하는 컬럼을 앞에 지정한다.


5 테이블에 만들 수 있는 인덱스의 수는 제한이 없으나, 너무 많이 만들면 오히려 성능 부하가 발생한다.

why? -> 인덱스 생성을 해 놓으면 해당 테이블에 DML 작업(insert, delete, update)시 인덱스에도 수정작업이 동시에 발생하기 때문에 과도하게 많은 인덱스를 생성해 놓으면

오히려 성능 부하가 걸릴 수 있다.

-> 일반적으로, 테이블 당 최대 5개를 넘지 않는 것이 좋다.


6 데이터의 검색보다 수정, 삭제, 삽입 작업이 빈번한 테이블에는 인덱스를 생성하지 않는 것이 좋다.

-> 인덱스는 DML작업에는 성능이 좋지 않기 때문에 검색을 위주로 하는 테이블에 생성하는 것이 좋다.(위에서 언급한 성능 이슈들이 발생할 수 있다.)


7 인덱스 생성시 무엇보다 가장 중요한 점은 SQL 쿼리가 인덱스를 잘 활용할 수 있게끔 짜여져야 한다는 것이다.(쿼리를 잘 짜서 만들자!)       

*/

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


  [ 인덱스의 활용,관리의 예 ]

  
  1. [ 인덱스를 조회하기 위한 딕셔너리 ]
    - user_indexes, user_ind_columns
    - dba_indexes, dba_ind_columns


-- DEPT2 테이블에 적용된 인덱스 검색 방법(user_indexes 딕셔너리에서)
select table_name, index_name
from user_indexes
where table_name = 'DEPT2';

-- EMP 테이블에 적용된 인덱스 검색
select table_name, index_name
from user_indexes
where table_name = 'EMP';

-- [index를 rebuild하는 방법]
  -- 인덱스는 한번 만들어 놓으면 영구적으로 좋은 성능을 가질수 없기 때문에
  -- 항상 관리를 해주어야 한다. 그 방법이 rebuild 하는 것이다.
  
  -- 테스트용 테이블 생성
  create table test_rebuild(
    no number
  );
  -- 테스트용 데이터 1000개 넣기
  begin
    for i in 1..1000 loop
      insert into test_rebuild values(i);
    end loop;
  end;
  /
  commit;
  -- 들어간 데이터 확인
  select * from test_rebuild;
  
  -- 인덱스 생성
  create index idx_test
  on test_rebuild(no);
  
  -- 인덱스의 상태 조회
  analyze index idx_test validate structure; --인덱스 상태를 분석함
  
  -- 인덱스 분석 쿼리를 수행하면 index_stats 딕셔너리에 해당 결과가 반영되게 된다.
  -- 또한,  
  -- 테이블 데이터 삭제시 인덱스에는 삭제되지 않고 사용하지 않는다는 표시만 해 두는대
  -- 이때, 관리가 필요함 따라서, 인덱스에 삭제상태로 표시한 데이터가 몇개 있는지(DEL_LF_ROWS_LEN)를
  -- index_stats 에서 조회하는데
  -- 아래 구문은 삭제한데이터/총있는데이터 비율을 구한다.
  select (DEL_LF_ROWS_LEN / LF_ROWS_LEN) * 100 AS balance
  from index_stats;
  -- 0이 나온다면 좋은 상태임을 알 수 있다.
  
  -- 그럼, 데이터를 삭제해 보자.
  delete from test_rebuild where no between 1 and 400; -- 1 ~ 400까지 데이터 삭제
  -- 남은 데이터 개수 : 600개
  select count(*) from test_rebuild;
  
  -- 다시한번 인덱스 분석을 해 주어야 함 index_stats에 반영될 수 있도록...
  analyze index idx_test validate structure;
  
  -- 39.6~~~%가 나오게 됨 -> 40%정도가 인덱스의 균형이 좋지 않다는 것을 의미함.
  select (DEL_LF_ROWS / LF_ROWS) * 100 AS balance
  from index_stats;
  
  select * from index_stats;
  select DEL_LF_ROWS from index_stats; -- 400
  
  select LF_ROWS from index_stats; -- 1000
  
  -- 40%를 성능을 위해 수정하기 위해선 rebuild 작업이 필요하다.
  alter index idx_test rebuild; -- rebuild 명령으로 인덱스를 수정한다.
  
  -- 다시 분석해서 보면
  analyze index idx_test validate structure;
  select (DEL_LF_ROWS / LF_ROWS) * 100 AS balance from index_stats; -- 0이 나오게 됨
  
  -- 이처럼 인덱스는 rebuild를 통해 꾸준히 관리가 필요하다.
  
  
  -- [ 인덱스 활용 예 ]
  create table emp3(
    no number,
    name varchar2(10),
    salary number
  );
  
  insert into emp3 values(1, '강호동', 200);
  insert into emp3 values(2, '이경규', 300);
  insert into emp3 values(3, '이경실', 100);
  insert into emp3 values(4, '유재석', 400);
  insert into emp3 values(5, '홍길동', 150);
  insert into emp3 values(6, '홍길자', 250);
  
  select * from emp3;
  
  -- index 생성
  create index idx_name
  on emp3(name);
  
  -- where절 조건으로 인덱스 컬럼으로 지정한 name을 쓰지 않았음으로 인덱스를 거치지 않고
  -- 결과가 나오기 때문에 정렬이 되어 있지 않고 출력되게 된다.
  select name from emp3;
  
  -- where절에 name조건을 주었기 때문에 인덱스를 거쳐 정렬된 상태로 나오게됨
  select name from emp3 where name > '0'; -- 이처럼, order by 효과를 대신할 수 있음
  
  -- order by시에도 정렬을 위한 수행 시간이 필요한대 인덱스를 활용하면 이러한 시간을 
  -- 줄일 수 있다.
  
  -- [인덱스를 활용해서 최소값을 구해보자]
  
  -- 먼저 index를 쓰지 않고 찾아오는 방식
  select min(name) from emp3; -- 내부적으로 정렬을 한번해서 찾아오게 됨 0.04초 걸렷음.
  
  -- 인덱스를 쓴 경우
  select name from emp3 where name > '0' and rownum = 1; -- 정렬이 발생하지 않고
  -- 가져올 수 있기 때문에 상당히 빠름 -> 0초로 찍힘
  
  -- 최대값도 해보자.
  select max(name) from emp3; -- 인덱스 사용하지 않은 경우 0.002초(정렬이 먼저 발생하기 때문)
  
  -- 인덱스의 hint를 사용해 최대값을 구해오는 방법
    -- hint? : 
    -- 아래의 경우는 실행계획을 담당하는 옵티마이저에게 ~~게 할거라고 알려주는 건대
    -- 즉, 기본적으로는 asc지만, desc로 지정해 가장 큰 값이 위로 올라와 있게 되기 때문에
    -- rownum = 1을 통해 최대값을 가져올 수 있게된다.
  select /*+ index_desc(emp3 idx_name)*/ name
  from emp3
  where name > '0' and rownum = 1;
  
  -- rownum없이도 구해올 수 있는 방법(위의 방법은 인덱스가 수정되는 과정에서 문제가 발생할 수 있음)
  -- 이 방식을 -> "first_row max방법" 이라 부른다.
  select /*+ index_desc(emp3 idx_name)*/ max(name)
  from emp3
  where name > '0';
  
  
  -- 사용하지 않는 인덱스의 경우 삭제하는게 좋다.(주의사항에서 언급되어 있다.)
  -- 이렇게 삭제시 정말 사용하지 않을건지 알고 삭제하는 것이 중요한데
  -- 11g 버전에서는 사용하지 않는 상태로 만들어서 테스트 해볼 수 있도록 제공하는데
  -- invisible 인덱스란 개념을 제공한다.
    -- : 인덱스를 삭제하기 전에 사용안함 상태로 만들어 테스트 할 수 있는 기능.
  
  -- salary 컬럼으로 emp3테이블의 인덱스 생성
  create index idx_sal on emp3(salary);
  
  select table_name, index_name, visibility 
  from user_indexes
  where table_name = 'EMP3';
  
  -- 인덱스를 사용안함 상태로 바꾸기
  alter index idx_sal invisible;
  -- 다시 조회하면 invisible상태로 바껴있음을 알 수 있음.
  -- 실행계획을 세우는 옵티마이저가 해당 인덱스를 사용하지 않겠다는 의미
  -- 하지만, 인덱스가 지워진건 아니고 보여지지 않은 것과 같은 효과란 것
  select table_name, index_name, visibility 
  from user_indexes
  where table_name = 'EMP3';
  
  -- 다시 visible 상태로 바까보기
  alter index idx_sal visible;
  
  



[ 적용한 트리거의 활성화/비활성화 설정 방법 ]

Alter Trigger 트리거명 ENABLE|DISABLE

  [ 패키지 ]


  : 연관성이 있는 함수나 프로시저를 그룹으로 모아놓은 개념.
  

  [ 패키지 구성 ]
  : 선언부 + 몸체부
  
  **참고로 패키지 선언부에 선언되지 않아도 패키지 몸체부에서
    사용할 수 있다... BUT 권장사항이 아니다.
    
  [ 구문 형식 ]
  - 선언부 형식
  create (or replace) package 패키지명
  IS
    패키지 내 전역 변수 선언;
    procedure 프로시저1(매개변수1,...);
    procedure 프로시저2(매개변수1,...);
    function 함수1(매개변수1,..2)return 타입;
    ...
  end;
  - 몸체부 형식
  create (or replace) package body 패키지명
  IS
  procedure 프로시저 이름
  subprogram bodis : 실제 작동하게될 서브프로그램(프로시저, 함수)
  end;
  
  *패키지 실행 : 패키지는 여러 환경에서 호출되어 실행가능하다.
              패키지에 대한 실행권한을 가진 사용자만 실행시킬 수 있다.
exec 패키지명.프로시저or함수명;
select 패키지명.함수명(매개변수) from ~~
  *패키지 삭제 : 선언부와 몸체부를 모두 삭제할 수 있다. 또는 몸체만 삭제할 수도 있다.
      drop package 패키지명; -- 둘 다 삭제할 경우
      drop package body 패키지명; -- 몸체만 삭제할 경우


- 패키지 내에 전역 변수를 선언하고 해당 변수를 사용할 경우 초기화 작업이 필요한 경우가 있다.
  이런 경우를 지원하기 위해 
  패키지.프로시저 or 함수를 수행할 때 마다 한번 무조건 실행하게 해 초기화 작업등을 할 수 있도록 지원하는 것이 있는데
  이를 ONE_TIME_ONLY_PACKAGE 라고 한다.
 
  방식은, 단순히 패키지 바디의 맨 아래 부분에 BEGIN을 기술하고 초기화 작업등을 해주면 된다.


[ 서브프로그램의 함수 사용 ]


  
  서브프로그램
    - 프로시저
    - 함수
    
    [ 함수와 프로시저의 차이? ]

    - 프로시저는 in, out, in out모드를 사용해서 값을 반환하기도 하고,
      반환하지 않고 종료 할 수도 있다.
      VS
    - 함수는 어떤 작업을 수행한 후에, 결과를 반환한다.

    
    [ 함수의 구문 형식 ]
    create (or replace) function 함수명
    파라미터1 파라미터타입,
    파라미터2 파라미터타입,...
    return datatype
    is
    PL/SQL 블럭;

EX)





 [ 서브프로그램의 이해, 프로시저 ]


  : PL/SQL의 서브프로그램이란?
    -> <PL/SQL의 익명 블럭의 특징>
      : . 이름이 없는 PL/SQL 블럭
        . 저장해서 사용되지 않는다.
        . 사용할 때마다 컴파일이 필요하다.
        . 다른 응용프로그램에서 사용할 수 없다.
        . 값을 반환할 수 없다.
        . 매개변수를 사용할 수 없다.
        
    -> <서브프로그램의 특징>
      : . 이름이 있는 PL/SQL 블럭
        . DB에 저장해 반복적으로 사용할 수 있다.
        . 최초 실행될 때 한번만 컴파일 한다.
        . 다른 응용프로그램에서 사용할 수 있다.
        . 함수일 경우 값을 리턴(반환)할 수 있다.
        . 매개변수를 사용할 수 있다.
        
      ** "서브 프로그램"은 내장된 함수프로시저가 있다.
        - 프로시저
        - 함수
      ---------------------------------------------------------------------
      
      - 프로시저란??
        : 특정 처리를 위한 서브 프로그램의 한 유형이다.
        : 단독으로 실행 가능하며, 다른 응용 프로그램에서도 호출되어 실행 가능하다.
        
        - 프로시저 구문 형식)
          create procedure 프로시저명
            파라미터1(in,out,in out) 데이터타입, -- default는 in모드
              -- out : 값을 반환하겠다, in : 서브프로그램 내에 값 전달 in out : 서브프로그램 내에도 전달되고, 외부 응용프로그램에도 반환하기도 함
            파라미터2(in,out,in out) 데이터타입
          is
            변수 선언부;
          begin
            프로시저 본문 처리부;
          exception
            예외처리부;
          end;

EX)


[ 외부 변수 선언 및 전달과 out 타입을 통한 결과값 받기 예제 ]


[    ORACLE 예외처리 개념, 종류, 사용법 - (8)    ]




  - 에러 의 종류 ]
      1. 컴파일 에러 : PL/SQL 블럭이 파싱(Parsing)될 때 "사용자 오타" 등으로 인해 발생되는 에러.
        (Compile Error)
      2. 런타임 에러(=Exception)
          : PL/SQL 블럭이 실행되는 동안 발생하는 에러로 일반적으로 런타임에러를 "Exception"이라 부른다.
            종류)
              a. 오라클 예외 
                  : 오라클에서 제공되는 예외(Predefined ORACLE Exception과 Non-Predefined ORACLE Exception이 있다.)
                    ㄱ. Predefined ORACLE Exception 
                          : 사전에 정해진 예외
                          종류)
                            - ACCESS_INTO_NULL 
                                : 정의되지 않은 오브젝트 속성에 값을 할당하고자 했을 때 발생하는 예외.                      
                            - CASE_NOT_FOUND 
                                : CASE문의 when절에 해당되는 조건이 없고 else절도 없을 경우 발생
                            - COLLECTION_IS_NULL 
                                : 선언되지 않은 컬렉션(nested table, varray)에 존재하는 메서드
                                                   이외의 메서드를 사용했을 때 발생되는 예외.
                            - CURSOR_ALREADY_OPEN 
                                : 이미 열려진 커서를 열려고 시도 했을 때 발생하는 예외
                            - DUP_VAL_ON_INDEX 
                                : 유일인덱스에 중복값을 입력햇을 때 발생하는 예외.
                            - INVALID_CURSOR 
                                : 잘못된 커서 조작이 샐행될 때 발생되는 예외.
                            - INVALID_NUMBER 
                                : 문자를 숫자로의 변환 시 실패가 될 때 발생하는 예외.
                            - LOGIN_DENIED 
                                : 잘못된 사용자명이나 암호로 로그인시도시 발생하는 예외.
                            - NO_DATA_FOUND 
                                : PL/SQL Select문이 한 건도 리턴하지 못하는 경우 발생하는 예외.
                            - NOT_LOGGED ON 
                                : 접속되지 않은 상태에서 데이터베이스에 대한 요청이 PL/SQL 프로그램으로
                                  실행된 경우 발생되는 예외.
                            - PROGRAM_ERROR 
                                : PL/SQL이 내부적인 문제를 가지고 있는 경우 발생되는 예외.
                            - ROWTYPE_MISMATCH 
                                : 할당문에서 호스트 커서 변수와 PL/SQL 커서 변수의 데이터 형이 불일치할 때 발생되는 예외
                            - STORAGE_ERROR 
                                : PL/SQL이 실행될 때 메모리가 부족하거나 메모리상에 문제가 일어났을 대 발생하는 예외.
                            - SUBSCRIPT_BEYOND_COUNT 
                                : 컬렉션의 요소 갯수보다 더 큰 첨자 값으로 참조한 경우 발생
                            - SUBSCRIPT_OUTSIDE_LIMIT 
                                : 컬렉션의 첨자 한계를 벗어난 참조가 일어났을 때 발생
                            - SYS_INVALID_ROWD 
                                : 문자열을 ROWID로 변환할 때 무효한 문자열의 표현일 경우 발생되는 예외.
                            - TIMEOUT_ON_RESOURCE 
                                : 자원에 대한 대기시간이 초과했을 때 발생하는 예외.
                            - TOO_MANY_ROWS 
                                : PL/SQL select문이 두건이상의 행을 리턴햇을 때 발생되는 예외.
                            - VALUE_ERROR 
                                : 산술,변환,절삭 크기 제약에 에러가 생겼을 때 발생되는 예외.
                            - ZERO_DIVIDE
                                : 0으로 나누려 했을 때 발생하는 예외.
                  
                    ㄴ. Non-predefined ORACLE Exception
                          : 사전에 정해지지 않은 예외
              b. 사용자 정의 예외
                  : 사용자에 의해 정의되는 예외
                    사용자 정의 예외 사용 예)
                      declare (선언부에서)
                      예외명 exception;
                      begin부나 exception부에서 raise문을 이용해서 예외를 발생시킨다.
                      
                      - 예외처리부 형식)
                          -- 예외처리부 : 예외 발생시 어떻게 처리할 것인지에 예외처리 내용이 들어간다.
                        Exception
                          when 예외명 then
                            실행문...
                          when 예외명2 then
                            실행문...
                          when OTHERS then
                            실행문...

EX)


[    ORACLE 커서(CURSOR)    ]




 [  커서  ]
  : select문을 통해 결과값들이 나올 때 이 결과들은 메모리 공간에 저장하게 되는데
  
    이때, 이 메모리 공간을 "커서"라고 한다.
    
    즉, 
      - 커서란? : 쿼리문에 의해서 반환되는 결과값들을 저장하는 메모리 공간이다.
      - Fetch란 : 커서에서 원하는 결과값을 추출하는 것.
    
    왜사용하는가???!!  
커서는 로우를 기반으로 하는 작업이 된다!!! 라는 것입니다. 저러한 로우를 하나 SELECT해서 여러가지 처리를 한후 어떠어떠한 작업을 한다~~
           
이것을 가능하게 하는 것이 바로!!! 커서 입니다.
      
     물론 SQL구문만을 가지고 어거지로 어찌어찌 한다면~~ 가능할 겁니다.
        
     하지만 커서를 이용하시면 훨씬 빠르고 간단히 저러한 처리를 가능하게 할 수 있습니다.
    
여기까진 이론적으로고... 그냥 근본적으로는

-> select의 결과가 하나의 행(단일 튜플)일 경우는 into절을 이용해 변수에 저장할 수 있지만, 결과가 복수행(복수 튜플)일      경우는 into절로 이를 처리할 수가 없죠
    이렇게 여러 복수 행의 결과를 행단위로 처리를 하기 위해서 사용하는 것이 Cursor입니다.
   

1. 커서의 정의
 

커서란 SQL Plus에서 사용자가 실행한 SQL문의 단위를 의미합니다.


오라클에서 수행한 모든 쿼리문은 커서 단위로  처리합니다.

PL/SQL의 SQL문처럼 하나의 결과를 리턴하는 경우 커서 없이도 SQL문의 실행결과가 암시적으로 커서에 저장되므로 이를 암시적 커서라고 합니다.
 

SQL문을 수행한 후에 결과로 얻어지는 행이 여러 개일 경우에는 암시적은 커서에 정보를 저장할 수 없기에 에러가 발생합니다. 이럴 경우에는 반드시 명시적인 커서를 사용해야 합니다.


명시적인 커서는 PL/SQL 레코드(RECORD)와 PL/SQL의 테이블(TABLE)을 결합한 것으로서 프로그램 언어의 구조체 배열과 유사합니다

------------------------------------------------------------------------------------------------------
(오라클에서 CURSOR란 시스템 글로벌 영역의 공유 풀 내에 저장공간을 사용하여 사용자가 SQL 문을 실행시키면 결과값을 저장공간에 가지고 있다가 원하는 시기에 순차적으로 fetch해 처리하여 해당 결과 셋을 프로그래밍적으로 

접근할수 있게 도와주는 기능이다.)

   
      [ 커서의 종류 ]
      1. 묵시적 커서(Implicit Cursor)
        : 오라클에서 자동으로 선언해주는 SQL 커서.(사용자는 생성 유무를 알 수 없다.)
        
      2. 명시적 커서(Explicit cursor)
        : 사용자가 선언해서 생성한 후에 사용하는 SQL 커서, 주로 여러개의 행을 처리하고자
          할 경우 사용한다.
        
      [ 커서의 속성 ]
      1. %Found : 가져올 레코드가 있는 경우 true를 반환
      2. %isOpen : 커서가 오픈 상태일 경우 true를 반환
      3. %NotFound : 더이상 참조할 레코드가 없을 때 true를 반환
      4. %RowCount : 카운터 역할을 한다. 처음 오픈시 0, 패치발생할 때마다 1씩 증가
      
      [ 커서의 처리 단계 ](명시적 커서 기준)
      1. 명시적 커서 선언(커서 생성)
        EX) Cursor 커서이름
      2. 명시적 커서 오픈
        EX) Open 커서이름
      3. 커서에서 데이터 추출(데이터 행 가져오기)
        EX) Fetch 커서이름
      4. 커서 종료
        EX) Close 커서이름



[    ORACLE 반복문(basic loop, while, for, continue)    ]





[    ORACLE 조건문(IF,CASE)    ]






[    ORACLE TABLE TYPE(컬렉션), 바인드 변수 -(4)    ]



쿼리의 일부분 예를 들어 WHERE 절의 내용만 다른 쿼리를 실행해야 하는 경우가 종종 생길 것이다. 이러한 경우에 거의 비슷한 두번의 쿼리를 실행하는 비효율성을 해소하는 방법이 바로 바인드 변수의 사용이다.
바인드 변수는 입력 내용을 넣고 SQL로부터 출력 내용을 받아내는 방법으로, " 이 부분에 들어갈 정확한 값은 이후에 알려줄테니, 일단 내가 값을 넣었을 때 어떻게 실행할 것인지에 대해서 계획만 세워둬라 "는 명령을 오라클에 내리는 것이다.

select * into temp from row_test where no = :bind_no; 이 부분이 있을 때 :가 붙은 변수가 바인드 변수인대, 실행한 뒤에 바인드 변수에 입력할 값을 넣게 된다.
그에 따라 no = 1, no = 2 등 실행할 때마다 다양한 결과를 낼 수가 있게 된다.


[    ORACLE rowType 변수 및 복합변수 활용 예    ]



[    ORACLE PL/SQL 개념 - (1)    ]





[ PL/SQL(Procedural Language/SQL) ]

  : 오라클에서 제공하는 프로그래밍 언어
  : 일반 프로그래밍 언어적인 요소를 다 가지고 있고, 
    데이터베이스 업무를 처리하기 위한 최적화된 언어
    
    
    
   ** [ 프로시저(PL)의 기본 구조 ] **
   
     - 선언부(Declare) : 모든 변수나 상수를 선언하는 부분
     - 실행부(Executable) : BEGIN ~ END // 실재 로직이 수행되는 부분 
          ex) 제어문, 반복문, 함수정의 등의 로직을 기술하는 부분...
     - 예외처리부(Exception) : 실행도중에 에러 발생시 해결하기위한 명령들을 기술하는 부분
       (생략가능)
       
      ** Declare, begin, exception 키워드들은 ';' 을 붙이지 않는다. **
      ** 나머지 문장들은 ';'으로 처리하여 영역의 긑을 표시한다.
      
      
     - 익명 블록(Anonymous PL/SQL)
          : 주로 일회성으로 사용할 경우 많이 사용된다.
          
     - 저장 블록(Stored PL/SQL)
          : 서버에 저장해 놓고 주기적으로 반복해서 사용할 경우 사용된다.

EX)


[    ORACLE 뷰(View) & 인라인 뷰   ]





[ 인라인(Inline) 뷰(View) 란? ]

: select의 from절에 테이블이 바로 오는 것이 아니라, select절이 오는 방식


왜 사용할까?

-> 서브쿼리를 포함해 테이블 조인이 이루어질 경우 검색하는 필드명은 테이블.필드명처럼해서 길어지게 된다. 이게 서브쿼리를 통해

메인 쿼리로 올라갈 수록 그 길이는 점점 더 길어져 불편할 수 있는데

이때, from절에서 select문을 통해 추출한 필드명에 Alias를 줘서 간단하게 만들 수 있다.

이러한 목적 이외에도 예를들어, 전체 데이터에서 비교하는 것보다 rownum을 이용해서 10번째 튜플 정보만 가져와 그 중에서 조건을 따져 데이터를

가져온다면 비교하는 횟수가 줄어들게 할 수도 있다.

이때, rownum을 통해 가져오는 갯수를 제한하는 방식을 N-TOP 질의라고 한다.

EX)     select 사원명, 부서명 from ( select e.ename AS 사원명, d.dName AS 부서명 from emp e, dept d where e.deptno = d.deptno

where rownum <= 10

order by e.sal

);





'스터디 > DB(ORACLE)' 카테고리의 다른 글

ORACLE PL/SQL 개념 - (1)  (0) 2017.09.11
ORACLE 시퀀스(sequence)  (0) 2017.09.08
ORACLE 무결성 제약조건  (0) 2017.09.07
ORACLE DML( insert, update, delete, select )  (0) 2017.09.06
ORACLE DDL( create, drop, alter, truncate )  (0) 2017.09.06
[    ORACLE 무결성 제약조건    ]





[   ORACLE DML( insert, update, delete, select )   ]




--DML : Data Manipulation Language : ( select, insert, update, delete )

-- 1. select 문 : 데이터 검색
      -- 형식) select 컬럼 from 테이블 where 조건들.. group by having order by ...

-- 2. insert 문 : 데이터 삽입(튜플 삽입)
      -- 형식)

 - 단일행을 삽입하는 경우 : insert into 테이블(컬럼1,컬럼2,...) values(값1,값2,...)
 - 복수행을 삽입하는 경우 : insert into 테이블(컬럼1,컬럼2...) (select 컬럼1,컬럼2,... from ~ where ~);
      
-- 3. update 문 : 데이터 수정 
      -- 형식) update 테이블 set 컬럼1=값1 where 조건들...      

-- 4. delete 문 : 데이터 삭제(튜플 삭제)
      -- 형식) delete from 테이블 where 조건
      
delete * from 테이블명; 과 Truncate Table 테이블명과의 차이점?

: delete를 수행시 자동으로 commit이 이루어 지지 않기 때문에 rollback을 할 수 있지만
  
  truncate의 경우 데이터를 삭제 후 자동으로 commit까지 진행하기 때문에 rollback을 할 수 없다.



[   ORACLE 서브쿼리ANY,ALL,IN에 대하여...  ]




메인 쿼리 안에서 메인 쿼리의 중간 결과로 사용되는 쿼리문을 "서브쿼리"라고 하는데,

서브 쿼리를 작성할 때 고려해야할 점은, 서브쿼리의 결과값이 단일 튜플이 나올 수도 있지만 다중 튜플일 경우이다.

일반적으로 salary(급여)가 (13000,6000,7000) 이 중 하나인 경우( salary = 13000 or salary = 6000, salary = 7000 )는

간단하게 salary IN (서브 쿼리) 로 "IN"을 사용해 작성하면 되지만

">"와 같은 연산자는 IN을 사용할 수가 없는 단일 비교 연산자이다. 이러한 경우에는 ANY ALL을 사용하게 된다.

ANY는 해당 비교 연산의 or결과로 ALL은 and 결과로 연산이 되는데 예를들자면

salary > ANY(다중 튜플을 결과로하는 서브쿼리) 는 

salary > 13000 or salary > 6000 or salary > 7000 의 결과가 된다. 즉, salary > 6000을 만족하는 결과들이 될 것이고,

salary > ALL(다중 튜플을 결과로하는 서브쿼리) 는

salary > 13000 and salary > 6000 and salary > 7000의 결과임으로, salary > 13000 을 만족하는 결과가 나올 것이다.



다음 아래는 해당 내용에 대한 예제 코드와 주석문이다.



[    ORACLE 날짜함수, 변환함수, decode(), case()  ]  






+ Recent posts