오라클 객체 종류
객체 종류 | 설명 |
테이블(Table) | 데이터를 저장하기 위한 가장 기본적인 논리적 데이터 저장 구조 행과 열로 구성됨 |
시퀀스(Sequence) | 일련번호를 생성하는 객체. 숫자 데이터를 일정한 방향으로 증가하도록 만들어주는 메커니즘 → Primary Key(PK)에서 자주 쓰임 |
뷰(View) | - 가상 테이블 - 실제 데이터를 저장하는 데이터 저장 장치가 아니라 하나 또는 그 이상의 테이블의 데이터를 참조하여 단순히 보여주는 역할만 수행하는 객체 |
인덱스(Index) | 테이블의 검색 효율을 높이기 위해 테이블 내의 원하는 레코드를 빠르게 찾아갈 수 있도록 만들어진 데이터 구조 (ROWID) |
시노님(Synonym) | 데이터베이스 객체에 대한 별칭을 부여하는 객체 |
Sequence(시퀀스)
- 일련번호를 생성하는 객체
- 숫자 데이터를 일정한 방향으로 증가하도록 만들어주는 메커니즘
- Primary Key(PK)에서 자주 쓰임
- 시퀀스는 테이블과는 독립적으로 저장되고 생성된다. 따라서 하나의 시퀀스를 여러 테이블에서 쓸 수 있다.
CREATE SEQUENCE 시퀀스명
[INCREMENT BY n] --n만큼 증가
[START WITH n] --시작값으로 n을 설정
[ {MAXVALUE n | NOMAXVALUE} ] --최댓값으로 n을 설정 (default = 9999999999999999999999999999)
[ {MINVALUE n | NOMINVALUE} ] --최솟값으로 n을 설정
[ {CYCLE | NOCYCLE} ] --1부터 다시 사이클 | maxvalue에 도달하면 끝 (default = NOCYCLE)
[ {CACHE | NOCACHE} ] --cache를 쓰겠다 | 쓰지 않겠다 (default = NOCACHE)
CACHE: 메모리에 시퀀스 값을 미리 할당한다.
CACHE 10이 설정되어있을 경우, Sequence 번호를 한번에 10개씩 메모리에 올려놓고 작업을 한다. 만일 메모리에 21~30번까지 시퀀스 번호를 올려놓았다고 가정할 때, DB를 재시작하면 메모리에 있던 21~30번은 삭제되고 31~40번까지의 시퀀스 번호가 새로 올라가기 때문에 21번~30번의 시퀀스 번호가 존재하지 않을 수 있다.
NOCACHE: 메모리에 시퀀스 값을 미리 할당하지 않는다.
시퀀스 생성
--dept의 pk로 사용되는 deptno 값으로 사용할 시퀀스를 만들어보자.
CREATE SEQUENCE dept_deptno_seq
START WITH 60 --60부터 시작
INCREMENT BY 10 --10씩 증가
MAXVALUE 99 --99까지
MINVALUE 60 --60부터
NOCACHE
NOCYCLE;
데이터 사전 조회
SELECT * FROM user_sequences WHERE sequence_name='DEPT_DEPTNO_SEQ';
SELECT * FROM user_objects WHERE object_type='SEQUENCE';
시퀀스 사용법
CURRVAL: 시퀀스의 현재값 (맨 처음에는 확인 불가. NEXTVAL 1회 실행 후 확인 가능)
SELECT dept_deptno_seq.CURRVAL FROM dual;
--현재 시퀀스값 확인
NEXTVAL: 시퀀스의 다음값 (CURRVAL + INCREMENT BY n)
SELECT dept_deptno_seq.NEXTVAL FROM dual;
--다음 시퀀스값 확인
예제
dept 테이블의 PK로 사용되는 deptno 값으로 사용할 시퀀스를 만들어보자.
CREATE SEQUENCE dept_deptno_seq
START WITH 60
INCREMENT BY 10
MAXVALUE 99
MINVALUE 60
NOCACHE
NOCYCLE;
INSERT INTO dept(deptno, dname, loc)
VALUES(dept_deptno_seq.NEXTVAL, '홍보부', '인천'); --60
INSERT INTO dept(deptno, dname, loc)
VALUES(dept_deptno_seq.NEXTVAL, '기획부', '수원'); --70
INSERT INTO dept(deptno, dname, loc)
VALUES(dept_deptno_seq.NEXTVAL, '영업부1', '수원'); --80
INSERT INTO dept(deptno, dname, loc)
VALUES(dept_deptno_seq.NEXTVAL, '영업부2', '수원'); --90
INSERT INTO dept(deptno, dname, loc)
VALUES(dept_deptno_seq.NEXTVAL, '영업부3', '수원');
--ORA-08004: sequence DEPT_DEPTNO_SEQ.NEXTVAL exceeds MAXVALUE and cannot be instantiated
SELECT dept_deptno_seq.CURRVAL FROM dual;
시퀀스 수정
ALTER SEQUENCE 시퀀스명
INCREMENT BY n
MINVALUE n
MAXVALUE n
CYCLE | NOCYCLE
CACHE n | NOCACHE;
[주의] START WITH(초기값)은 변경할 수 없다.
초기값을 변경하려면 시퀀스를 지우고 다시 만들어야 한다.
ALTER SEQUENCE DEPT_DEPTNO_SEQ
START WITH 7;
--오류 보고 -
--ORA-02283: cannot alter starting sequence number
시퀀스 삭제
DROP SEQUENCE 시퀀스명;
--dept_deptno.seq를 삭제하세요
DROP SEQUENCE dept_deptno_seq;
View(뷰)
- 하나의 가상 테이블 또는 테이블에 대한 데이터베이스 관리 시스템에 저장된 SELECT 구문
- 실제 데이터를 저장하는 데이터 저장 장치가 아니라, 하나 또는 그 이상의 테이블의 데이터를 참조하여 단순히 보여주는 역할만 수행한다.
- 데이터를 보거나 변경할 수 있는 창과 같다.
- [장점]
- 데이터의 복잡성을 감소시킴
- 복잡한 질의를 감소시킴
- 기본 테이블의 데이터를 다양한 관점으로 보여줌
뷰 생성
CREATE [OR REPLACE] VIEW 뷰이름 --뷰를 생성하거나 기존의 뷰에 새로운 뷰를 덮어씌울 경우(or replace)
AS
SELECT 컬럼명1, 컬럼명2 ... FROM 뷰에 사용할 테이블명 WHERE 조건;
예시
--emp 테이블에서 부서번호가 20인 사원들의 정보를 뷰(view)로 만드세요.
--뷰 이름: emp20_view
CREATE OR REPLACE VIEW emp20_view
AS
SELECT * FROM emp WHERE deptno = 20;
--emp테이블에서 30번 부서만 EMPNO를 EMP_NO로, ENAME을 NAME으로,
--SAL를 SALARY로, DEPTNO를 DNO로 바꾸어 EMP30_VIEW를 생성하세요.
CREATE OR REPLACE VIEW emp30_view
AS
SELECT empno AS emp_no, ename AS name, sal AS salary, deptno AS dno
FROM emp
WHERE deptno = 30;
--원테이블(emp)에서 WARD가 10번 부서로 부서이동을 하면 VIEW는 어떻게 될까?
UPDATE emp SET deptno = 10 WHERE ename = 'WARD';
SELECT * FROM emp30_view; --WARD가 VIEW에서 빠짐
--VIEW를 수정하면 어떻게 될까?
UPDATE emp30_view SET salary=3000 WHERE name = 'BLAKE'; --원테이블에서도 BLAKE의 급여가 변경됨
WITH READ ONLY
VIEW를 수정하면 원테이블도 수정되고, 원테이블을 수정하면 VIEW도 수정된다.
만약 VIEW를 수정하지 못하게 하려면 VIEW를 생성할 때 WITH READ ONLY (읽기전용) 옵션을 준다.
CREATE [OR REPLACE] VIEW 뷰이름 --뷰를 생성하거나 기존의 뷰에 새로운 뷰를 덮어씌울 경우(or replace)
AS
SELECT 컬럼명1, 컬럼명2 ... FROM 뷰에 사용할 테이블명 WHERE 조건
WITH READ ONLY;
[예제]
--고객 테이블의 고객 정보 중 나이가 19세 이상인 고객의 정보를 확인하는 뷰를 만들어보세요.
--단, 뷰의 이름은 MEMBER_19VIEW로 하고, 덮어쓰기 가능 및 읽기전용으로 만드세요.
CREATE OR REPLACE VIEW member_19view
AS
SELECT * FROM member WHERE age >= 19
WITH READ ONLY;
=> 원테이블 변경 가능(뷰에도 영향 미침), 뷰는 변경 불가능
--원 테이블 변경: member에서 아이디가 id1인 회원의 나이를 17세로 수정하세요
UPDATE member SET age=17 WHERE userid='id1';
SELECT * FROM member_19view ORDER BY AGE; --id1인 회원이 뷰에서도 제거됨
--member_19view에서 아이디가 'id3'인 회원의 마일리지를 500점 추가하세요
UPDATE member_19view SET mileage = mileage + 500 WHERE userid='id3';
--SQL 오류: ORA-42399: cannot perform a DML operation on a read-only view
테이블들을 조인한 뷰는 읽기전용
--카테고리, 상품, 공급업체를 JOIN한 VIEW를 만드세요 (뷰 이름: prod_view)
CREATE OR REPLACE VIEW prod_view
AS
SELECT * FROM CATEGORY C JOIN PRODUCTS P
ON c.category_code = p.category_fk
JOIN SUPPLY_COMP S
ON p.ep_code_fk = s.ep_code;
SELECT category_name, products_name, output_price, ep_name FROM prod_view;
3개의 관련된 테이블들을 조인하여 기본 테이블의 데이터를 다양한 관점으로 보여줄 수 있게 되었고, 코드도 훨씬 간결해졌다.
한편, JOIN문으로 생성된 뷰는 읽기 전용으로만 사용이 가능하다. 뷰를 변경하려고 시도하면 오류가 난다.
UPDATE prod_view SET category_name='텔레비전' WHERE cnum=2;
WITH CHECK OPTION
- WHERE절의 조건을 엄격하게 유지하도록 제한함
- WHERE절에 사용된 컬럼값을 변경하지 못한다.
CREATE [OR REPLACE] VIEW 뷰이름 --뷰를 생성하거나 기존의 뷰에 새로운 뷰를 덮어씌울 경우(or replace)
AS
SELECT 컬럼명1, 컬럼명2 ...
FROM 뷰에 사용할 테이블명
WHERE 조건
WITH CHECK OPTION;
[예제]
CREATE OR REPLACE VIEW emp20vw
AS
SELECT * FROM emp
WHERE deptno=20 --deptno=20에서 다른 부서로 이동 불가능
WITH CHECK OPTION CONSTRAINT emp20vw_ck;
--deptno=20인 직원의 정보를 변경하자.
UPDATE emp20vw SET sal=sal+500 WHERE empno=7369; --sal은 변경 가능
UPDATE emp20vw SET deptno=30 WHERE empno=7369; --deptno는 변경 불가능
--ORA-01402: view WITH CHECK OPTION where-clause violation
데이터 사전 조회
- user_view
- user_objects;
SELECT * FROM user_views WHERE view_name = 'EMP20VW';
SELECT text FROM user_views WHERE view_name = 'EMP20VW';
SELECT * FROM user_objects WHERE object_name = 'EMP20VW';
뷰 삭제
DROP VIEW 뷰이름
--emp20vw를 삭제하고, 데이터 사전에서 조회해보세요.
DROP VIEW emp20vw;
SELECT * FROM user_views WHERE view_name = 'EMP20VW';
Index(인덱스)
- 테이블 값에 빠르게 접근할 수 있도록 하는 데이터베이스 객체
- 보다 빨리 데이터를 검색할 수 있도록 도와주는 선택적 구조
- 일반 사전에서 ABCD 순으로 정렬되면 단어를 찾을 때 검색이 용이하듯, SQL에서는 인덱스를 이용하여 데이터를 신속하게 검색하도록 한다.
- 특정 테이블에서 인덱스를 이용하면 컬럼의 자료가 내부에서 순차적으로 정렬되어 자료 검색시 정렬된 값을 이용해 자료를 검색할 수 있다.
- 인덱스를 최적으로 구성하여 사용하면 데이터 파일에 대한 I/O를 줄일 수 있고, 성능을 향상시킬 수 있다.
- 그러나 테이블에 과도한 인덱스 사용한 테이블을 입력, 수정, 삭제할 때 오히려 많은 과부하를 발생시킬 수 있다. 따라서 언제, 어디에 인덱스를 만들지 잘 고려해서 사용해야 한다.
인덱싱할 테이블 선택
- 쿼리가 적은 양의 결과를 가져오는 경우 테이블에 인덱스를 인덱스를 사용한다.
(테이블 전체 행의 10~15% 미만이 검색 대상이 되는 경우) - 수정이 많은 테이블에서는 인덱싱을 하지 않는다.
WHERE절이 자주 사용되는 테이블에 대해 인덱스를 생성한다.
인덱싱할 컬럼의 결정
- WHERE절에서 가장 빈번하게 지정되는 컬럼을 선택한다.
- 유일한 값을 갖는 컬럼을 인덱스로 사용한다.
- 두 개 이상의 테이블을 조인하기 위해 사용되는 컬럼을 인덱싱한다.
- 자주 수정되는 컬럼은 인덱싱을 하지 않는다.
→ PK, FK가 이러한 조건들에 가장 만족한다.
INDEX 생성
- 자동 생성
PK나 UNIQUE 제약 조건을 정의하면 UNIQUE 인덱스가 자동적으로 생성된다. - 사용자가 생성
column에 UNIQUE 인덱스 또는 NON-UNIQUE 인덱스를 생성한다.
* unique index: 지정된 열의 값이 고유함을 보장
* non-unique index: 지정된 열의 값에 중복을 허용
CREATE [UNIQUE] INDEX 인덱스명 ON 테이블명 (컬럼명)
--emp테이블의 사원명(ename)을 인덱싱하세요.
CREATE INDEX emp_ename_indx ON emp (ename); --NON-UNIQUE 인덱스
데이터 사전에서 조회
- user_objects
- user_indexes
- user_ind_columns
--[1] user_objects
SELECT * FROM user_objects
WHERE object_type='INDEX' AND object_name='EMP_ENAME_INDX';
--[2] user_indexes
SELECT * FROM user_indexes
WHERE index_name = 'EMP_ENAME_INDX';
--[3] user_ind_columns
SELECT * FROM user_ind_columns
WHERE table_name ='EMP';
검색속도 차이 비교
색인 전: 0.003초
SELECT * FROM emp WHERE ename LIKE '%E%';
색인 후: 0.001초 >> 검색 속도가 빨라졌다.
CREATE INDEX emp_ename_indx ON emp (ename);
SELECT * FROM emp WHERE ename LIKE '%E%';
인덱스 삭제
- 인덱스 수정은 없다. 인덱스를 고치고 싶다면 삭제하고 다시 생성하는 방법밖에 없다.
DROP INDEX 인덱스명;
--emp_ename_indx를 삭제하세요.
DROP INDEX emp_ename_indx;
SELECT * FROM user_indexes
WHERE index_name = 'EMP_ENAME_INDX'; --검색 결과 없음
Synonym(동의어)
- 오라클 객체(테이블, 뷰, 시퀀스, 프로시저 등)에 대한 별칭(alias)
- 즉, 객체에 대한 참조를 의미한다.
- 다른 유저의 객체를 참조할 때 많이 사용한다.
- 동의어 사용시 장점
- 객체의 긴 이름을 간편한 이름으로 참조하여 SQL코딩을 단순화할 수 있다.
- 객체를 참조하는 사용자의 오브젝트를 감출 수 있어 보안을 유지할 수 있다.
동의어 생성
CREATE [PUBLIC] SYNONYM 시노님명 FOR 객체명(스키마.테이블명);
CREATE SYNONYM A FOR mystar.note;
--mystar유저의 note테이블에 대한 시노님 만들기 (시노님명: A)
Microsoft Windows [Version 10.0.22621.3155]
(c) Microsoft Corporation. All rights reserved.
C:\Users\user>sqlplus system/oracle --오라클에 접근
SQL*Plus: Release 11.2.0.2.0 Production on 목 2월 22 09:47:47 2024
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL> show user
USER is "SYSTEM"
SQL> CREATE USER mystar
2 identified by mystar; //mystar의 비밀번호: mystar
User created.
SQL> conn mystar/mystar
ERROR:
ORA-01045: user MYSTAR lacks CREATE SESSION privilege; logon denied
Warning: You are no longer connected to ORACLE.
SQL> show user
USER is ""
SQL> conn system/oracle
Connected.
SQL> grant connect.resource to mystar;
grant connect.resource to mystar
*
ERROR at line 1:
ORA-00990: missing or invalid privilege
SQL> grant connect, resource to mystar;
Grant succeeded.
SQL> conn mystar/mystar
Connected.
SQL> show user
USER is "MYSTAR"
SQL> create table note(
2 no number(2),
3 msg varchar2(30)
4 );
Table created.
SQL> desc note;
Name Null? Type
----------------------------------------- -------- ----------------------------
NO NUMBER(2)
MSG VARCHAR2(30)
SQL> insert into note values(1, '안녕하세요');
1 row created.
SQL> insert into note values(2, '반가워요~');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from note;
NO MSG
---------- ------------------------------------------------------------
1 안녕하세요
2 반가워요~
SQL> show user
USER is "MYSTAR"
SQL> grant all on note to scott;
Grant succeeded.
SQL> conn scott/tiger
Connected.
SQL> select * from mystar.note;
NO MSG
---------- ------------------------------------------------------------
1 안녕하세요
2 반가워요~
SQL> show user
USER is "SCOTT"
SQL> insert into mystar.note values(3, '저는 스콧이에요');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from mystar.note;
NO MSG
---------- ------------------------------------------------------------
1 안녕하세요
2 반가워요~
3 저는 스콧이에요
SQL> show user
USER is "SCOTT"
SQL> create synonym A for mystar.note;
create synonym A for mystar.note
*
ERROR at line 1:
ORA-01031: insufficient privileges
SQL> conn system/oracle
Connected.
SQL> grant create synonym to scott;
Grant succeeded.
SQL> conn scott/tiger
Connected.
SQL> show user
USER is "SCOTT"
SQL> create synonym A for mystar.note;
Synonym created.
SQL> select * from A;
NO MSG
---------- ------------------------------------------------------------
1 안녕하세요
2 반가워요~
3 저는 스콧이에요
SQL> update A set msg='동의어를 생성했어요' where no=1;
1 row updated.
SQL> select * from A;
NO MSG
---------- ------------------------------------------------------------
1 동의어를 생성했어요
2 반가워요~
3 저는 스콧이에요
SQL> commit;
Commit complete.
동의어 삭제
DROP SYNONYM 시노님명;