데이터베이스(database, DB)는 여러 사람이 공유하여 사용할 목적으로 체계화해 통합, 관리하는 데이터의 집합이다.
Key 란?
검색, 정렬 시 Tuple을 구분할 수 있는 기준이 되는 속성
Tuple을 유일하게 식별하기 위해 사용하는 속성들의 부분 집합
(기본키로 사용할 수 있는 속성들)
다음 2가지 조건을 만족해야 후보키가 될 수 있음
후보키 중에서 선택한 Main Key
기본키(PK)의 특징
후보키 중에서 기본키를 제외한 나머지 키 = 보조키
유일성은 만족하지만, 최소성은 만족하지 못하는 키
다른 릴레이션의 기본키를 그대로 참조하는 속성의 집합
Join 이란?
두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색하는 방법
테이블을 연결하려면, 적어도 하나의 칼럼을 서로 공유하고 있어야 하므로 이를 이용하여 데이터 검색에 활용
SELECT
A.NAME, B.AGE
FROM EX_TABLE A
INNER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
SELECT
A.NAME, B.AGE
FROM EX_TABLE A
LEFT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
SELECT
A.NAME, B.AGE
FROM EX_TABLE A
RIGHT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
SELECT
A.NAME, B.AGE
FROM EX_TABLE A
FULL OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
SELECT
A.NAME, B.AGE
FROM EX_TABLE A
CROSS JOIN JOIN_TABLE B
SELECT
A.NAME, B.AGE
FROM EX_TABLE A, EX_TABLE B
해커에 의해 조작된 SQL 쿼리문이 데이터베이스에 그대로 전달되어 비정상적 명령을 실행시키는 공격 방법
보통 로그인을 할 때, 아이디와 비밀번호를 input 창에 입력하게 된다.
예를 들어 아이디가 abc, 비밀번호가 1234일 때 쿼리는 아래와 같은 방식으로 전송된다.
SELECT * FROM USER WHERE ID = "abc" AND PASSWORD = "1234";
1234; DELETE * USER FROM ID = "1";
보안이 완벽하지 않은 경우, 이처럼 비밀번호가 아이디와 일치해서 TRUE가 되고 뒤에 작성한 DELETE 문도 데이터베이스에 영향을 줄 수 있게 되는 치명적인 상황이다.
이 밖에도 기본 쿼리문의 WHERE절에 OR문을 추가하여 '1' = '1'
과 같은 true 문을 작성하여 무조건 적용되도록 수정한 뒤 DB를 마음대로 조작할 수도 있다.
시스템에서 발생하는 에러 메시지를 이용해 공격하는 방법이다.
보통 에러는 개발자가 버그를 수정하는 면에서 도움을 받을 수 있는 존재이다.
해커들은 이를 역이용해 악의적인 구문을 삽입하여 에러를 유발시킨다.
즉 예를 들면, 해커는 GET 방식으로 동작하는 URL 쿼리 스트링을 추가하여 에러를 발생시킨다.
이에 해당하는 오류가 발생하면, 이를 통해 해당 웹 앱의 데이터베이스 구조를 유추할 수 있고 해킹에 활용한다.
로그인 전, 검증 로직을 추가하여 미리 설정한 특수문자들이 들어왔을 때 요청을 막아낸다.
view를 활용하여 원본 데이터베이스 테이블에는 접근 권한을 높인다.
일반 사용자는 view로만 접근하여 에러를 볼 수 없도록 만든다.
preparestatement를 사용하면 특수문자를 자동으로 escaping 해준다. (statement와는 다르게 쿼리문에서 전달인자 값을
?
로 받는 것)
이를 활용해 서버 측에서 필터링 과정을 통해서 공격을 방어한다.
웹 앱 개발 시, 데이터베이스를 선택할 때 고민하게 된다.
MySQL과 같은 SQL을 사용할까? 아니면 MongoDB와 같은 NoSQL을 사용할까?
보통 Spring에서 개발할 때는 MySQL을, Node.js에서는 MongoDB를 주로 사용했을 것이다.
하지만 단순히 프레임워크에 따라 결정하는 것이 아니다.
프로젝트를 진행하기에 앞서 적합한 데이터베이스를 택해야 한다.
SQL을 사용하면 RDBMS에서 데이터를 저장, 수정, 삭제 및 검색 할 수 있음
관계형 데이터베이스에는 핵심적인 두 가지 특징이 있다.
데이터는 테이블에 레코드로 저장되는데, 각 테이블마다 명확하게 정의된 구조가 있다.
해당 구조는 필드의 이름과 데이터 유형으로 정의된다.
따라서 스키마를 준수하지 않은 레코드는 테이블에 추가할 수 없다.
즉, 스키마를 수정하지 않는 이상은 정해진 구조에 맞는 레코드만 추가가 가능한 것이 관계형 데이터베이스의 특징 중 하나이다.
또한, 데이터의 중복을 피하기 위해 '관계'를 이용한다.
하나의 테이블에서 중복 없이 하나의 데이터만을 관리하기 때문에 다른 테이블에서 부정확한 데이터를 다룰 위험이 없어지는 장점이 있다.
비관계형 DB는 스키마도 없고, 관계도 없다.
NoSQL에서는 레코드를 문서(documents)라고 부른다.
여기서 SQL과 핵심적인 차이가 있는데, SQL은 정해진 스키마를 따르지 않으면 데이터 추가가 불가능하지만
NoSQL에서는 다른 구조의 데이터를 같은 컬렉션에 추가가 가능하다.
문서(documents)는 Json과 비슷한 형태로 데이터를 가지고 있다.
관계형 데이터베이스처럼 여러 테이블에 나누어 담지 않고, 관련 데이터를 동일한 '컬렉션'에 넣는다.
SQL에서는 Orders, Users, Products 테이블로 나눈 것을 NoSQL에서는 Orders에 한꺼번에 포함해서 저장하게 된다.
따라서 여러 테이블에 조인할 필요 없이, 이미 필요한 모든 것을 갖춘 문서를 작성하는 것이 NoSQL이다.
(NoSQL에는 조인이라는 개념이 존재하지 않음)
그러면 조인하고 싶을 때 NoSQL은 어떻게 할까?
컬렉션을 통해 데이터를 복제하여 각 컬렉션 일부분에 속하는 데이터를 정확하게 산출하도록 한다.
하지만 이렇게 할 경우, 데이터가 중복되어 서로 영향을 줄 위험이 있다.
따라서 조인을 잘 사용하지 않고, 자주 변경되지 않는 데이터일 때 NoSQL을 쓰면 상당히 효율적이다.
두 데이터베이스를 비교할 때 중요한 Scaling 개념도 존재한다.
데이터베이스 서버의 확장성은 '수직적' 확장과 '수평적' 확장으로 나누어진다.
수직적 확장 : 단순히 데이터베이스 서버의 성능을 향상시키는 것 (ex. CPU 업그레이드)
수평적 확장 : 더 많은 서버가 추가되고 데이터베이스가 전체적으로 분산됨을 의미 (하나의 데이터베이스에서 작동하지만 여러 호스트에서 작동)
데이터 저장 방식으로 인해 SQL 데이터베이스는 일반적으로 수직적 확장만 지원함
수평적 확장은 NoSQL 데이터베이스에서만 가능
어떤 데이터를 다루느냐에 따라 선택을 고려해야 한다.
SQL 장점
SQL 단점
NoSQL 장점
NoSQL 단점
NoSQL에서는 여러 컬렉션을 모두 수정해야 하기 때문에 비효율적
정규화를 해야 하는 이유는 잘못된 테이블 설계로 인해 Anomaly(이상 현상)가 나타나기 때문이다.
예) {Student ID, Course ID, Department, Course ID, Grade}
기본키가 {Student ID, Course ID} 인 경우
→ Course를 수강하지 않은 학생은 Course ID가 없는 현상이 발생함
결국 Course ID를 Null로 할 수밖에 없는데, 기본키는 Null이 될 수 없으므로 Table에 추가될 수 없음
굳이 삽입하기 위해서는 '미수강'과 같은 Course ID를 만들어야 함
불필요한 데이터를 추가해야 삽입할 수 있는 상황
만약 어떤 학생의 전공(Department)이 '컴퓨터'에서 '음악'으로 바뀌는 경우, 모든 Department를 '음악'으로 바꾸어야 함
그러나 일부를 깜빡하고 바꾸지 못하는 경우, 제대로 파악하지 못함
일부만 변경하여, 데이터가 불일치 하는 모순의 문제
만약 어떤 학생이 수강을 철회하는 경우,
{Student ID, Course ID, Department, Course ID, Grade} 의 정보 중에서 Student ID, Department와 같은 학생에 대한 정보도 함께 삭제됨
튜플 삭제로 인해 꼭 필요한 데이터까지 함께 삭제되는 문제
Index를 사용하지 않는 경우, MYI 파일은 비어져 있음
그러나 인덱싱하는 경우, MYI 파일이 생성됨
이후에 사용자가 Select 쿼리로 Index를 사용하는 Column을 탐색 시, MYI 파일의 내용을 검색함
사용하면 좋은 경우
(1) Where 절에서 자주 사용되는 Column
(2) 외래키가 사용되는 Column
(3) Join에 자주 사용되는 Column
Index 사용을 피해야 하는 경우
(1) Data 중복도가 높은 Column
(2) DML이 자주 일어나는 Column
INSERT
기존 Block에 여유가 없을 때, 새로운 Data가 입력됨
→ 새로운 Block을 할당 받은 후, Key를 옮기는 작업을 수행 (많은 양의 Redo가 기록되고, 유발)
→ Index split 작업 동안, 해당 Block의 Key 값에 대해서 DML이 블로킹 됨 (대기 이벤트 발생)
DELETE
[Table과 Index 상황 비교]
Table에서 Data가 delete 되는 경우 : Data가 지워지고, 다른 Data가 그 공간을 사용 가능
Index에서 Data가 delete 되는 경우 : Data가 지워지지 않고, 사용 안 됨 표시만 해둠
→ Table의 Data 수와 Index의 Data 수가 다를 수 있음
UPDATE
Table에서 update가 발생하면 → Index는 Update 할 수 없음
Index에서는 Delete가 발생한 후, 새로운 작업의 Insert 작업 / 2배의 작업이 소요되어 힘듦
가장 큰 목표는 테이블 간 중복된 데이터를 허용하지 않는 것이다.
중복된 데이터를 만들지 않으면 무결성을 유지할 수 있고, DB 저장 용량 또한 효율적으로 관리할 수 있다.
정규화에는 여러가지 단계가 있지만, 대체적으로 1~3단계 정규화까지의 과정을 거친다.
테이블 컬럼이 원자값(하나의 값)을 갖도록 테이블을 분리시키는 것을 말한다.
조건
Customer
Customer ID | First Name | Surname | Telephone Number |
---|---|---|---|
123 | Pooja | Singh | 555-861-2025, 192-122-1111 |
456 | San | Zhang | (555) 403-1659 Ext. 53; 182-929-2929 |
789 | John | Doe | 555-808-9633 |
현재 테이블은 전화번호를 여러 개 가지고 있어 원자값이 아니다. 따라서 1NF에 맞추기 위해서는 아래와 같이 분리할 수 있다.
Customer
Customer ID | First Name | Surname | Telephone Number |
---|---|---|---|
123 | Pooja | Singh | 555-861-2025 |
123 | Pooja | Singh | 192-122-1111 |
456 | San | Zhang | 182-929-2929 |
456 | San | Zhang | (555) 403-1659 Ext. 53 |
789 | John | Doe | 555-808-9633 |
현재 테이블은 전화번호를 여러 개 가지고 있어 원자값이 아니다. 따라서 1NF에 맞추기 위해서는 아래와 같이 분리할 수 있다.
테이블의 모든 컬럼이 완전 함수적 종속을 만족해야 한다.
쉽게 말하면, 테이블에서 기본키가 복합키(키1, 키2)로 묶여 있을 때, 두 키 중 하나의 키만으로 다른 컬럼을 결정지을 수 있으면 안 된다.
기본키의 부분집합 키가 결정자가 되어선 안 된다는 것
Electric Toothbrush Models
Manufacturer | Model | Model Full Name | Manufacturer Country |
---|---|---|---|
Forte | X-Prime | Forte X-Prime | Italy |
Forte | Ultraclean | Forte Ultraclean | Italy |
Dent-o-Fresh | EZbrush | Dent-o-Fresh EZbrush | USA |
Kobayashi | ST-60 | Kobayashi ST-60 | Japan |
Hoch | Toothmaster | Hoch Toothmaster | Germany |
Hoch | X-Prime | Hoch X-Prime | Germany |
Manufacture
와 Model
이 키가 되어 Model Full Name
을 알 수 있다.
Manufacturer Country
는 Manufacturer
로 인해 결정된다. (부분 함수 종속)
따라서, Model
과 Manufacturer Country
는 아무런 연관관계가 없는 상황이다.
결국 완전 함수적 종속을 충족시키지 못하고 있는 테이블이다. 부분 함수 종속을 해결하기 위해 테이블을 아래와 같이 나눠서 2NF를 만족할 수 있다.
Electric Toothbrush Manufacturers
Manufacturer | Manufacturer Country |
---|---|
Forte | Italy |
Dent-o-Fresh | USA |
Kobayashi | Japan |
Hoch | Germany |
Electric Toothbrush Manufacturers
Manufacturer | Model | Model Full Name |
---|---|---|
Forte | X-Prime | Forte X-Prime |
Forte | Ultraclean | Forte Ultraclean |
Dent-o-Fresh | EZbrush | Dent-o-Fresh EZbrush |
Kobayashi | St-60 | Kobayashi ST-60 |
Hoch | Toothmaster | Hoch Toothmaster |
Hoch | X-Prime | Hoch X-Prime |
2NF가 진행된 테이블에서 이행적 종속을 없애기 위해 테이블을 분리하는 것이다.
이행적 종속 : A → B, B → C 이면 A → C 가 성립된다.
조건
Tournament Winners
Tournament | Year | Winner | Winner Date of Birth |
---|---|---|---|
Indiana Invitational | 1998 | Al Fredrickson | 21 July 1975 |
Cleveland Open | 1999 | Bob Albertson | 28 September 1968 |
Des Moines Masters | 1999 | Al Fredrickson | 21 July 1975 |
Indiana Invitational | 1999 | Chip Masterson | 14 March 1977 |
현재 테이블에서는 Tournament
와 Year
이 기본키다.
Winner
는 이 두 복합키를 통해 결정된다.
하지만 Winner Date of Birth
는 기본키가 아닌 Winner
에 의해 결정되고 있다.
따라서 이는 3NF를 위반하고 있으므로 아래와 같이 분리해야 한다.
1) Tournament Winners
Tournament | Year | Winner |
---|---|---|
Indiana Invitational | 1998 | Al Fredrickson |
Cleveland Open | 1999 | Bob Albertson |
Des Moines Masters | 1999 | Al Fredrickson |
Indiana Invitational | 1999 | Chip Masterson |
2) Winner Dates of Birth
Winner | Date of Birth |
---|---|
Al Fredrickson | 21 July 1975 |
Bob Albertson | 28 September 1968 |
Al Fredrickson | 21 July 1975 |
Chip Masterson | 14 March 1977 |
데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위
상태를 변화시키는 것 = SQL 질의어를 통해 DB에 접근하는 것
- SELECT
- INSERT
- DELETE
- UPDATE
작업 단위 = 많은 SQL 명령문들을 사람이 정하는 기준에 따라 정하는 것
예시) 사용자 A가 사용자 B에게 만원을 송금한다.
* 이 때 DB 작업
- 1. 사용자 A의 계좌에서 만원을 차감한다.
: UPDATE 문을 사용해 사용자 A의 잔고를 변경
- 2. 사용자 B의 계좌에 만원을 추가한다.
: UPDATE 문을 사용해 사용자 B의 잔고를 변경
현재 작업 단위: 출금 UPDATE문 + 입금 UPDATE문
→ 이를 통틀어 하나의 트랜잭션이라고 한다.
→ 위 두 쿼리문 모두 성공적으로 완료되어야만 "하나의 작업(트랜잭션)이 완료되는 것이다. `Commit`
→ 작업 단위에 속하는 쿼리 중 하나라도 실패하면 모든 쿼리문을 취소하고 이전 상태로 돌려 놓아야 한다. `Rollback`
즉, 하나의 트랜잭션 설계를 잘 만드는 것이 데이터를 다룰 때 많은 이점을 가져다 준다.
트랜잭션이 DB에 모두 반영되거나, 혹은 전혀 반영되지 않아야 한다.
트랜잭션의 작업 처리 결과는 항상 일관성 있어야 한다.
둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다.
트랜잭션이 성공적으로 완료되었으면, 결과는 영구적으로 반영되어야 한다.
Commit
: 하나의 트랜잭션이 성공적으로 끝났고, DB가 일관성 있는 상태일 때, 이를 알려주기 위해 사용하는 연산
Rollback
: 하나의 트랜잭션 처리가 비정상적으로 종료되어 트랜잭션 원자성이 깨진 경우
transaction이 정상적으로 종료되지 않았을 때, last consistent state (예) Transaction의 시작 상태)로 roll back 할 수 있음
상황이 주어지면 DB 측면에서 어떻게 해결할 수 있을 지 대답할 수 있어야 함
이해를 위한 2가지 개념: DBMS의 구조 / Buffer 관리 정책
DBMS의 구조
다음 2가지로 분류
(1) Query Processor(질의 처리기) (2) Storage System(저장 시스템)
입출력 단위 : 고정 길이의 page 단위로 disk에 읽거나 쓴다.
저장 공간 : 비휘발성 저장 장치인 disk에 저장, 일부분을 Main Memory에 저장
Page Buffer Manager of Buffer Manager
DMBS의 Storage System에 속하는 모듈 중 하나로, Main Memory에 유지하는 페이지를 관리하는 모듈
Buffer 관리 정책에 따라, UNDO 복구와 REDO 복구가 요구되거나 그렇지 않게 되므로, transaction 관리에 매우 중요한 결정을 가져온다.
UNDO
필요한 이유
: 수정된 Page들이 Buffer 교체 알고리즘에 따라서 디스크에 출력될 수 있음
Buffer 교체는 ttransaction과는 무관하게 buffer의 상태에 따라서 결정됨
이로 인해, 정상적으로 종료되지 않은 transaction이 변경한 page들은 원상 복구 되어야 하는데, 이 복구를 undo 라고 함
2개의 정책 (수정된 페이지를 디스크에 쓰는 시점으로 분류)
1) steal : 수정된 페이지를 언제든지 디스크에 쓸 수 있는 정책
- 대부분의 DBMS가 채택하는 Buffer 관리 정책
- UNDO logging과 복구를 필요로 함
2) ¬steal : 수정된 페이지들을 EOT(End Of Transaction)까지는 버퍼에 유지하는 정책
- UNDO 작업이 필요하지 않지만, 매우 큰 메모리 버퍼가 필요함
Transaction이 종료되는 시점에 해당 transaction이 수정한 page를 디스크에 쓸 것인가 아닌가로 기준
1) FORCE : 수정했던 모든 페이지를 Transaction commit 시점에 disk에 반영
transaction이 commit 되었을 때 수정된 페이지들이 disk상에 반영되므로 redo 필요없음
2) ¬FORCE : commit 시점에 반영하지 않는 정책
transaction이 disk상의 DB에 반영되지 않을 수 있기에 redo 복구가 필요 (대부분의 DBMS 정책)
트랜잭션에서 일관성 없는 데이터를 허용하도록 하는 수준
데이터베이스는 ACID 특징과 같이 트랜잭션이 독립적인 수행을 하도록 한다.
따라서 Locking을 통해 트랜잭션이 DB를 다루는 동안, 다른 트랜잭션이 관여하지 못하도록 막아야 한다.
하지만 무조건 Locking으로 동시에 수행되는 수많은 트랜잭션들을 순서대로 처리하는 방식으로 구현하게 되면 데이터베이스의 성능이 떨어지게 된다.
그렇다고 해서 성능을 높이기 위해 Locking의 범위를 줄인다면 잘못된 값이 처리될 문제가 발생하게 된다.
따라서 최대한 효율적인 Locking 방법이 필요하다.
Read Uncommitted (레벨 0)
SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 계층
트랜잭션에 처리중이거나, 아직 Commit되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용함
사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 아직 완료되지 않은(Uncommitted) 트랜잭션이지만 데이터B를 읽을 수 있다.
데이터베이스의 일관성을 유지하는 것이 불가능함
Read Committed (레벨 1)
SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리는 계층
트랜잭션이 수행되는 동안 다른 트랜잭션이 접근할 수 없어 대기하게 됨
Commit이 이루어진 트랜잭션만 조회 가능
대부분의 SQL 서버가 Default로 사용하는 Isolation Level임
사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 해당 데이터에 접근이 불가능함
Repeatable Read (레벨 2)
트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리는 계층
트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장함
다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 불가능
MySQL에서 Default로 사용하는 Isolation Level
Serializable (레벨 3)
트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리는 계층
완벽한 읽기 일관성 모드를 제공함
다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 및 입력 불가능
선택 시 고려사항
Isolation Level에 대한 조정은 동시성과 데이터 무결성에 연관되어 있음
동시성을 증가시키면 데이터 무결성에 문제가 발생하고,
데이터 무결성을 유지하면 동시성이 떨어지게 됨
레벨을 높게 조정할수록 발생하는 비용이 증가함
낮은 단계 Isolation Level을 활용할 때 발생하는 현상들
Dirty Read
커밋되지 않은 수정중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
어떤 트랜잭션에서 아직 실행이 끝나지 않은 다른 트랜잭션에 의한 변경사항을 보게 되는 경우
Non-Repeatable Read
한 트랜잭션에서 같은 쿼리를 두 번 수행할 때, 그 사이에 다른 트랜잭션 값을 수정 또는 삭제하면서 두 쿼리의 결과가 상이하게 나타나는 일관성이 깨진 현상
Phantom Read
한 트랜잭션 안에서 일정 범위의 레코드를 두 번 이상 읽었을 때, 첫 번째 쿼리에서 없던 레코드가 두 번째 쿼리에서 나타나는 현상
트랜잭션 도중 새로운 레코드 삽입을 허용하기 때문에 나타나는 현상임
빠른 오픈 소스 인 메모리 키 값 데이터 구조 스토어
보통 데이터베이스는 하드 디스크나 SSD에 저장한다.
하지만 Redis는 메모리(RAM)에 저장해서 디스크 스캐닝이 필요 없으므로 매우 빠르다는 장점이 존재한다.
캐싱도 가능해 실시간 채팅에 적합하며, 세션 공유를 위해 세션 클러스터링에도 활용된다.
RAM은 휘발성 아닌가요?
이를 막기 위한 백업 과정이 존재한다.
value 5가지
일련의 쿼리를 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합
데이터베이스에서 SQL을 통해 작업을 하다 보면, 하나의 쿼리문으로 원하는 결과를 얻을 수 없을 때가 생긴다. 원하는 결과물을 얻기 위해 사용할 여러 줄의 쿼리문을 한 번의 요청으로 실행하면 좋지 않을까? 또한, 인자 값만 상황에 따라 바뀌고 동일한 로직의 복잡한 쿼리문을 필요할 때마다 작성한다면 비효율적이지 않을까?
이럴 때 사용할 수 있는 것이 바로 프로시저다.
프로시저를 만들어두면, 애플리케이션에서 여러 상황에 따라 해당 쿼리문이 필요할 때 인자 값만 전달하여 쉽게 원하는 결과물을 받아낼 수 있다.
CREATE OR REPLACE PROCEDURE 프로시저명(변수명1 IN 데이터타입, 변수명2 OUT 데이터타입) // 인자 값은 필수 아님
IS
[
변수명1 데이터타입;
변수명2 데이터타입;
..
]
BEGIN
필요한 기능; // 인자값 활용 가능
END;
EXEC 프로시저명; // 호출
예시1 (IN)
CREATE OR REPLACE PROCEDURE test( name IN VARCHAR2 )
IS
msg VARCHAR(5) := '내 이름은';
BEGIN
dbms_output.put_line(msg||' '||name);
END;
EXEC test('Joy');
내 이름은 Joy
예시2 (OUT)
CREATE OR REPLACE PROCEDURE test( name OUT VARCHAR2 )
IS
BEGIN
name := 'Joy'
END;
DECLARE
out_name VARCHAR2(100);
BEGIN
test(out_name);
dbms_output.put_line('내 이름은 ' ||out_name);
END;
내 이름은 Joy
최적화 & 캐시
프로시저의 최초 실행 시 최적화 상태로 컴파일이 되며, 그 이후 프로시저 캐시에 저장된다.
만약 해당 프로세스가 여러 번 사용될 때, 다시 컴파일 작업을 거치지 않고 캐시에서 가져오게 된다.
유지 보수
작업이 변경될 때, 다른 작업은 건드리지 않고 프로시저 내부에서 수정만 하면 된다.
트래픽 감소
클라이언트가 직접 SQL문을 작성하지 않고, 프로시저명에 매개변수만 담아 전달하면 된다.
즉, SQL문이 서버에 이미 저장되어 있기 때문에 클라이언트와 서버 간 네트워크상 트래픽이 감소된다.
보안
프로시저 내에서 참조 중인 테이블의 접근을 막을 수 있다.