레이블이 오라클자바강좌인 게시물을 표시합니다. 모든 게시물 표시
레이블이 오라클자바강좌인 게시물을 표시합니다. 모든 게시물 표시

2013년 10월 15일 화요일

오라클 동의어(Oracle Synonym) 오라클 동의어(Oracle Synonym) - 테이블, 뷰, 시쿼스에 대한 별칭

오라클 동의어(Oracle Synonym)

오라클 동의어(Oracle Synonym)
- 테이블, 뷰, 시쿼스에 대한 별칭, 동의어
- public, private로 생성 가능
- Public synonym은 생성할 수 있는 권한이 있는 user만이 만들 수 있으며, 모든 user들이 사용할 수 있다.

[문법]
CREATE [PUBLIC] SYNONYM 
 synonym명 FOR object;
DROP [PUBLIC] SYNONYM synonym명; 
[예]
CREATE SYNONYM emp FOR scott.emp;
DROP SYNONYM emp;
 

SQL> conn system/onj
 
SQL> SELECT * FROM s_emp;
(* Error 발생)
 
SQL> SELECT * FROM scott.s_emp;
(* system user는 SELECT ANY TABLE 권한을 가지고 있으므로 성공)
 
SQL> CREATE SYNONYM s_emp FOR scott.s_emp;
 
SQL> SELECT * FROM s_emp;
 
SQL> CREATE TABLE s_emp (a number);
(* Error 발생)
 
Base table의 이름이 바뀌면 Synonym은 더 이상 사용할 수 없게 된다.

SQL> conn scott/tiger

SQL> RENAME s_emp TO e;

SQL> conn system/manager

SQL> SELECT * FROM s_emp;
(* 에러 발생)

SQL> conn scott/tiger

SQL> RENAME e TO s_emp;


오라클자바커뮤니티에서 설립한 개발자교육6년차 오엔제이프로그래밍 실무교육센터(오라클SQL,튜닝,힌트,자바프레임워크,안드로이드,아이폰,닷넷 실무개발강의)  




2013년 8월 26일 월요일

오라클 테이블 생성 예제

테이블 생성 하기


