posted by 구름너머 2004. 10. 15. 11:21

'ORACLE' 카테고리의 다른 글

NVL과 NVL2 함수에 대하여  (0) 2004.12.03
PL/SQL 에서 NULL 체크하기  (0) 2004.11.30
EXPLAIN PLAN(실행계획  (0) 2004.10.15
Oracle Hint사용  (0) 2004.10.15
제약조건의 확인(테이블,컬럼)  (0) 2004.10.15
posted by 구름너머 2004. 10. 15. 11:19

'ORACLE' 카테고리의 다른 글

PL/SQL 에서 NULL 체크하기  (0) 2004.11.30
SQL*Plus AUTOTRACE  (0) 2004.10.15
Oracle Hint사용  (0) 2004.10.15
제약조건의 확인(테이블,컬럼)  (0) 2004.10.15
계층구조 쿼리의 예제  (0) 2004.10.15
posted by 구름너머 2004. 10. 15. 10:20


<<Optimization Approaches and Goals - Optimization 접근과 목적>>


/*+ ALL_ROWS */

ALL_ROWS는 Full Table Scan을 선호하며 CBO(Cost Based Optimization)는 default로
ALL_ROWS를 선택 합니다.

SQL>SELECT /*+ ALL_ROWS */ ename, hiredate FROM emp WHERE ename like '%%%'

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: ALL_ROWS (Cost=1 Card=5 Bytes=80)
1 0 TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=5 Bytes=80)



/*+ CHOOSE */

Hint Level의 CHOOSE는 RBO(Rule Based Optimization)인지 CBO(Cost Based Optimization)
인지를 선택 합니다.

만약 주어진 table의 통계 정보가 없다면 Rule Based 접근 방식을 사용 합니다.



/*+ FIRST_ROWS */

Full Table Scan보다는 index scan을 선호하며
Interactive Application인 경우 best response time을 제공 합니다.

또한 sort merge join보다는 nested loop join을 선호 합니다.

SQL>SELECT /*+ FIRST_ROWS */ ename FROM emp WHERE empno=7876

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=1 Card=1 Bytes=20)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=1 Bytes=20)
2 1 INDEX (RANGE SCAN) OF 'PK_EMP' (UNIQUE) (Cost=1 Card=1)



/*+ RULE */

Rule Based 접근 방식을 사용하도록 지정 합니다.



<<Access Methods - 접근 방법>>


/*+ CLUSTER(table_name) */

Cluster Scan을 선택하도록 지정한다. 따라서 clustered object들에만 적용 됩니다.



/*+ FULL(table_name) */

Table을 Full Scan하길 원할 때 사용 합니다.



/*+ HASH(table) */

Hash scan을 선택하도록 지정한다.
이 hint는 HASHKEYS parameter를 가지고 만들어진 cluster내에 저장된 table에만 적용이 됩니다.



/*+ INDEX(table_name index_name) */

지정된 index를 강제적으로 쓰게끔 지정 합니다.



/*+ INDEX_ASC(table_name index_name) */

지정된 index를 오름차순으로 쓰게끔 지정 합니다.
Default로 Index Scan은 오름차순 입니다



/*+ INDEX_DESC(table_name index_name) */

지정된 index를 내림차순으로 쓰게끔 지정 합니다.


SQL>SELECT /*+ index_desc(emp pk_emp) */ empno
FROM emp
WHERE rownum = 1 ;

위 문장은 제일 큰 것 하나만 조회되므로, max function의 기능을 대신할 수 있습니다.



/*+ INDEX_FFS(table index) */

Full table scan보다 빠른 Full index scan을 유도 합니다.



/*+ ROWID(table) */

Rowid로 Table Scan을 하도록 지정 합니다.



<<Join Orders>>


/*+ ORDERED */

From절에 기술된 테이블 순서대로 join이 일어나도록 유도 합니다.



<<Join Operations>>


/*+ USE_HASH (table_name) */

각 테이블간 HASH JOIN이 일어나도록 유도 합니다.



/*+ USE_MERGE (table_name) */

지정된 테이블들의 조인이 SORT-MERGE형식으로 일어나도록 유도 합니다.



