2010. 9. 1. 13:53

(unix)shell script 예제


/var/log/messages* 화일에서

aaa 라는 문자열이 들어간  행만 뽑아 화일1로 저장하고

그중 8번째 필드값만 추출하는데 데이타가 겹치는 경우가 있어  (중복된 값은 제거) 하고 

화일2로 저장

 

 

grep aaa /var/log/messages* >file1

awk '{print $8}' file1 | sort | uniq >file2

 

두개의 구문을 아래와 같이 한 줄로 실행할 수도 있습니다.

grep aaa /var/log/messages* | awk '{print $8}' | sort | uniq >file2

2010. 9. 1. 13:51

(oracle)오라클 PL/SQL은 무엇인가?

PL/SQL은 무엇인가?

- PL/SQL(Procedural Language/SQL)의 약어
- 오라클 DB 환경에서 실행되는 절차적인 데이터베이스 프로그래밍 언어
- 표준 SQL과 3세대 언어의 강력한 일부 기능을 포함한 SQL의 확장 언어
- PL/SQL에서는 프로그램 단위를 블록(block)이라 부르며, 애플리케이션 로직들을 작성

그림 8.1 SQL문과 PL/SQL 블록의 실행 비교




■ 오라클 환경에서 PL/SQL을 학습하는 이유

▪ 오라클 개발 도구를 수행하는 모든 프로그래밍의 기초
▪ 클라이언트가 아닌 서버 상에서 프로세스를 수행하는데 PL/SQL을 사용함
▪ PL/SQL을 사용하면 업무 규칙이나 복잡한 로직을 캡슐화(Encapsulation)할 수 있어, 모듈화(Modularity)와 추상화(Abstraction)가 가능
▪ 데이터베이스 트리거를 통하여 데이터베이스 무결성을 제약하는 복잡한 규칙의 코딩과 변경 내역, 데이터를 복사
▪ PL/SQL은 독립적인 플랫폼 수준을 제공

■ PL/SQL에서 제공하는 명령문은
    ▪ 모든 SQL문
    ▪ 변수 및 상수 등의 선언문
    ▪ 대입문
    ▪ 조건 판단문
    ▪ 제어 흐름문
    ▪ 반복 처리문

■ PL/SQL로 작성할 수 있는 것은?

   ▪ SQL*Plus 스크립트(scripts)
   ▪ 프로시저(Procedure), 함수(Function) 서브프로그램
   ▪ 패키지(Package)
   ▪ 데이터베이스 트리거 (Database Trigger)
   ▪ 애플리케이션 로직 (Application Logic)

8.2 PL/SQL의 기본 블록 구조
    - PL/SQL의 프로그램 단위는 블록(Block)


    DECLARE    선택       변수와 상수, 프로시저와 함수 서브프로그램,
                                   커서 등을 선언
          선언문
           .....

     -----------------------------------------------
     BEGIN          필수     처리할 명령문들을 절차적으로 기술
                                    ▪ 모든 SQL문
          실행문                 ▪ 대입문, 반복 처리문, 조건 판단문, 제어 흐름문
          .....                     ▪ 커서 처리문

     -----------------------------------------------
     EXCEPTION   선택      오류 처리에 관한 예외처리 명령문을 기술
    
         예외처리문
         .....

    -----------------------------------------------
     END;              필수

/


그림 8.2  PL/SQL의 기본 블록 구조


8.3 PL/SQL의 블록 작성 및 실행

8.3.1 PL/SQL 블록의 작성

     ▪ ‘무엇을 어떻게 처리할 것인가?’를 분석
  ▪ DECLARE를 기술하고, 블록에서 필요한 변수나 상수, 서브 프로그램, 커서 등을 문법에 맞추어 한 줄에 하나씩 기술
  ▪ BEGIN을 기술하고, 절차적인 실행 순서에 의하여 명령문을 기술
  ▪ EXCEPTION을 기술하고, 실행절에 기술된 명령문이 실행될 때 발생될 수 있는 오류에 대한 예외처리문을 기술
  ▪ 마지막으로 END;을 기술
  ▪ PL/SQL 블록에서 한 문장이 종료할 때마다 세미콜론(;)을 쓴다.

【예제 】
  SG_Scores 테이블에서 학번이 ‘C9901'인 학생의 평균점수를 계산하여 출력하는 익명의 블록을 작성하라.

SQL> SET SERVEROUTPUT ON
SQL> get ex8_01.sql
  1  DECLARE
  2     v_avg           NUMBER(3)      := 0;
  3     v_student_id    VARCHAR2(5)    := 'C9901';
  4  BEGIN
  5     SELECT   AVG(Score)
  6       INTO   v_avg
  7       FROM   SG_Scores
  8       WHERE  student_id = v_student_id
  9       GROUP  BY student_id;
10       DBMS_OUTPUT.PUT_LINE (v_student_id || '의 평균점수는 ['
11   || v_avg || ']점 입니다.');
12* END;
SQL> /
C9901의 평균점수는 [80]점 입니다.

PL/SQL 처리가 정상적으로 완료되었습니다.


8.3.2  PL/SQL 블록의 실행
☞ SQL*Plus를 이용하는 방법
▪ 편집기(editor)로 PL/SQL 블록을 입력한 후, *.sql 파일로 저장

▪ @ 또는 start 명령어로 *.sql 파일을 호출하여 실행

Netterm이나 텔넷(Telnet)을 이용하여 SQL*Plus상에서 블록을 실행

☞ Oracle Developer의 Procedure Builder를 이용하는 방법
▪  Program  PL/SQL Interpreter  메뉴를 선택
▪ PL/SQL Interpreter 화면에 작성한 블록을 입력
▪ END;이 입력되면 자동 실행


8.4 선언절에 변수, 상수 선언

상수는 프로그램이 시작하여 종료될 때까지 일정한 값을 가지는 수,
어떤 값을 대입 불가
12, 87과 같은 숫자형 리터럴과 ‘Computer', '홍길동’, ‘T' 와 같은 문자형 리터럴

변수는 프로그램이 시작하여 종료될 때까지 변하는 수,
어떤 값을 대입 가능. i, Course_id 등과 같이 문자로 지정

8.4.1 PL/SQL의 데이터타입

• SQL에서 사용 가능한 모든 데이터타입과  추가적인 데이터타입