오라클자바커뮤니티에서 설립한  개발자실무교육6년차 오엔제이프로그래밍 실무교육센터
(신입사원채용무료교육, 오라클, SQL, 튜닝, 자바, 스프링, Ajax, jQuery, 안드로이드, 아이폰, 닷넷, C#, ASP.Net)   www.onjprogramming.co.kr 


 
à 오라클을 설치하게 되면 SCOTT계정은 자동으로 생성되어 있을 것이다. 그리고 default tablespace SYSTEM 테이블스페이스로 설정 되어 있다. 원래 SYSTEM 테이블스페이스에 사용자의 테이블을 만드는 것은 좋은 방법이 아니다. 왜냐면 이 부분은 오라클 시스템에서 사용되는 객체들이 저장되는 곳이기 때문이다(딕셔너리 정보 등이 저장된다) . 그러므로 우선 SYS 계정으로 접속하여 SCOTT 사용자의 default tablespace USERS 라는 테이블스페이스로 변경하자. 그리고 실습을 위해 USER_DATA 라는 테이블스페이스를 만들자. 데이터파일의 경로는 PC환경에 맞게 수정하길 바란다.
 
SQL> connect / as sysdba
연결되었습니다.
 
SQL> alter user scott default tablespace users;
 
사용자가 변경되었습니다.
 
SQL> create tablespace user_data
  2  datafile 'C:\oracle\oradata\wink\test01.dbf'
  3  size 10m
  4  autoextend on
  5  next 1m
  6  maxsize 1000m;
 
테이블 영역이 생성되었습니다.
 
SQL> connect scott/tiger
연결되었습니다.
 
à 아래 예문에서 주의 깊게 볼 부분은 tablespace 구이다. 이것은 employee 테이블을 어느 테이블스페이스에 만들것인지에 대해 설정이며 생략되면 scott 사용자의 defaut tablespace에 만들어 지게 된다. 또한 테이블스페이스에서 지정한 매개변수들을 그대로 employee 테이블은 상속 받게 된다. 물론 그 다음 예문처럼 명시적으로 지정을 하는 것도 가능하다.
 
SQL> create table employee (
  2  empno number(4) primary key,
  3  ename varchar2(15) not null,
  4  addr varchar2(50) ,
  5  sal number(8,2)
  6  ) tablespace user_data;
 
테이블이 생성되었습니다.
 
SQL> create table employee2 (
  2  empno number(4) primary key,
  3  ename varchar2(15) not null,
  4  addr varchar2(50) ,
  5  sal number(8,2)
  6  )
  7  pctfree 10
  8  pctused 40
  9  tablespace user_data
 10  storage (
 11     initial 10k
 12     next 10k
 13     maxextents 20
 14     pctincrease 0
 15  );
 
테이블이 생성되었습니다.

[오라클자바커뮤니티강좌,oraclejava,javaoracle교육강좌강의,오라클자바실무개발잘하는학원,오라클강좌자바강좌강의]Flashback Feature – Transaction Query


FlashBack Transaction Query라고 하는 것은 이전 강좌에서 설명 드렸던 Flashback Version Query의 결과로 나타난 해당 Transaction에 대해 특별한 정보를 얻을 수 있는 것 정도로 보시면 됩니다.


오라클자바커뮤니티에서 설립한  개발자실무교육6년차 오엔제이프로그래밍 실무교육센터
(신입사원채용무료교육, 오라클, SQL, 튜닝, 자바, 스프링, Ajax, jQuery, 안드로이드, 아이폰, 닷넷, C#, ASP.Net)   www.onjprogramming.co.kr 


VERSIONS_XID 값이 트랜잭션의 아이디라고 했는데 이 값을 FLASHBACK_TRANSACTION_QUERY의 인자 값으로 줘서 쿼리를 실행 하면 해당 트랜잭션에 대한 정보를 볼 수 있습니다.

예를 들면 어떤 DML을 이용했으며 어떠한 SQL 구문이 실행 되었다든지 하는 것이 확인 가능 합니다.

아래의 예를 통해 이해 하도록 하겠습니다.

아래에서 “0600030021000000”  값이 VERSIONS_XID 값 입니다. 이 값은 Flashback Version Query의 결과로서 얻어 낼 수 있습니다. 이전 강좌의 내용을 참고 하세요~

SELECT xid, operation, start_scn,commit_scn, logon_user, undo_sql
FROM  flashback_transaction_query
WHERE  xid = HEXTORAW('0600030021000000');


XID              OPERATION                        START_SCN COMMIT_SCN
---------------- -------------------------------- ---------- ----------
LOGON_USER
------------------------------
UNDO_SQL
----------------------------------------------------------------------------------------------------
0600030021000000 UPDATE                              725208    725209
SCOTT
update "SCOTT"."FLASHBACK_VERSION_QUERY_TEST" set "DESCRIPTION" = 'ONE' where ROWID = 'AAAMP9AAEAAAA
AYAAA';

0600030021000000 BEGIN                                725208    725209
SCOTT

XID              OPERATION                        START_SCN COMMIT_SCN
---------------- -------------------------------- ---------- ----------
LOGON_USER
------------------------------
UNDO_SQL
----------------------------------------------------------------------------------------------------



2 rows selected.
 

2013년 8월 5일 월요일

[자바교육,오라클교육,자바프레임워크, 스트럿츠]Struts Action처리 후 다음 View 결정하기, 오라클자바커뮤니티

Action처리 후 다음 View 결정하기 


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의) 
 www.onjprogramming.co.kr 


Action 클래스의 execute() 메소드를 보시면 Return형이 org.apache.struts.action.ActionForward임을 알 수 있습니다. ActionForward 클래스는 execute()메소드가 종료된 후 Controller에서 제어를 넘길 곳을 지정 합니다.

또한 코드 내에서 실제 파일명을 주는 대신 ActionForward 매핑에 JSP페이지(View)를 할당하고 이 ActionForward를 웹 애플리케이션 전체에서 사용 가능 하게 할 수 있습니다.

아래는 struts-config.xml 파일 내의 ActionForward 매핑 예 입니다.

<global-forwards>
        <forward name="success" path="/main.jsp" />
        <forward name="logoff" path="/logoff.do" />
        <forward name="login" path="/login.jsp" />
    </global-forwards>

또는 어떠한 Action에서만 Actionforward를 참조하게 하기 위해서는 다음과 같이 할 수도 있습니다.

<action
        Path=”/LoginSunmit”
        Type=”login2.LoginAction”
        Scope=”request”>
        <forward name=”SUCCESS” path=”/success.jsp” redirect=”true”/>
</action>

위에서 redirect를 true로 했으므로 이 경우엔 forward가 아니라 redirection을 이용합니다.

아래는 로그인 예제의 LogoffAction.java(로그오프 Action 처리) 입니다.

package login2;

import org.apache.struts.action.Action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;

import login2.LoginForm;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class LogoffAction extends Action {       
       
        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
               
                //필요한 어트리뷰트를 뽑아 냅니다.
                //LoginAction에서 사용자의 로그온개체를 Consants.USER_KEY라는 이름으로 세션에 저장
                HttpSession session = request.getSession();
                UserInfoVO userinfo = (UserInfoVO)session.getAttribute(Constants.USER_KEY);
               
                if (userinfo != null) {
                        //로그를 남기자
                        StringBuffer buf = new StringBuffer("User Logout : " + userinfo.getId());
                        servlet.log(buf.toString());                                       
                }               
               
                //사용자의 로그인을 삭제, session.invaidate() 의 경우 션의 모든 것을 무효화 시킴.
                session.removeAttribute(Constants.USER_KEY);
               
                //성공적으로 처리 되었음을 알림
                return (mapping.findForward(Constants.SUCCESS));
               
        }

       

2013년 8월 3일 토요일

[Oracle Hint]ACCESS 경로를 변경하는 힌트(NO_EXPAND) , 오라클힌트강좌 CCESS 경로를 변경하는 힌트(NO_EXPAN)

[Hint]ACCESS 경로를 변경하는 힌트(NO_EXPAN)

NO_EXPAND 힌트는 CBO(COST BASED Optimizer) 모드에서 OR 조건이나 IN List등을 사용할 때 OR확장 (Concatenation등을)을 막는 것인데 실행 계획에 Concatenation등이 보이는 경우 이곳이 일어나지 않도록 처리해 줍니다.

구로디지털 오엔제이프로그래밍실무교육센터


OR UNION-ALL로 풀지 말고

아래의 예를 보죠~

[형식]

실습을 위해 먼저 옵티마이저 모드를 RULE로 바꾼 후

왜 바꾸냐 하면?  EMP 테이블의 경우 데이터 양이 적으므로 OR를 사용하더라도 FULL SCAN하는 실행계획을 만들어 내므로 고의로 CONCATENATION을 만들어 내기 위해 RULE BASED Optimizer Mode로 변경하는 것입니다. 물론 옵티마이저 모드를 CHOOSE로 한 후 테이블의 통계 정보를 삭제하는 경우에도 동일 합니다.

alter session set optimizer_mode=rule;

SELECT ename, sal
FROM   EMP
WHERE  JOB   = 'CLERK'
OR     JOB   = 'SALESMAN'

-----------------------------------------------------------------
Operation    Object Name  Rows   Bytes  Cost  
-----------------------------------------------------------------
SELECT STATEMENT Optimizer Mode=RULE                                
  CONCATENATION                                                 
    TABLE ACCESS BY INDEX ROWID   SCOTT.EMP                          
      INDEX <st1:placetype w:st="on">RANGE</st1:placetype> SCAN      SCOTT.IDX_EMP_JOB                         
    TABLE ACCESS BY INDEX ROWID   SCOTT.EMP                          
      INDEX <st1:placetype w:st="on">RANGE</st1:placetype> SCAN      SCOTT.IDX_EMP_JOB                         



SELECT
       ENAME, SAL
FROM   EMP
WHERE  JOB   = 'CLERK'
OR     JOB   = 'SALESMAN'

Operation            Object Name      Rows     Bytes    Cost     
SELECT STATEMENT Optimizer Mode=RULE                        6                        2            
  INLIST ITERATOR                                                                                     
    TABLE ACCESS BY INDEX ROWID         SCOTT.EMP        6           96         2            
      INDEX <st1:placetype w:st="on">RANGE</st1:placetype> SCAN             SCOTT.IDX_EMP_JOB      6                        1            




[실습]

-      실습을 위한 예제 테이블 및 데이터는 아래 링크에서 확인 바랍니다.

myemp1 : 1000만건
myemp1_old : 100만건
mydept : 5

테스트환경 : oracle 11g

아래와 같은 결과를 내기 위한 힌트 구문을 이해하고 왜 inlist iterator가 빠른지 느껴 보라.

먼저 인덱스를 하나 만들자.

SQL> create index idx_myemp1_sal on myemp1(sal);

인덱스가 생성되었습니다.


n  옵티마이저가 사용 못하도록 일단 숨기고

SQL> alter index idx_myemp1_sal invisible;

인덱스가 변경되었습니다.

n  인덱스가 없는 경우엔 무조건 FULL SCAN을 한다.


SQL> select count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000;

  COUNT(*)
----------
        15

   : 00:00:08.85


-----------------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |     5 | 17035   (2)| 00:03:25 |
|   1 |  SORT AGGREGATE    |        |     1 |     5 |            |          |
|*  2 |   TABLE ACCESS FULL| MYEMP1 |    15 |    75 | 17035   (2)| 00:03:25 |
-----------------------------------------------------------------------------

SQL> select count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000;

  COUNT(*)
----------
        15

   : 00:00:08.82

Execution Plan
----------------------------------------------------------
Plan hash value: 3929728256

-------------------------------------
| Id  | Operation          | Name   |
-------------------------------------
|   0 | SELECT STATEMENT   |        |
|   1 |  SORT AGGREGATE    |        |
|*  2 |   TABLE ACCESS FULL| MYEMP1 |


n  인덱스를 다시 보이도록 하자.
SQL> alter index idx_myemp1_sal visible;

인덱스가 변경되었습니다.

SQL> select /*+ index(myemp1 idx_myemp1_sal)  */ count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000;

  COUNT(*)
----------
        15

   : 00:00:00.01

-------------------------------------------------------------------------------------
| Id  | Operation          | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                |     1 |     5 |     5   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |                |     1 |     5 |            |          |
|   2 |   INLIST ITERATOR  |                |       |       |            |          |
|*  3 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |    15 |    75 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

n  아래처럼 힌트를 안써도 CBO인 경우 알아서 인덱스를 사용한다.
SQL> select count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000;

  COUNT(*)
----------
        15

   : 00:00:00.00

-------------------------------------------------------------------------------------
| Id  | Operation          | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                |     1 |     5 |     5   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |                |     1 |     5 |            |          |
|   2 |   INLIST ITERATOR  |                |       |       |            |          |
|*  3 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |    15 |    75 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

SQL> select count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000;

  COUNT(*)
----------
        15

   : 00:00:00.01

---------------------------------------------
| Id  | Operation          | Name           |
---------------------------------------------
|   0 | SELECT STATEMENT   |                |
|   1 |  SORT AGGREGATE    |                |
|   2 |   CONCATENATION    |                |
|*  3 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |
|*  4 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |
|*  5 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |
---------------------------------------------



where절에 3개의 or 만으로는 inlist iterrator concatenation을 비교해 보기 어려워
이번에는 sal > 900000 이라는조건을 하나 더 줘보자. 그리고 통계정보도 보기 위해
set autotrace on 이라고 하자.

SQL>set autotrace on;

SQL> select count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000
  5  or sal > 900000;

  COUNT(*)
----------
   5500010

   : 00:00:02.53


---------------------------------------------
| Id  | Operation          | Name           |
---------------------------------------------
|   0 | SELECT STATEMENT   |                |
|   1 |  SORT AGGREGATE    |                |
|   2 |   CONCATENATION    |                |
|*  3 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |
|*  4 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |
|*  5 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |
|*  6 |    INDEX RANGE SCAN| IDX_MYEMP1_SAL |

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      12973  consistent gets
      12963  physical reads
          0  redo size
        438  bytes sent via SQL*Net to client
        416  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select /*+ index(myemp1 idx_myemp1_sal)  */ count(*) from myemp1
  2  where sal = 100000
  3  or sal = 200000
  4  or sal = 300000
  5  or sal > 900000;

  COUNT(*)
----------
   5500010

   : 00:00:01.50

--------------------------------------------------------------------------------------
| Id  | Operation           | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                |     1 |     5 | 12745   (1)| 00:02:33 |
|   1 |  SORT AGGREGATE     |                |     1 |     5 |            |          |
|   2 |   CONCATENATION     |                |       |       |            |          |
|   3 |    INLIST ITERATOR  |                |       |       |            |          |
|*  4 |     INDEX RANGE SCAN| IDX_MYEMP1_SAL |    15 |    75 |     5   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN | IDX_MYEMP1_SAL |  5499K|    26M| 12740   (1)| 00:02:33 |
--------------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      12972  consistent gets
          0  physical reads
          0  redo size
        438  bytes sent via SQL*Net to client
        416  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
1      rows processed

4 index range scan concatenation 했을 때는 physical read가 발생하며
inlist iterator의 경우 physical read 0이다 그리고 시간도 조금 단축되고
확인 바란다. 쿼리가 단문인 경우 별차이 없다고 느끼겠지만 장문의 반복적인 쿼리 에서는 많은 성능 차이가 날 것이다. 그리고 CBO인 경우 no_expend를 사용 안하더라도 인덱스가 있는 경우 알아서 inlist iterator 연산을 수행하도록 실행계획을 작성하니 별 걱정 안해도 될 것 같다