<<Parallel Execution>>


/*+ NOPARALLEL(table_name) */

NOPARALLEL hint를 사용하면, parallel query option을 사용하지 않도록 할 수 있다.

SQL>SELECT /*+ NOPARALLEL */ * FROM emp;



/*+ PARALLEL(table_name, degree) */

PARALLEL hint를 사용하면 query에 포함된 table의 degree를 설정할 수 있습니다.

예를 들어, 다음과 같이 hint를 적어 degree 4로 parallel query option을 실행하도록 할 수 있습니다.
이 때 parallel이란 글자와 괄호( '(' )사이에 blank를 넣지 않도록 주의해야 합니다.

SQL>SELECT /*+ PARALLEL(emp, 4) */ * FROM emp;



* DEGREE의 의미 및 결정

Parallel Query에서 degree란 하나의 operation 수행에 대한 server process의 개수 입니다.
이러한 degree 결정에 영향을 주는 요인들에는 다음과 같은 것들이 있습니다.

(1) system의 CPU 갯수
(2) system의 maximum process 갯수
(3) table이 striping되어 있는 경우, 그 table이 걸쳐있는 disk의 갯수
(4) data의 위치 (즉, memory에 cache되어 있는지, disk에 있는지)
(5) query의 형태 (예를 들어 sorts 혹은 full table scan)

한 사용자만이 parallel query를 사용하는 경우, sorting이 많이 필요한
작업과 같은 CPU-bound 작업의 경우는 CPU 갯수의 1 ~ 2배의 degree가 적당하며,
sorting보다는 table scan과 같은 I/O bound 작업의 경우는 disk drive 갯수의 1 ~ 2배가 적당합니다.

동시에 수행되는 parallel query가 많은 경우에는 위의 각 사용자의 degree를
줄이거나 동시에 사용하는 사용자 수를 줄여야 합니다.

'ORACLE' 카테고리의 다른 글