데이터타입                                            설 명
-------------------------------------------------------------------------
BOOLEAN              논리적인 데이터(True, False, Unknown)를 저장할 때 사용
BINARY_INTEGER   부호가 있는 정수를 저장할 때 사용
                             데이터 범위는 -2147483647부터 2147483647까지
   ꋯ NATURAL        정수 중에서 0부터 2147483647까지 저장할 때 사용
   ꋯ POSITIVE        정수 중에서 1부터 2147483647까지 저장할 때 사용
%TYPE                  기존 테이블의 한 칼럼에 정의된 데이터타입을 참조
%ROWTYPE           기존 테이블의 모든 칼럼에 정의된 데이터타입을 참조

8.4.2 변수와 상수 선언

변수명 데이터타입(크기)                    [ := 초기값 ] ;
상수명       CONSTAT   데이터타입(크기)     := 상수값 ;


■ 변수명이나 상수명을 정의할 때는

∙ SQL 객체명과 동일한 규칙으로 정의하고
∙ 상수명은 데이터타입과 일치하는 상수 값을 반드시 기술하고
∙ 한 줄에 한 개의 변수나 상수를 정의하며
∙ 초기 값이 Null이나 0인 경우 생략할 수 있다.

【예제】변수와 상수의 선언 예

P_count NUMBER(3) := 0;
Zip_Code VARCHAR2(9);
I BINARY_INTEGER := 0;
k   CONSTANT POSITIVE := 100;



8.4.3 테이블을 참조하여 변수 선언
     - 기존 테이블에 정의된 데이터타입과 크기를 참조하여 변수를 선언

■ %TYPE

형식=>   변수명  테이블명.칼럼명%TYPE ;

- 기존 테이블의 칼럼에 선언된 데이터타입과 크기를 참조하여 변수를 선언
- 테이블 칼럼의 제약조건은 적용되지 않음.


        v_student_id    SG_Scores.student_id%TYPE := 'C9901';
        v_avg           SG_Scores.Score%TYPE      := 0;
        v_grade         SG_Scores.Grade%TYPE;  

■ %ROWTYPE

형식=> 변수명   테이블명%ROWTYPE ;

    - 기존 테이블의 각 칼럼에 정의된 데이터타입과 크기를 참조
    - 칼럼 수와 동일한 복수 개의 변수가 선언,
    - 각 기억 장소의 구분은 “변수명.칼럼명”으로 구분


【예제】SG_Scores 테이블을 참조하여 학번과 평균 점수를 저장하기 위한 변수를 %ROWTYPE을 이용하여 선언하라.


SQL> get ex8_04.sql
  1  DECLARE
  2     v               SG_Scores%ROWTYPE;
  3     v_cnt           NUMBER(2)       := 0;
  4  BEGIN
  5     v.student_id    := 'C9901';
  6     SELECT Count(*), AVG(SCORE)
  7       INTO   v_cnt, v.Score
  8       FROM   SG_Scores
  9       WHERE  student_id = v.student_id
10       GROUP  BY student_id;
11      IF v.score >= 90
12         THEN  v.grade := 'A';
13         ELSIF v.Score >= 80
14               THEN v.grade := 'B';
15               ELSIF v.Score >= 70
16                     THEN v.grade := 'C';
17                     ELSIF v.Score >= 60
18                           THEN v.grade := 'D';
19         ELSE  v.grade := 'F';
20      END IF;
21      DBMS_OUTPUT.PUT_LINE (v.student_id || '의 과목수는 [' ||
22                  v_cnt || ']이고 평균점수는 [' || v.Score ||
23                  ']점 [' || v.grade || '] 등급입니다.');
24* END;

8.4.4 PL/SQL 테이블과 사용자 정의 레코드 선언

■ PL/SQL 테이블 선언
   데이터타입과 크기가 동일한 기억장소가 동적으로 복수 개 선언

형식=>
   TYPE 테이블타입명 IS TABLE OF
                데이터타입(크기)
    INDEX BY BINARY_INTEGER;

    테이블명   테이블타입명;


- 각 기억장소 구분은 “테이블명(첨자명)”,
- 첨자명은 정수로 된 첨자명이거나, 양의 정수
- 테이블의 크기는 사용할 때 동적으로 결정

【예제】PL/SQL 테이블 선언 및 사용 예


DECLARE
TYPE Table_type IS TABLE OF
      VARCHAR2(20)
INDEX BY BINARY_INTEGER;

v_Dept_Name    Table_type;

BEGIN
...
v_Dept_Name(2) := '컴퓨터정보기술계열‘;
...
END;


■ 사용자 정의 레코드 선언
    - 데이터타입과 크기가 다른 기억장소가 복수 개 선언

형식=>  TYPE 레코드타입명 IS RECORD
         ( 필드명1  데이터타입(크기) [NOT NULL] [초기값],
            . . .
           필드명n  데이터타입(크기) [NOT NULL] [초기값] ) ;

          레코드명 레코드타입명;

       - 각 기억 장소의 구분은 “레코드명.필드명“으로 구분

【예제 】사용자 정의 레코드 선언 및 사용 예


DECLARE
TYPE  Record_Type IS RECORD
      Dept_ID   Department.Dept_ID%type,
      Dept_Name Department.Dept_Name%type;

Dept_Rec   Record_Type;
...
BEGIN
...
Dept_Rec.Dept_ID := '컴정‘;
Dept_Rec.Dept_Name := '컴퓨터정보기술계열‘;
...
END;

8.5 조건 판단문

