데이터베이스에서의 뷰에 대해서 알아보는 시간이다. 😊
뷰(View)란?
뷰의 정의
뷰란 데이터베이스에서 데이터를 직접 가지지 않는 가상의 테이블을 의미한다.
사용자가 자주 조회하는 데이터를 정의한 SELECT 문을 뷰로 저장하면,
뷰에 접근할 때마다 내부에 정의된 SELECT 문이 실행되어 결과를 반환한다!
즉, 뷰를 쿼리에서 사용하면 해당 뷰의 SELECT 문이 먼저 수행된다.
뷰의 특징
1. 실제 데이터를 저장하지 않는다.
뷰의 개념을 잘 보여주는 대표적인 특징이다.
앞서 말했던 것처럼, 뷰는 실제 데이터 대신 쿼리문을 저장한다.
때문에, 복잡하거나 자주쓰는 쿼리를 뷰로 만들면 재사용할 수 있다는 장점이 존재한다.
2. 보안에 용이하다.
쿼리문을 뷰로 저장할 때, 원하는 데이터만 선택적으로 보여줄 수 있어 보안에 용이하다.
예를 들어, 직원(employees) 테이블에서 급여(salary) 열은 보안상 공개를 꺼려할 수 있다..
이 경우, 급여 열을 제외한 나머지 열들로 뷰로 생성하고 → 특정 사용자에게 해당 뷰의 조회 권한만 부여하면 된다.
3. 뷰는 수정이 불가능하다.
뷰를 수정하는 기능은 따로 존재하지 않는다.
만약 SELECT 문을 새로 정의하고 싶다면 기존 뷰를 삭제한 뒤, 다시 생성하면 된다.
이외에도 다양한 특징이 존재하지만! 뷰의 구현 방식을 살펴보고 더 구체적으로 알아보도록 하자~
뷰(View)의 사용 방법
뷰의 구현 방식에 대해서 알아보도록 하자.
뷰 생성
-- 뷰 생성
CREATE VIEW [뷰 이름] AS
SELECT ...
-- 뷰 조회
SELECT * FROM [뷰 이름];
생각보다 단순(?)하다. 뷰로 지정할 하는 쿼리 앞에 [뷰 이름]을 명시하여 뷰를 생성하면 된다.
생성된 뷰는 일반 테이블을 조회하듯이 사용할 수 있다.
중첩 뷰 생성
뷰는 중첩이 가능하다.
즉, 이미 정의된 뷰를 FROM에 사용해 새로운 뷰를 만드는 것을 중첩 뷰라고 한다.
중첩 뷰의 예시는 다음과 같다.
-- 1) 뷰 생성
CREATE VIEW V_ORDERS AS
SELECT * FROM ORDERS;
-- 2) 중첩 뷰 생성
CREATE VIEW V_ORDERS_SEOUL AS
SELECT * FROM V_ORDERS WHERE REGION = '서울';
1) ORDERS(주문) 테이블을 뷰(V_ORDERS)로 생성
2) V_ORDERS라는 뷰에서 REGION(지역)이 서울인 결과(rows)만을 가지고 2차 뷰(V_ORDERS_SEOUL)를 생성
뷰의 재정의
-- 뷰의 재정의
CREATE OR REPLACE VIEW [뷰 이름] AS
SELECT ...
앞서 뷰는 수정이 불가능하므로, 뷰를 삭제한 뒤 다시 생성해야 한다고 언급하였다.
(하지만 이 방식은 삭제와 생성의 쿼리를 두 번 실행해야 하는 번거로움이 있다.)
CREATE OR REPLACE는 1) [뷰 이름]의 뷰가 없으면 새로 생성하거나,
2) 이미 존재하면 SELECT 문을 재정의하여 뷰 내용을 갱신해준다.
CREATE OR REPLACE를 쓰게 되면, 뷰를 삭제하지 않고 갱신하기 때문에 삭제로 인해 사라지는 권한을 다시 부여할 필요가 없다.
즉, 기존 권한을 유지시켜 준다는 장점이 존재한다!!
뷰의 삭제
DROP VIEW [뷰 이름]; -- 기본값: RESTRICT
DROP VIEW [뷰 이름] CASCADE; -- [뷰 이름]을 참조하는 다른 뷰들도 같이 삭제
DROP VIEW IF EXISTS [뷰 이름]; -- [뷰 이름]이 존재하면 삭제
뷰를 삭제하는 기본 문법은 DROP VIEW 이다.
default 삭제 옵션은 RESTRICT으로, 삭제하는 뷰를 참조하는 다른 뷰(ex: 중첩 뷰 등)가 존재하면 삭제가 불가능하다.
CASCADE는 삭제하는 뷰와 더불어 해당 뷰를 참조하는 다른 뷰들도 같이 삭제된다.
IF EXISTS는 뷰 이름이 존재할 경우 삭제된다.
이때 CASCADE 옵션으로 삭제하게 되면, 해당 뷰 이름 뿐만 아니라 참조하는 뷰들도 한꺼번에 삭제된다!
뷰(View) 사용 시 주의점
지금까지 우리는 뷰의 개념과 사용 방법까지 함께 살펴보았다.
이제부터는 뷰를 사용할 때 유의해야할 점에 대해 알아보도록 하겠다..
1. 과도한 중첩 뷰를 생성하면 유지보수가 힘들다.
유지보수가 힘든 이유는 1) 성능 2) 효율, 두 가지로 정리할 수 있다.
3 depth까지의 중첩 뷰를 생성하였다고 가정해보자.
성능적인 면에서 유지보수가 힘든 이유
- 뷰는 물리적 테이블을 가지는 대신, 정의된 쿼리를 매번 동적으로 실행한다.
- 따라서 3 depth의 중첩 뷰를 통해 쿼리를 실행하게 되면,
1, 2, 3 depth에 해당하는 쿼리가 모두 실행된 결과를 기반으로 최종 결과가 만들어진다.
따라서, 실행 시간이 길어질수록 성능 저하가 발생한다.
효율 면에서 유지보수가 힘든 이유
- 만약, 뷰에서 사용한 원본 테이블의 column 이름이나 자료형이 변경되었다고 가정해보자.
- 이때, 3 depth 중첩 뷰에서 상위 1 depth 또는 2 depth 뷰가 변경 전의 column을 참조하고 있다면,
3 depth 뷰를 포함해서 관련된 모든 뷰들을 삭제 후 재생성해야 한다.
원본 테이블 ← View 1 (1 depth) ← View 2 (2 depth) ← View 3 (3 depth)
다시 말해, 원본 테이블 변경 → 3, 2, 1 depth 삭제 → 1, 2, 3 depth 순으로 뷰를 재생성해야 하는 번거로움이 있다.
2. 다음 예약어를 써서 만든 뷰는 단순 조회(Read Only)만 가능하다.
- 집계함수: SUM, AVG, COUNT 등
- 그룹: GROUP BY, HAVING
- 중복 제거: DISTINCT
- 결합: UNION, UNION ALL
위의 예약어를 가지고 뷰를 생성하게 되면, 뷰로 SELECT 문만 사용할 수 있다.
이유는 다음과 같다.
만약, A 테이블과 B 테이블을 UNION한 결과로 뷰(View 1)를 생성하였다.
생성한 뷰에 새로운 데이터를 INSERT 한다면, 데이터베이스는 A 테이블과 B 테이블 중 어디에 데이터를 넣어야 할까?
정답은 아무도 몰라~ 이다. 전지전능한 데이터베이스조차 이 사실을 모른다.
UNION 뿐만 아니라, 뷰에 여러 테이블이 포함된 경우는
실제 데이터를 조작할 시 대상 테이블을 명확히 파악하기 어렵다.
3. 뷰는 인덱스를 사용할 수 없다.
뷰는 데이터가 아닌 쿼리를 가지고 있기 때문에, 인덱스를 사용할 수 없다.
또한 원본 테이블에 인덱스가 있어도, 뷰를 조회할 때는 인덱스의 성능이 제대로 발휘되지 않을 수 있다.
다음 예시를 살펴보자.
-- a 열 인덱스 생성
CREATE INDEX idx_a ON A (a);
-- 원본 테이블
SELECT DISTINCT A.a, A.c, B.b
FROM A
JOIN B ON A.a = B.a
WHERE A.a = 999;
-- 뷰
CREATE VIEW VIEW1 AS
SELECT DISTINCT A.a, A.c, B.b
FROM A
JOIN B ON A.a = B.a;
SELECT * FROM VIEW1 where a = 999;
- 원본 테이블에서는 데이터베이스가 쿼리 전체를 보고 인덱스를 먼저 쓸지 결정한다.
- 원본 테이블은 a column의 조건(WHERE)을 가장 먼저 인덱스로 찾게 된다.
- 뷰 조회는 내부 구조가 복잡한 경우, 정의된 쿼리를 먼저 실행한다.
- A와 B를 조인해서 DISTINCT한(Full Scan) 이후, a column을 필터링한다.
- 따라서, 데이터베이스가 인덱스(idx_a) 활용을 하지 못한다.
지금까지 뷰에 대해 알아보면서, 뷰는 성능이나 활용 면에서 단점이 더 많아보이네 ..? 라고 생각할 수 있다.
하지만 뷰는 편의성과 재사용성에서 확실한 장점을 가지기 때문에,
상황에 따라 적재적소에 사용하도록 하자~
[참고]
'Computer Science > 데이터베이스' 카테고리의 다른 글
| [DB] 트랜잭션 락(Transaction Lock)(+ 동시성 제어) (1) | 2025.12.21 |
|---|---|
| [DB] 인덱스(Index) (0) | 2025.10.31 |
| [DB] 정규화(Normalization) / 1NF, 2NF, 3NF, BCNF (0) | 2025.10.24 |
| [DB] 트랜잭션 고립 수준(Transaction Isolation Level) (0) | 2025.09.19 |
| [DB] 공통 테이블 식(CTE) (0) | 2025.09.19 |