SQL*Plus AUTOTRACE  (0) 2004.10.15
EXPLAIN PLAN(실행계획  (0) 2004.10.15
제약조건의 확인(테이블,컬럼)  (0) 2004.10.15
계층구조 쿼리의 예제  (0) 2004.10.15
계층 구조의 조회(Hierarchical Queries)  (0) 2004.10.15
posted by 구름너머 2004. 10. 15. 10:18

--1. 테이블에 걸려있는 제약 조건의 확인
-- USER_CONS_COLUMNS : 컬럼에 할당된 제약 조건을 볼 수 있습니다.
-- USER_CONSTRAINTS : 유저가 소유한 모든 제약 조건을 불 수 있습니다.
--이 두개의 데이터사전을 참조 하면 됩니다.
SELECT SUBSTR(A.COLUMN_NAME,1,15) COLUMN_NAME,   -- 컬럼명
     DECODE(B.CONSTRAINT_TYPE,
'P','PRIMARY KEY',
           'U','UNIQUE KEY',
           'C','CHECK OR NOT NULL',
'R','FOREIGN KEY') CONSTRAINT_TYPE,   -- 제약조건 TYPE
     A.CONSTRAINT_NAME   CONSTRAINT_NAME   -- 제약 조건 명
FROM  USER_CONS_COLUMNS  A,  USER_CONSTRAINTS  B  
WHERE  A.TABLE_NAME = UPPER('TB_CODECD')  
AND  A.TABLE_NAME = B.TABLE_NAME  
AND  A.CONSTRAINT_NAME = B.CONSTRAINT_NAME  
ORDER BY 1   

--2. 테이블의 특정 컬럼에 걸려있는 제약 조건의 확인
--USER_CONS_COLUMNS : 컬럼에 할당된 제약 조건을 볼 수 있습니다.
--SQL>SET LINESIZE 300
SELECT SUBSTR(TABLE_NAME,1,15)    TABLE_NAMES,  
     SUBSTR(COLUMN_NAME,1,15)   COLUMN_NAME,  
       SUBSTR(CONSTRAINT_NAME,1,25) CONSTRAINT_NAME  
FROM USER_CONS_COLUMNS
WHERE TABLE_NAME = UPPER('TB_CODECD')
AND COLUMN_NAME = UPPER('CD_CODE')  

'ORACLE' 카테고리의 다른 글

EXPLAIN PLAN(실행계획  (0) 2004.10.15
Oracle Hint사용  (0) 2004.10.15
계층구조 쿼리의 예제  (0) 2004.10.15
계층 구조의 조회(Hierarchical Queries)  (0) 2004.10.15
EXECUTE IMMEDIATE를 이용한 Dynamic SQL  (0) 2004.10.15
posted by 구름너머 2004. 10. 15. 10:12


아래 강좌에서 START WITH와 CONNECT BY절을 이용해서 계층 구조로 쿼리를 해오는것을 살펴봤습니다.

이번에는 계층구조를 이용해서 역순으로 쿼리를 해오는것을 보겠습니다.

SQLPLUS scott/tiger
-- 조금 깔끔하게 보기 위해서.. 셋팅 먼저 하고요..
SQL> SET LINESIZE 100
SQL> SET PAGESIZE 100
SQL> COL ename FORMAT A20

SQL>SELECT LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
FROM emp
START WITH EMPNO=7839
CONNECT BY PRIOR empno=mgr;
ENAME EMPNO MGR JOB
-------------------- ---------- ---------- ---------
KING 7839 PRESIDENT
JONES 7566 7839MANAGER
SCOTT 7788 7566 ANALYST
ADAMS 7876 7788 CLERK
FORD 7902 7566 ANALYST
SMITH 7369 7902 CLERK


위 SQL문은 EMPNO가 7839인 것을 기준으로 EMPNO와 MGR컬럼을 가지고 계층구조로 비교해서 결과값을 반환 합니다.

위 SQL문의 CONNECT BY PRIOR empno=mgr 이 부분을..한번 바꺼 볼까요..

아래처럼.. CONNECT BY empno=PRIOR mgr 이렇게 바꺼서 한번 실행해 보세요..
그럼..역순으로.. 쿼리를 해서 결과값을 반환 합니다


SQL>SELECT LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
FROM emp
START WITH EMPNO=7369
CONNECT BY empno=PRIOR mgr;



ENAME EMPNO MGR JOB
-------------------- ---------- ---------- ---------
SMITH 7369 7902 CLERK
FORD 7902 7566 ANALYST
JONES 7566 7839 MANAGER
KING 7839 PRESIDENT


위에 결과값과 비교해 보세요..

이 SQL문은 실제로..실무에서 카테고리의 Depth를 표현할때 아주 많이 사용 합니다.

컴퓨터/소프트웨어>모니터>일반CRT모니터

이런 카테고리 구조를 하나의 SQL문으로 쉽게 가져 올수가 있죠..
- 김정식 [2004-03-16]
이렇게 하면 한줄로 나오겠지..
SELECT lvl3||' > '||lvl2||' > '||lvl1 lvl
FROM
(SELECT MAX(DECODE(lvl, 3, category_name)) lvl3,
MAX(DECODE(lvl, 2, category_name)) lvl2,
MAX(DECODE(lvl, 1, category_name)) lvl1
FROM
(SELECT LEVEL lvl, category_name
FROM wp_category
WHERE category_id > 0
START WITH category_id=1913
CONNECT BY category_id=PRIOR parent_id))
posted by 구름너머 2004. 10. 15. 10:10

오라클 데이터베이스 scott유저의 emp테이블을 보면 empno와 mgr컬럼이 있습니다.


mgr 컬럼의 데이터는 해당 사원의 관리자의 empno를 의미 합니다.


예를 들어서 아래의 데이터를 보면은..


EMPNO ENAME SAL MGR
------ --------- ------- ----------
7369 SMITH 800 7902
7902 FORD 3000 7566


empno 7369사원의 관리자는 7902의 empno를 가진 사원이며
empno 7902사원의 관리자는 7566의 empno를 가진 사원입니다.


이런 상위 계층과 하위계층의 관계를 오라클에서는 START WITHCONNECT BY를 이용해서
쉽게 가져올 수 있습니다.

상품의 카테고리(대분류,중분류,소분류...)를 조회 할때 START WITH와 CONNECT BY를 이용하면
트리 구조로 편리하게 조회 할 수 있습니다.


게시판에서의 일반글과 답변글 과의 관계에서도 사용 할 수 있습니다.



START WITH와 CONNECT BY를 이용해 데이터를 계층적인 순서로 조회할 수 있습니다.


START WITH

- 계층 질의의 루트(부모행)로 사용될 행을 지정 합니다..
- 서브쿼리를 사용할 수도 있습니다.


CONNECT BY

- 이 절을 이용하여 계층 질의에서 상위계층(부모행)과 하위계층(자식행)의 관계를 규정 합니다.
- 보통 PRIOR 연산자를 많이 사용 합니다..
- 서브쿼리를 사용할 수 없습니다..



CONNECT BY의 실행순서는 다음과 같습니다.

- 첫째 START WITH절
- 둘째 CONNECT BY 절
- 세째 WHERE 절 순서로 풀리게 되어있습니다.


-- 테스트를 위해서 scott유저로 접속을 합니다.
SQLPLUS scott/tiger


예제1)상위계층과 하위 계층 관계의 순서대로 쿼리해 옴


-- LEVEL 예약어를 사용하여 depth를 표현 할 수 있습니다.
-- 직업이 PRESIDENT을 기준으로 계층 구조로 조회합니다.

SQL>SELECT LEVEL,empno,ename, mgr
FROM emp
START WITH job = 'PRESIDENT' -- 직업이 PRESIDENT를 기준으로
CONNECT BY PRIOR empno = mgr; -- 사원(empno)과 관리자(mgr)의 관계를 계층 구조로 조회

LEVEL EMPNO ENAME MGR
--------- ---------- -------------------- ----------
1 7839 KING
2 7566 JONES 7839
3 7788 SCOTT 7566
4 7876 ADAMS 7788
3 7902 FORD 7566
4 7369 SMITH 7902
2 7698 BLAKE 7839
3 7499 ALLEN 7698
3 7521 WARD 7698
3 7654 MARTIN 7698
3 7844 TURNER 7698
3 7900 JAMES 7698
2 7782 CLARK 7839
3 7934 MILLER 7782


-- LEVEL컬럼은 depth를 나타냅니다.
-- JONES의 관리자는 KING을 나타냅니다.
-- SCOTT의 관리자는 JONES를 나타냅니다.
-- 예제와 같이 상/하의 계층 구조를 쉽게 조회 할 수 있습니다.




예제2) 사원성명을 계층 구조로 보여 줌