문법>
       IF 조건1
       THEN 명령문1; . . . ; 명령문N;
       [  ELSIF 조건2
       [         THEN 명령문1; . . . ; 명령문N;   ]
       [      ELSIF 조건3
   . . .
       [  ELSE  명령문1; . . . ; 명령문N; ]
        END IF;

- 조건의 결과가 참이면 THEN 이하의 명령문을 처리하고,
  거짓이면 ELSIF절을 실행
- 조건이 모두 거짓이면 ELSE절
- ELSIF문은 16개까지 반복하여 사용


IF문은

① IF 조건 THEN 명령문_1
   END IF;

② IF 조건 THEN 명령문_1
           ELSE 명령문_2
   END IF;

③ IF 조건_1
     THEN  명령문_1
     ELSIF  조건_2
            THEN  명령문_2
            ELSIF 조건_3  THEN 명령문_3
                    ...
       ELSE 명령문_n
   END IF;

【예제 】 IF ~ THEN ~ ELSIF문 예

IF v.score >= 90
       THEN  v.grade := 'A';
       ELSIF v.Score >= 80
             THEN v.grade := 'B';
             ELSIF v.Score >= 70
                   THEN v.grade := 'C';
                   ELSIF v.Score >= 60
                         THEN v.grade := 'D';
       ELSE  v.grade := 'F';
    END IF;



  
8.6 반복문

8.6.1 LOOP문

문법> LOOP
명령문1;
. . .  ;
명령문N;
END LOOP;

- EXIT문은 무한 루프로부터 탈출하는 명령문

■ EXIT문

문법> ① EXIT;
② EXIT [레이블명] WHEN 조건;

∙ EXIT문은 무한 루프로부터 무조건 탈출
∙ EXIT WHEN 조건 명령문은 조건이 참(True)일 때 탈출


【예제 】1에서 10까지 반복하여 TEMP 테이블에 저장하라. (LOOP문 사용)

SQL> CREATE TABLE Temp (
    2  Col1 NUMBER(3),
    3  Col2   DATE);

SQL> DECLARE
  2  Max_No  CONSTANT POSITIVE := 10;
  3  I                NATURAL  := 0;
  4  BEGIN
  5     LOOP
  6        I := I + 1;
  7        EXIT WHEN I > Max_No;
  8        INSERT INTO TEMP
  9           VALUES (I, SYSDATE);
10     END LOOP;
11* END;

SQL> SELECT * FROM Temp;

8.6.2 WHILE ~ LOOP문

조건이 참(True)일 때, LOOP ~ END LOOP내의 명령문들을 반복 처리

문법> WHILE 조건 LOOP
명령문1;
. . . ;
명령문N;
END LOOP;


【예제】1에서 10까지 반복하여 TEMP 테이블에 저장하라. (WHILE문 사용)

SQL> DECLARE
  2  Max_No  CONSTANT POSITIVE := 10;
  3  I                NATURAL := 0;
  4  BEGIN
  5     WHILE I < MAX_NO LOOP
  6        I := I + 1;
  7        INSERT INTO TEMP
  8           VALUES (I, SYSDATE);
  9     END LOOP;
10* END;

8.6.3 FOR ~ LOOP문

  - 변수가 초기 값부터 1씩 증가하여 최종 값이 될 때까지 반복 처리

문법> FOR 변수 IN [REVERSE] 초기값..최종값 LOOP
명령문1;
. . . ;
                명령문N;
          END LOOP;

【예제】1에서 10까지 반복하여 TEMP 테이블에 저장하라. (FOR문 사용)


SQL> DECLARE
  2  Max_No  CONSTANT POSITIVE := 10;
  3  I                NATURAL := 0;
  4  BEGIN
  5     FOR I IN 1..MAX_NO LOOP
  6         INSERT INTO TEMP
  7           VALUES (I, SYSDATE);
  8     END LOOP;
  9* END;


8.7 NULL문

   - 어떤 처리도 하지 않음. 문법 형식을 갖추기 위해 사용

문법>NULL;


【예제 】변수 a가 0보다 크지 않으면 i 값을 1 증가시켜라.

  IF a > 0 THEN   NULL;
           ELSE   i = i + 1;
  END IF;

8.8 대입문

문법> expr1 := expr2

우변(칼럼명, 변수, 리터럴, 수식, 함수)의 값을 좌변(칼럼명, 변수)에 저장



8.9 제어문

   GOTO문은 무조건 레이블명으로 이동

문법> GOTO  레이블명


【예제 】GOTO문을 이용한 제어문 사용 예

                       ....
GOTO label_1;
                       ....
    <>
                    ...


8.10 주석 달기

☞ --  문자열
    - 단일 줄에 주석


☞ /*  문자열  */
    - 여러 줄로 주석

8.11 실행절에 SQL문 사용

8.11.1  PL/SQL에서의 SELECT문

- 검색된 행의 수가 한 행이 되어야 하고, 검색한 값을 INTO절의 변수에 저장
- 검색된 행의 수가 0행(NO_DATA_FOUND)이거나 복수 행(TOO_MANY_ROWS)일 때 오류가 발생
- ORDER BY절은 사용하지 않음

문법>

SELECT 칼럼명1, 칼럼명2, 리터럴, 함수, 수식, ...
INTO         변수명, . . .
FROM 테이블명1, 테이블명2, 뷰명1, ...
WHERE 검색조건1 ...
GROUP BY   칼럼명1, 칼럼명2, ...
HAVING 검색조건2 ;

■ SQL과 PL/SQL에서 SELECT문의 차이점

  ∙ SELECT 구문이 다름
  ∙ 결과 행
  ∙ 결과를 출력

【예제 】SG_Scores 테이블을 참조하여 ‘C9901'학번의 과목수, 평균 점수를 계산하여 출력하라.

SQL> DECLARE
  2     -- 변수 선언
  3     v_avg        NUMBER(3)    := 0;   -- 평균점수 저장
  4     v_cnt        NUMBER(2)    := 0;   /* 과목수 저장 */
  5     v_student_id VARCHAR2(5)  := 'C9901';    /* 검색할 학번 */
  6  BEGIN
  7     -- 학번의 데이터를 검색하여 과목수와 평균점수 계산
  8     SELECT   COUNT(Course_Id), AVG(Score)
  9       INTO   v_cnt, v_avg
10       FROM   SG_Scores
11       WHERE  student_id = v_student_id
12       GROUP  BY student_id;
13     -- 화면에 표시
14       DBMS_OUTPUT.PUT_LINE (v_student_id || '의 [' || v_cnt ||
15      ']과목에 대한 평균점수는 [' || v_avg || ']점 입니다.');
16* END;


☞ SET SERVEROUTPUT ON
【예제 】SG_Scores 테이블을 참조하여 ‘A9901'학번의 과목수, 평균점수를 계산하여 출력하라.


SQL> DECLARE
  2     v_avg        NUMBER(3)     := 0; -- 평균점수 저장
  3     v_cnt        NUMBER(2)     := 0; /* 과목수 저장 */
  4     v_student_id VARCHAR2(5)   := 'A9901';  /* 검색할 학번 */
  5  BEGIN
  6     SELECT   COUNT(Course_Id), AVG(Score)
  7       INTO   v_cnt, v_avg
  8       FROM   SG_Scores
  9       WHERE  student_id = v_student_id
10       GROUP  BY student_id;
11      DBMS_OUTPUT.PUT_LINE (v_student_id || '의 [' || v_cnt ||
12     ']과목에 대한 평균점수는 [' || v_avg || ']점 입니다.');
13* END;
SQL> /
DECLARE
*
1행에 오류:
ORA-01403: no data found
ORA-06512: at line 8

8.12  PL/SQL에서 화면에 출력하기

▪ DBMS_OUTPUT 내장프로시저 사용하기 위한 SQL*Plus 명령어
문법> SET SERVEROUTPUT ON


▪DBMS_OUTPUT 프로시저의 활성화와 비활성화
문법>  DBMS_OUTPUT.ENABLE;
          DBMS_OUTPUT.DISABLE;

▪문자열을 화면에 출력하는 DBMS_OUTPUT.PUT_LINE
문법>  DBMS_OUTPUT.PUT_LINE(‘출력할 내용’)


【예제】‘HELLO WORLD' 문자열을 DBMS_OUTPUT 프로시저를 비활성화하여 출력하고, 활성화한 후 출력하라.

SQL> SET SERVEROUTPUT ON
SQL> BEGIN
  2     DBMS_OUTPUT.DISABLE;
  3     DBMS_OUTPUT.PUT_LINE('1. HELLO WORLD.');
  4     DBMS_OUTPUT.ENABLE;
  5     DBMS_OUTPUT.PUT_LINE('2. HELLO WORLD.');
  6* END;
SQL> /
2. HELLO WORLD.

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL>

출처 : [기타] 인터넷 : http://www.it-sesang.com 오라클공인센터


2010. 9. 1. 13:50

(oracle)오라클 Tips - SQL 작성법


오라클 Tips
kenu  2003-10-13 04:18:35 

kenu@okjsp.pe.kr http://okjsp.pe.kr 
<25가지 SQL작성법> 
from : http://nettop.pe.kr
from : http://kkaok.pe.kr
from : http://koug.net


<25가지 SQL작성법>

1.데이터와 비즈니스 어플리케이션을 잘 알아야 한다.

동일한 정보는 다른 비즈니스 데이터 원천으로부터 검색될 수 있다. 이러한 원천
에 익숙해야 한다. 당신은 당신의 데이터베이스 안의 데이터의 크기와 분포를 반
드시 알아야 한다. 또한 SQL을 작성하기 전에 비즈니스 개체 안의 관계와 같은
데이터 모델을 전체적으로 이해해야 한다. 이러한 이해는 당신이 여러 테이블에
서 정보를 검색하는데 있어서 보다 좋은 쿼리를 작성할 수 있다. DESIGNER/2000
과 같은 CASE TOOLS은 다른 비즈니스와 데이터베이스 객체사이의 관계를 문서화
하는데 좋은 역할을 한다.

2.실제 데이터를 가지고 당신의 쿼리를 검사하라.

대부분의 조직은 개발, 검사, 제품의 3가지 데이터베이스 환경을 가진다. 프로그
래머는 어플리케이션을 만들고 검사하는데 개발 데이터베이스 환경을 사용하는
데, 이 어플리케이션이 제품 환경으로 전환되기 전에 프로그래머와 사용자에 의
해 검사 환경하에서 보다 엄격하게 검토되어야 한다.
SQL이 검사 환경하에서 테스트될 때, 검사 데이터베이스가 가지고 있는 데이터
는 제품 데이터베이스를 반영해야 한다. 비실제적인 데이터를 가지고 테스트된
SQL문은 제품 안에서는 다르게 작동할 수 있다. 엄격한 테스트를 보장하기 위해
서는, 검사 환경하에서의 데이터 분포는 반드시 제품 환경에서의 분포와 밀접하
게 닮아야 한다.

3.동일한 SQL을 사용하라.

가능한한 BIND VARIABLE, STORED PROCEDURE, PACKAGE의 이점을 활용하라. IDENTICAL
SQL문의 이점은 PARSING이 불필요하기에 데이터베이스 서버안에서 메모리 사용
의 축소와 빠른 수행을 포함한다. 예로서 아래의 SQL 문은 IDENTICAL하지 않다.

SELECT * FROM EMPLOYEE WHERE EMPID = 10;
SELECT * FROM EMPLOYEE WHERE EMPID = 10;
SELECT * FROM EMPLOYEE WHERE EMPID = 20;

그러나 I_EMPID라고 이름 주어진 BIND VARIABLE을 사용하면 SQL 문은 이렇게 된
다.
SELECT * FROM EMPLOYEE WHERE EMPID = :I_EMPID;

4.주의 깊게 인덱스를 사용하라.

테이블상에 모든 필요한 인덱스는 생성되어야 한다. 하지만 너무 많은 인덱스는
성능을 떨어뜨릴 수 있다. 그러면 어떻게 인덱스를 만들 칼럼을 선택해야 하는
가?

*최종 사용자에 의해 사용되는 어플리케이션 SQL과 쿼리의 WHERE 절에서 빈번
하게 사용되는 칼럼에 인덱스를 만들어야 한다.

*SQL 문에서 자주 테이블을 JOIN하는데 사용되는 칼럼은 인덱스되어야 한다.

*같은 값을 가지는 ROW가 적은 비율을 가지는 칼럼에 인덱스를 사용하라.

*쿼리의 WHERE 절에서 오직 함수와 OPERATOR로 사용되는 칼럼에는 인덱스를 만들
면 안된다.

*자주 변경되거나 인덱스를 만들때 얻는 효율성보다 삽입, 갱신, 삭제로 인해 잃는
효율성이 더 큰 칼럼에는 인덱스를 만들면 안된다. 이러한 OPERATION은 인덱스를
유지하기 위한 필요 때문에 느려진다.

*UNIQUE 인덱스는 더 나은 선택성 때문에 NONUNIQUE 인덱스보다 좋다. PRIMARY
KEY 칼럼에 UNIQUE 인덱스를 사용한다. 그리고 FOREIGN KEY 칼럼과 WHERE 절
에서 자주 사용되는 칼럼에는 NONUNIQUE 인덱스를 사용한다.

5.가용한 인덱스 PATH를 만들어라

인덱스를 사용하기 위해서는 기술한 SQL문을 이용할 수 있는 식으로 SQL을 작
성하라. OPTIMIZER는 인덱스가 존재하기 때문에 인덱스를 사용하는 ACESS PATH
를 사용할 수 없다. 따라서 ACCESS PATH는 반드시 SQL이 사용할 수 있게 만들
어 져야 한다. SQL HINT를 사용하는 것은 인덱스 사용을 보증해주는 방법중 하
나이다. 특정 ACCESS PATH를 선택하기 위한 다음의 힌트를 참고 하라

6.가능하면 EXPLAIN과 TKPROF를 사용하라

만약 SQL문이 잘 다듬어지지 않았다면 비록 오라클 데이터베이스가 잘 짜여져
있어도 효율성이 떨어질 것이다. 이럴 경우 EXPLAIN TKPROF에 능숙해져야 한
다. EXPALIN PLAN은 SQL이 사용하는 ACCESS PATH를 발견할 수 있게 해주고
TKPROF는 실제 PERFORMANEC의 통계치를 보여준다. 이 TOOL은 오라클 서버 소
프트웨어에 포함되어 있고 SQL의 성능을 향상시켜 준다.

7.OPTIMIZER를 이해하라.

SQL은 RULE-BASED나 COST-BASED중 하나를 이용해서 기동된다.기존의 소
프트웨어는 RULE BASED 방식을 채택하고 있다. 그리고 많은 오라클 소프트웨
어가 이러한 방식을 오랫동안 사용해 왔다. 그러나 새로 출시된 소프트웨어에 대
해서는 COST BASED 방식의 OPTIMIZER를 고려해야 한다. 오라클은 새로 출
시되는 프로그램을 COST BASED방식으로 업그레이드 시켜왔으며 이러한 방식
은 시스템을 훨씬 더 안정적으로 만들었다. 만약 COST BASED방식의
OPTIMIZER를 사용한다면 반드시 ANALYZE 스키마를 정기적으로 사용해야 한
다. ANALYZE스키마는 데이터베이스 통계를 데이터 사전 테이블에 기록하는 역
할을 수행하며 그렇게 되면 COST BASED OPTIMIZER가 그것을 사용하게 된
다. SQL은 COST BASED OPTIMIZER를 사용할 때만 잘 조정될 수 있다. 만약
RULE BASED에서 COST BASED로 바꾸고 싶다면 데이터베이스를 사용하는 모
든 소프트웨어의 모든 SQL문의 성능을 평가해 보아야 한다.

8.지엽적으로 동작하더라도 전역적으로 생각하라

항상 주의할 것은 하나의 SQL문을 조정하기 위해 생긴 데이터베이스안의 변화
는 다른 응용프로그램이나 다른 사용자가 이용하는 다른 명령문에 영향을 미친다
는 사실이다.

9.WHERE절은 매우 중요하다.

비록 인덱스가 가용하다고 해도 다음의 WHERE 절은 그 인덱스 ACCESS PATH
를 사용하지 않는다.(즉 COL1 과 COL2는 같은 테이블에 있으며 인덱스는
COL1에 만들어진다.)

COL1 > COL2
COL1 < COL2
COL1 > = COL2
COL1 <= COL2
COL1 IS NULL
COL1 IS NOT NULL.

인덱스는 NULL값을 갖는 칼럼에는 ROWID를 저장하지 않는다. 따라서 NULL값
을 갖는 ROW를 검색할 때는 인덱스를 사용하지 못한다.

COL1 NOT IN (VALUE1, VALUE2 )
COL1 != EXPRESSION
COL1 LIKE ''%PATTERN''.

이럴 경우 THE LEADING EDGE OF THE INDEX(?) 는 작동되지 않고 인덱스가 사
용되지 못하게 한다. 한편 COL1 LIKE ''PATTERN %''이나 COL1 LIKE ''PATTERN %
PATTERN%'' 는 한정된 인덱스 스캔을 수행하기 때문에 인덱스를 사용할 수 있다.

NOT EXISTS SUBQUERY
EXPRESSION1 = EXPRESSION2.

인덱스된 컬럼을 포함하는 표현(EXPRESSION), 함수, 계산(CALCULATIONS)은 인덱스
를 사용하지 못한다. 다음의 예에서 보면 UPPER SQL 함수를 사용하면 인덱스
스캔을 사용할 수 없고 FULL TABLE SCAN으로 끝나고 만다.

SELECT DEPT_NAME
FROM DEPARTMENT
WHERE UPPER(DEPT_NAME) LIKE ''SALES%'';

10.레코드 필터링을 위해서는 HAVING보다는 WHERE를 사용하라

인덱스가 걸려있는 칼럼에는 GROUP BY와 같이 HAVING절을 사용하지 마라. 이 경
우 인덱스는 사용되지 않는다. 또한 WHERE절로 된 ROW를 사용하지 마라. 만약
EMP테이블이 DEPTID컬럼에 인덱스를 가지고 있다면 다음 질의는 HAVING 절을
이용하지 못한다.

SELECT DEPTID,
SUM(SALARY)
FROM EMP
GROUP BY DEPTID
HAVING DEPTID = 100;

그러나 같은 질의가 인덱스를 사용하기 위해 다시 씌여질 수 있다.

SELECT DEPTID,
SUM(SALARY)
FROM EMP
WHERE DEPTID = 100
GROUP BY DEPTID;

11. WHERE 절에 선행 INDEX 칼럼을 명시하라.

복합 인덱스의 경우, 선행 인덱스가 WHERE절에 명시되어 있다면 쿼리는
그 인덱스 를 사용할 것이다. 다음의 질의는 PART_NUM과 PRODUCT_ID 칼럼
에 있는 PRIMARY KEY CONSTRAINT에 기초한 복합 인덱스를 이용할 것이다.

SELECT *
FROM PARTS
WHERE PART_NUM = 100;

반면, 다음의 쿼리는 복합인덱스를 사용하지 않는다.

SELECT *
FROM PARTS
WHERE PRODUCT_ID = 5555;

같은 요청(REQUEST)이 인덱스를 이용하기 위해 다시 씌어 질 수 있다. 다음 질의
의 경우, PART_NUM컬럼은 항상 0 보다 큰 값을 가질것이다.

SELECT *
FROM PARTS
WHERE PART_NUM > 0
AND PRODUCT_ID = 5555;

12.인덱스 SCAN과 FULL TABLE SCAN을 평가하라.

한 행(ROW)의 15% 이상을 검색하는 경우에는 FULL TABLE SCAN이 INDEX
ACESS PATH보다 빠르다. 이런 경우, SQL이 FULL TABLE SCAN을 이용할 수 있도록
여러분 스스로 SQL을 작성하라. 다음의 명령문은 비록 인덱스가 SALARY
COLUMN에 만들어져 있어도 인덱스 SCAN을 사용하지 않을 것이다. 첫 번째 SQL
에서, FULL HINT를 사용한다면 오라클은 FULL TABLE SCAN을 수행할 것이다. 인덱
스의 사용이 나쁜 점이 더 많다면 아래의 기술을 이용해서 인덱스 수행을 막을
수 있다.

SELECT * --+FULL
FROM EMP
WHERE SALARY = 50000;

SELECT *
FROM EMP
WHERE SALARY+0 = 50000;

다음의 명령문은 비록 인덱스가 SS# COLUMN에 있어도 인덱스 SCAN을 사용하
지 않을 것이다.

SELECT *
FROM EMP
WHERE SS# || '' '' = ''111-22-333'';

오라클이 불분명한 데이터 변환을 수행해야 하는 경우 인덱스가 항상 사용되지
않는 것은 아니다. 다음의 예를 보면, EMP 칼럼에 있는 SALARY는 숫자형 칼
럼이고 문자형이 숫자값으로 변환된다.

SELECT *
FROM EMP
WHERE SALARY = ''50000'';

테이블의 행이 15%이거나 그보다 작을 경우 인덱스 스캔은 보다 잘 수행 될 것
이다. 왜냐 하면 인덱스 스캔은 검색된 행(ROW)하나 하나 마다 다중의 논리적인
읽기 검색(READ)을 할 것이기 때문이다. 그러나 FULL TABLE SCAN은 하나의 논리적
인 읽기 검색 영역 안의 BLOCK에 있는 모든 행들을 읽을 수 있다. 그래서 테이
블의 많은 행들에 접근해야 하는 경우에는 FULL TABLE SCAN이 낫다. 예로 다음의
경우를 보자. 만약 EMP TABLE과 그 테이블의 모든 인덱스에 대해 ANALYZE라
는 명령어가 수행된다면, 오라클은 데이터 사전인 USER_TABLES와
USER_INDEXES에 다음과 같은 통계치를 산출해 낸다.

TABLE STATISTICS:
NUM_ROWS = 1000
BLOCKS = 100

INDEX STATISTICS:

BLEVEL = 2
AVG_LEAF_BLOCKS_PER_KEY = 1
AVG_DATA_BLOCKS_PER_KEY = 1

이러한 통계치 에 근거해서, 아래에 보이는 것이 각각의 다른 SCAN에 대한 논리
적인 읽기(READ)-즉 ACESS된 BLOCK이 될 것이다.

USE OF INDEX TO RETURN ONE ROW = 3

(BLEVEL+(AVG_LEAF_BLOCKS_PER_KEY - 1) +
AVG_DATA_PER_KEY

FULL TABLE SCAN = 100
(BLOCKS)

USE OF INDEX TO RETURN ALL ROWS = 3000
(NUM_ROWS * BLOCKS ACCESSED TO RETURN ONE ROW USING INDEX)

13. 인덱스 스캔에 ORDER BY를 사용하라

오라클의 OPTIMIZER는 , 만약 ORDER BY라는 절이 인덱스된 칼럼에 있다면 인
덱스 스캔을 사용할 것이다. 아래의 질의는 이러한 점을 보여 주는 것인데 이 질
의는 비록 그 칼럼이 WHERE 절에 명시되어 있지 않다고 해도 EMPID컬럼에 있
는 가용한 인덱스를 사용할 것이다. 이 질의는 인덱스로부터 각각의 ROWID를
검색하고 그 ROWID를 사용하는 테이블에 접근한다.

SELECT SALARY
FROM EMP
ORDER BY EMPID;

만약 이 질의가 제대로 작동하지 않는다면, 당신은 위에서 명시되었던 FULL HINT
를 사용하는 같은 질의를 다시 작성함으로써 다른 대안들을 이용해 볼 수 있다.

14. 자신의 데이터를 알아라

내가 이미 설명한 것처럼, 당신은 당신의 데이터를 상세하게 알고 있어야 한다.
예를 들어 당신이 BOXER라는 테이블을 가지고 있고 그 테이블이 유일하지 않은
인덱스를 가진 SEX라는 컬럼과 BOXER_NAME이라는 두 개의 테이블을 가지고 있
다고 가정해 보자. 만약 그 테이블에 같은 수의 남자, 여자 복서가 있다면 오라
클이 FULL TABLE SCAN을 수행하는 경우 다음의 질의가 훨씬 빠를 것이다.

SELECT BOXER_NAME
FROM BOXER
WHERE SEX = ''F'';

당신은 다음과 같이 기술함으로써 질의가 FULL TABLE SCAN을 수행하는지를 확실
하게 해 둘 수 있다.

SELECT BOXER_NAME --+ FULL
FROM BOXER
WHERE SEX = ''F'';

만약 테이블에 980 명의 남성 복서 데이터가 있다면, 질의는 인덱스 SCAN으로
끝나기 때문에 아래형식의 질의가 더 빠를 것이다.

SELECT BOXER_NAME --+ INDEX (BOXER BOXER_SEX)
FROM BOXER
WHERE SEX = ''F'';

이 예는 데이터의 분포에 대해 잘 알고 있는 것이 얼마나 중요한 가를 예시해 준
다. 데이터가 많아지고(GROW) 데이터 분포가 변화하는 것처럼 SQL 도 매우 다
양할 것이다. 오라클은 OPTIMIZER 가 테이블에 있는 데이터의 분포를 잘 인식하
고 적절한 실행 계획을 선택하도록 하기 위해 오라클 7.3 에 HISTOGRAMS라는
기능을 추가했다.

15. KNOW WHEN TO USE LARGE-TABLE SCANS.

작거나 큰 테이블에서 행들을 추출할 때, 전체 테이블의 검색은 인텍스를 사용한
검색보다 성능이 더 좋을 수도 있다. 매우 큰 테이블의 인덱스 검색은 수많은
인덱스와 테이블 블록의 검색이 필요할수도 있다. 이러한 블록들이 데이터베이
스 버퍼 캐쉬에 이동되면 가능한한 오래도록 그곳에 머무른다. 그래서 이러한
블록들이 다른 질의등에 필요하지 않을 수도 있기 때문에, 데이터베이스 버퍼 히
트 비율이 감소하며 다중 사용자 시스템의 성능도 저하되기도 한다. 그러나 전
체 테이블 검색에 의해서 읽혀진 블록들은 데이터베이스 버퍼 캐쉬에서 일찍 제
거가 되므로 데이터베이스 버퍼 캐쉬 히트 비율은 영향을 받지 않게 된다.

16. MINIMIZE TABLE PASSES.

보통, SQL질의시 참조하는 테이블의 숫자를 줄임으로 성능을 향상시킨다. 참조
되는 테이블의 숫자가 적을수록 질의는 빨라진다. 예를 들면 NAME, STATUS,
PARENT_INCOME, SELF_INCOME의 네개의 컬럼으로 이루어진 학생 테이블
에서 부모님에 의존하는 학생과 독립한 학생의 이름과 수입에 대해서 질의시, 이
학생 테이블을 두번 참조하여 질의하게 된다..
SELECT NAME, PARENT_INCOME
FROM STUDENT
WHERE STATUS = 1
UNION
SELECT NAME, SELF_INCOME
FROM STUDENT
WHERE STATUS = 0;
( NAME이 프라이머리 키이며, STATUS는 독립한 학생의 경우는 1, 부모님에
의존적인 학생은 0으로 표시한다)
위의 같은 결과를 테이블을 두번 참조하지 않고도 질의 할 수 있다.

SELECT NAME,PARENT_INCOME*STATUS + SELF_INCOME(1-STATUS)
FROM STUDENT;

17. JOIN TABLES IN THE PROPER ORDER.

다수의 테이블 조인시 테이블들의 조인되는 순서는 매우 중요하다. 전반적으로,
올바른 순서로 테이블이 조인되었다면 적은 수의 행들이 질의시 참조된다. 언제
나 다수의 조인된 테이블들을 질의시 우선 엄격하게 조사하여 행들의 숫자를 최
대한으로 줄인다. 이러한 방법으로 옵티마이저는 조인의 차후 단계에서 적은 행
들을 조사하게 된다. 뿐만 아니라, 여러 조인을 포함하는 LOOP JOIN에서는 가
장 먼저 참조되는 테이블(DRIVING TABLE)이 행들을 최소한으로 리턴하도록 해야
한다. 그리고, 마스터와 상세 테이블 조인시에는(예를 들면 ORDER & ORDER
LINE ITEM TABLES) 마스터 테이블을 먼저 연결 시켜야 한다.
규칙에 근거한 옵티마이저의 경우에는 FROM CLAUSE의 마지막 테이블이 NESTED
LOOP JOIN의 DRIVING TABLE이 된다. NESTED LOOP JOIN이 필요한 경우에는
LOOP의 안쪽의 테이블에는 인텍스를 이용하는 것을 고려할 만하다. EXPLAIN
PLAN과 TKPROF는 조인 타입, 조인 테이블 순서, 조인의 단계별 처리된 행들
의 숫자들을 나타낸다.
비용에 근거한 옵티마이저의 경우에는 WHERE CLAUSE에 보여지는 테이블의 순
서는 옵티마이저가 가장 최적의 실행 계획을 찾으려고 하는 것과 상관 없다. 조
인되는 테이블의 순서를 통제하기 위해서 ORDERED HINT를 사용하는 것이 낫다.

SELECT ORDERS.CUSTID, ORDERS.ORDERNO,
ORDER_LINE_ITEMS.PRODUCTNO --+ORDERED
FROM ORDERS, ORDER_LINE_ITEMS
WHERE ORDERS.ORDERNO = ORDER_LINE_ITEMS.ORDERNO;

18. USE INDEX-ONLY SEARCHES WHEN POSSIBLE.

가능하다면, 인덱스만을 이용하여 질의를 사용하라. 옵티마이저는 오직 인덱스만
을 찾을 것이다. 옵티마이저는 SQL을 만족시키는 모든 정보를 인덱스에서 찾을
수 있을 때, 인덱스만을 이용할 것이다. 예를들면, EMP테이블이 LANME과
FNAME의 열에 복합 인덱스를 가지고 있다면 다음의 질의는 인덱스만은 이용할
것이다.

SELECT FNAME
FROM EMP
WHERE LNAME = ''SMITH'';

반면에 다음의 질의는 인덱스와 테이블을 모두 참조한다.

SELECT FNAME , SALARY
FROM EMP
WHERE LNAME = ''SMITH'';

19. REDUNDANCY IS GOOD.

WHERE CLAUSE에 가능한한 많은 정보를 제공하라. 예를 들면 WHERE COL1 =
COL2 AND COL1 = 10이라면 옵티마이저는 COL2=10이라고 추론하지만,
WHERE COL1 = COL2 AND COL2 = COL3이면 COL1=COL3이라고 초론하지는
않는다.

20. KEEP IT SIMPLE, STUPID.

가능하면 SQL문을 간단하게 만들라. 매우 복잡한 SQL문은 옵티마이저를 무력
화시킬 수도 있다. 때로는 다수의 간단한 SQL문이 단일의 복잡한 SQL문보다
성능이 좋을 수도 있다. 오라클의 비용에 근거한 옵티마이저는 아직은 완벽하지
않다. 그래서 EXPLAIN PLAN에 주의를 기울여야 한다. 여기서 비용이란 상대적인
개념이기에 정확히 그것이 무엇을 의미하는지 알지 목한다. 하지만 분명한 것은
적은 비용이 보다 좋은 성능을 의미한다는 것이다.
종종 임시 테이블을 사용하여 많은 테이블들을 포함하는 복잡한 SQL 조인을 쪼
개는 것이 효율적일 수도 있다. 예를 들면, 조인이 대량의 데이터가 있는 8개의
테이블을 포함할 때, 복잡한 SQL을 두 세개의 SQL로 쪼개는 것이 낫을 수 있
다. 각각의 질의는 많아야 네개정도의 테이블들을 포함하며 그 중간 값을 저장
하는 것이 낫을 수 있다.

21. YOU CAN REACH THE SAME DESTINATION IN DIFFERENT WAYS.

많은 경우에, 하나 이상의 SQL문은 의도한 같은 결과를 줄 수 있다. 각각의
SQL은 다른 접근 경로를 사용하며 다르게 수행한다. 예를들면, MINUS(-) 산술
자는 WHERE NOT IN (SELECT ) OR WHERE NOT EXISTS 보다 더 빠르다.
예를들면, STATE와 AREA_CODE에 각각 다른 인덱스가 걸려 있다. 인덱스에
도 불구하고 다음의 질의는 NOT IN의 사용으로 인해 테이블 전체를 조사하게
된다.
SELECT CUSTOMER_ID
FROM CUSTOMERS
WHERE STATE IN (''VA'', ''DC'', ''MD'')
AND AREA_CODE NOT IN (804, 410);

그러나 같은 질의가 다음 처럼 쓰여진다면 인덱스를 사용하게 된다
SELECT CUSTOMER_ID
FROM CUSTOMERS
WHERE STATE IN (''VA'', ''DC'', ''MD'')
MINUS
SELECT CUSTOMER_ID
FROM CUSTOMERS
WHERE AREA_CODE IN (804, 410);

WHERE절에 OR을 포함한다면 OR대신에 UNION을 사용할 수 있다. 그래서,
SQL 질의를 수행하기 전에 먼저 실행계획을 조심스럽게 평가해야 한다. 이러한
평가는 EXPLAIN PLAN AND TKPROF를 이용하여 할 수 있다.

22. USE THE SPECIAL COLUMNS.

ROWID AND ROWNUM 열을 이용하라. ROWID를 이용하는 것이 가장 빠르다.
예를들면, ROWID를 이용한 UPDATE는 다음과 같다.

SELECT ROWID, SALARY
INTO TEMP_ROWID, TEMP_SALARY
FROM EMPLOYEE;

UPDATE EMPLOYEE
SET SALARY = TEMP_SALARY * 1.5
WHERE ROWID = TEMP_ROWID;

ROWID값은 데이터베이스에서 언제나 같지는 않다. 그래서, SQL이나 응용 프
로그램이용시 ROWID값을 절대화 시키지 말라. 리턴되는 행들의 숫자를 제한
시키기위해 ROWNUM을 이용하라. 만약에 리턴되는 행들을 정확히 모른다면
리턴되는 행들의 숫자를 제한하기위해 ROWNUM을 사용하라
다음의 질의는 100개 이상의 행들을 리턴하지는 않는다.
SELECT EMPLOYE.SS#, DEPARTMENT.DEPT_NAME
FROM EMPLOYEE, DEPENDENT
WHERE EMPLOYEE.DEPT_ID = DEPARTMENT.DEPT_ID
AND ROWNUM < 100;

23.함축적인 커서대신 명시적인 커서를 사용하라.

함축적 커서는 여분의 FETCH를 발생시킨다. 명시적 커서는 DECLARE, OPEN,
FETCH와 CLOSE CURSOR문을 사용하여 개발자에 의해서 생성된다. 함축 커서는
DELETE, UPDATE, INSERT와 SELECT문을 사용하면 오라클에 의해서 생성
된다.

24.오라클 병렬 쿼리 옵션을 찾아서 이용하라.

병렬 쿼리 옵션을 사용하면, 보다 빠른 성능으로 SQL을 병렬로 실행할 수 있다.
오라클 7에서는, 오직 FULL TABLE SCAN에 기반한 쿼리만이 병렬로 수행될 수 있다.
오라클 8에서는, 인덱스가 분할되어있다면 INDEXED RANGE SCANS에 기반한 쿼리도
병렬로 처리될 수 있다. 병렬 쿼리 옵션은 다수의 디스크 드라이버를 포함하는
SMP와 MPP SYSTEM에서만 사용될 수 있다.

오라클 서버는 많은 우수한 특성을 가지고 있지만, 이러한 특성의 존재만으로는
빠른 성능을 보장하지 않는다. 이러한 특성을 위해서 데이터베이스를 조정해야하
며 특성을 이용하기 위해 특별하게 SQL을 작성해야 한다. 예를 들면, 다음의
SQL은 병렬로 수행될 수 있다.

SELECT * --+PARALLEL(ORDERS,6)
FROM ORDERS;

25.네트웍 소통량을 줄이고 한번에 처리되는 작업량을 늘려라.

ARRAY PROCESSING과 PL/SQL BLOCK을 사용하면 보다 나은 성능을 얻을 수 있고
네트웍 소통량을 줄인다. ARRAY PROCESSING은 하나의 SQL문으로 많은 ROW를 처
리할 수 있게 한다. 예를 들면, INSERT문에서 배열을 사용하면 테이블내의
1,000 ROW를 삽입할 수 있다. 이러한 기술을 사용하면 주요한 성능 향상을 클라
이언트/서버와 배치시스템에서 얻어질 수 있다.

복합 SQL문은 과도한 네트웍 소통을 유발할 수 있다. 그러나 만일 SQL문이 단
일 PL/SQL 블록안에 있다면, 전체 블록은 오라클 서버에 보내져서 그곳에서 수
행되고, 결과는 클라이언트의 APPLICATION에게 돌아온다.

개발자와 사용자는 종종 SQL을 데이터베이스에서 데이터를 검색하고 전송하는
간단한 방법으로 사용한다. 때때로 직접적으로 SQL을 작성하지 않고 코드 발생
기를 사용하여 작성한 APPLICATION은 심각한 성능 문제를 일으킨다. 이러한 성능
감퇴는 데이터베이스가 커지면서 증가한다.

SQL은 유연하기 때문에, 다양한 SQL문으로 같은 결과를 얻을 수 있다. 그러나
어떤 문은 다른 것보다 더 효율적이다. 여기에 기술된 팁과 기법을 사용하면 빠
르게 사용자에게 정보를 제공할 수 있는 APPLICATION과 리포트를 얻을 수 있다.
원본: 오라클 Tips