SQL>SET LINESIZE 100
SQL>SET PAGESIZE 100
SQL>COL ename FORMAT A20

-- 예제1의 결과를 가지고 LPAD함수를 이용해서 ename왼쪽에 공백을 추가 했습니다.
SQL>SELECT LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
FROM emp
START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr;

ENAME EMPNO MGR JOB
-------------------- ---------- ---------- ---------
KING 7839 PRESIDENT
JONES 7566 7839 MANAGER
SCOTT 7788 7566 ANALYST
ADAMS 7876 7788 CLERK
FORD 7902 7566 ANALYST
SMITH 7369 7902 CLERK
BLAKE 7698 7839 MANAGER
ALLEN 7499 7698 SALESMAN
WARD 7521 7698 SALESMAN
MARTIN 7654 7698 SALESMAN
TURNER 7844 7698 SALESMAN
JAMES 7900 7698 CLERK
CLARK 7782 7839 MANAGER
MILLER 7934 7782 CLERK


예제3) 레벨이 2까지만 쿼리해서 가져오는 예제

SQL>SELECT LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
FROM emp
START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr
AND LEVEL <=2 ;

ENAME EMPNO MGR JOB
-------------------- ---------- ---------- ---------
KING 7839 PRESIDENT
JONES 7566 7839 MANAGER
BLAKE 7698 7839 MANAGER
CLARK 7782 7839 MANAGER



예제4) 각 label별로 급여의 합과 인원수를 구하는 예제

SQL> SELECT LEVEL, SUM(sal) total,COUNT(empno) cnt
FROM emp
START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr
GROUP BY LEVEL
ORDER BY LEVEL;

LEVEL TOTAL CNT
---------- ---------- ----------
1 5000 1
2 8275 3
3 13850 8
4 1900 2




데이터가 많아질 경우....

-
첫째로 풀리는 START WITH job='PRESIDENT' job 컬럼에 index가 생성되어 있지 않는다면
속도를 보장할 수 없습니다.

- 그리고 둘째로 풀리는 CONNECT BY PRIOR empno = mgr 역시 PRIOR 쪽의 컬럼값이 상수가
되기 때문에 MGR컬럼에 index를 생성하여야 CONNECT BY의 속도를 보장할 수 있습니다.

- 계층구조를 CONNECT BY, START WITH로 풀면 부분범위 처리가 불가능하고 Desc으로
표현하기가 어렵 습니다.


참고..

http://dblab.changwon.ac.kr/oracle/sqltest/hierarchical.html/
http://www.en-core.com/

posted by 구름너머 2004. 10. 15. 09:59

1. EXECUTE IMMEDIATE를 이용한 Dynamic SQL


Oracle 8i에서의 Dynamic SQL은 두가지 방법이 있습니다.

첫번째 방법은 "EXECUTE IMMEDIATE" 절을 사용하여 embedded dynamic sql을 구현하는
방법이고,

두번째 방법은 선언되어지는 것 대신에 실행시에 문장을 보내는 ref cursor의 확장된 개념으로
query를 위해 사용되어지는 방법 입니다.


여기서는 EXECUTE IMMEDIATE를 이용한 Dynamic SQL에 대해서 알아보겠습니다.

[Syntax]

EXECUTE IMMEDIATE dynamic_sql_string
[INTO {define_var1 [, define_var2] ... | plsql_record }]
[USING [IN | OUT | IN OUT] bind_arg1 [,
[IN | OUT | IN OUT] bind_arg2] ...];



2. 간단하게 테이블을 생성하는 예제 입니다


첫번째 예제는 간단하게 테이블을 생성하는 예제 입니다.

==========================================================

CREATE OR REPLACE PROCEDURE dynamic_sql_01
IS

str varchar2(200);

BEGIN

str := 'CREATE TABLE total (total number)';
EXECUTE IMMEDIATE str;

END;

==========================================================

프로시저가 생성되었습니다.


-- 프로시저를 실행해서 테이블을 생성 합니다.
SQL> EXEC dynamic_sql_01;
PL/SQL 처리가 정상적으로 완료되었습니다.


-- 생성된 테이블을 확인해 봅니다.
SQL> DESC total;
이름 널? 유형
----------------------------------------- -------- -----------
TOTAL NUMBER



* 프로시저 생성시 "ORA-01031: 권한이 불충분합니다" 에러가 발생하면
system유저로 접속을 해서 EXECUTE IMMEDIATE를 실행하는 유저에게
CREATE ANY TABLE 권한을 부여 합니다.

SQL> CONN system/manager
SQL> GRANT create any table TO scott;



3. 테이블 생성 후 INSERT 예제


두번째 예제는 TABLE_ROWS라는 테이블을 생성하고, 다이나믹 하게 테이블명을 입력하면
테이블명과 테이블에 등록된 데이터수를 TABLE_ROWS에 INSERT하고 출력하는 예제 입니다.


===============================================================

CREATE OR REPLACE PROCEDURE dynamic_sql_02
(v_table_name IN VARCHAR2)
IS

v_str VARCHAR2(200);
v_cnt NUMBER;
v_temp VARCHAR2(50);

CURSOR cur_exists IS
SELECT TABLE_NAME
FROM USER_TABLES
WHERE table_name = 'TABLE_ROWS';

BEGIN

OPEN cur_exists
FETCH cur_exists INTO v_temp;


-- 테이블이 존재하면 테이블을 삭제 합니다.
IF cur_exists%FOUND THEN
v_str := 'DROP TABLE table_rows';
EXECUTE IMMEDIATE v_str;
END IF;

-- 테이블 생성
v_str := 'CREATE TABLE table_rows (total number, table_name varchar2(50))';
EXECUTE IMMEDIATE v_str;


-- 데이터 카운트 조회
v_str := 'SELECT COUNT(*) cnt FROM '||v_table_name ;
EXECUTE IMMEDIATE v_str INTO v_cnt ;


-- 데이터 insert
v_str := 'INSERT INTO table_rows VALUES ('||v_cnt||', :A1 )';
EXECUTE IMMEDIATE v_str USING v_table_name;


DBMS_OUTPUT.PUT_LINE(' 테이블 명 : '||v_table_name||' 데이터 수 : '||v_cnt);

CLOSE cur_exists;

END;
/
===============================================================

프로시저가 생성되었습니다.

SQL> SET SERVEROUTPUT ON:

-- emp 테이블명과 테이블의 데이터카운트를 INSERT합니다.
SQL> EXEC dynamic_sql_02('emp');
테이블 명 : emp 데이터 수 : 14

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


-- 정상적으로 처리되었는지 확인해 봅니다.
SQL> SELECT * FROM table_rows;

TOTAL TABLE_NAME
---------- --------------
14 emp


posted by 구름너머 2004. 10. 15. 09:55


◈ DB에 등록된 유저의 정보 조회

- dba_users 데이터 사전을 이용하시면 됩니다.


SQL>col username format a15
SQL>col default_tablespace format a15
SQL>col temperary_tablespace format a15
SQL>SELECT username, default_tablespace, temporary_tablespace, created
FROM dba_users

USERNAME DEFAULT_TABLESP TEMPORARY_TABLESPACE CREATED
--------------- --------------- ------------------------------ --------
SYS SYSTEM TEMP 01/03/25
SYSTEM TOOLS TEMP 01/03/25
OUTLN SYSTEM SYSTEM 01/03/25
DBSNMP SYSTEM SYSTEM 01/03/25
SCOTT SYSTEM SYSTEM 01/03/25
ADAMS SYSTEM SYSTEM 01/03/25
OEM OEM_REPOSITORY TEMP 01/10/11
JONES SYSTEM SYSTEM 01/03/25
CLARK SYSTEM SYSTEM 01/03/25
BLAKE SYSTEM SYSTEM 01/03/25
....

18개의 행이 선택되었습니다.


DEFAULT_TABLESPACE와 TEMPORARY_TABLESPACE는 유저를 생성할때 지정한 것이며,
이때 테이블스페이스를 지정하지 않으면 오라클은 자동적으로
DEFAULT_TABLESPACE와 TEMPORARY_TABLESPACE를 system으로 이용합니다.



◈ 유저의 Object 정보 조회

- user_objects 데이터 사전을 이용하시면 됩니다.


SQL>col object_name format a25;
SQL>SELECT object_name, object_type
FROM user_objects
WHERE object_type = 'INDEX';

OBJECT_NAME OBJECT_TYPE
------------------------- ------------------
BIANRY_PK INDEX
BINARY_FK INDEX
BOARD_CTNT_LST_FK1 INDEX
BOARD_CTNT_LST_FK2 INDEX
BOARD_CTNT_LST_PK INDEX
BOARD_FK1 INDEX
BOARD_PK INDEX
COMMUNITY_TYPE_IDX INDEX
COMMUNITY_TYPE_PK INDEX
COMM_CTNT_LST_FK1 INDEX
COMM_CTNT_LST_FK2 INDEX
...
27개의 행이 선택되었습니다.

object_type를 보고 싶으면

SQL>SELECT object_type
FROM user_objects
GROUP BY object_type;

OBJECT_TYPE
------------------
INDEX
SEQUENCE
TABLE

'ORACLE' 카테고리의 다른 글

계층구조 쿼리의 예제  (0) 2004.10.15
계층 구조의 조회(Hierarchical Queries)  (0) 2004.10.15
EXECUTE IMMEDIATE를 이용한 Dynamic SQL  (0) 2004.10.15
중복된 RECORD 삭제 방법  (0) 2004.10.15
*새로운 Oracle 9i의 쿼리문*  (0) 2004.10.15