View

김기현·2025년 6월 15일

Database

목록 보기
13/24

뷰는 가상 테이블이며, 실제 데이터를 저장하지 않고, SELECT 쿼리 결과를 저장한 것처럼 사용할 수 있는 객체이다. 마치 테이블처럼 사용할 수 있지만, 내부적으로는 정의된 SQL 쿼리가 실행되어
결과가 표시된다.

뷰의 특징

  • 물리적으로 데이터를 저장하지 않는다.
  • 복잡한 SQL을 단순하게 재사용 가능하다.
  • 보안적으로 유용하다(원본 테이블 전체를 노출하지 않고 필요한 컬럼만 제공할 수 있다)
  • 읽기 전용 또는 업데이트 가능(제약사항이 있다)

예제

MySQL 기준이다.

-- 테이블
CREATE TABLE employees
(
    id         INT PRIMARY KEY,
    name       VARCHAR(100),
    department VARCHAR(100),
    salary     INT
);

INSERT INTO employees
VALUES (1, 'kim', 'HR', 5000),
       (2, 'lee', 'Engineering', 8000),
       (3, 'park', 'Engineering', 7500);
-- 뷰 생성
CREATE VIEW engineering_employees AS
SELECT id, name, salary
FROM employees
WHERE department = 'Engineering';

-- 뷰에서 데이터 조회
SELECT *
FROM engineering_employees;
idnamesalary
2lee8000
3park7500
-- 뷰 목록 보기
SHOW FULL TABLES WHERE Table_type = 'VIEW';

-- 뷰 정의 확인
SHOW CREATE VIEW engineering_employees;

뷰 수정

CREATE OR REPLACE VIEW engineering_employees AS
SELECT id, name, department, salary
FROM employees
WHERE department = 'Engineering';

뷰 삭제

DROP VIEW engineering_employees;

뷰에서 데이터 수정

뷰가 단일 테이블 기반이고 집계나 조인 없이 단순한 SELECT라면 데이터를 수정할 수도 있다.

UPDATE engineering_employees
SET salary = 8500
WHERE name = 'lee';

이 경우 실제 employees테이블의 lee의 급여가 변경된다.

수정 가능한 뷰

다음과 같은 조건을 만족하면 뷰를 통해 수정할 수 있다.

  1. 단일 테이블 기반: 여러 테이블을 조인하지 않아야 한다.
  2. 집계 함수가 없다: SUM(), AVG() 같은 집계 함수가 없어야 한다.
  3. DISTINCT가 없다: 중복 제거를 안 해야 한다.
  4. GROUP BY, HAVING BY가 없다: 그룹화를 하면 안 된다.
  5. 서브쿼리나 유도 컬럼이 없다: SELECT id, salary * 1.1 AS bonus처럼 추가적인 계산이 있으면 안 된다.
  6. 모든 NOT NULL 컬럼 포함: NOT NULL인 컬럼들이 모두 뷰에 포함되어 있어야 한다.
  7. 기본 키가 포함되어야 한다: 기본 키는 각 행을 고유하게 식별하는 수단이기 때문에 뷰를 통해 UPDATE, DELETE를 하는 경우 필요하다.
    • 식별 불가능성: 기본 키가 없으면 어떤 행을 수정해야 할지 판단할 수 없다.
    • 기본 키가 있어야 일관된 DML로 동작할 수 있다.
-- 수정 가능한 뷰 (위의 예시)
CREATE VIEW engineering_employees AS
SELECT id, name, salary
FROM employees
WHERE department = 'Engineering';

수정 불가능한 뷰

다음과 같은 경우는 MySQL이 수정 방법을 결정할 수 없기 때문에 뷰를 통한 변경이 금지된다.

-- 집계를 포함한다.
CREATE VIEW avg_salary_by_dept AS
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;

-- 계산된 컬럼이 있는 뷰
CREATE VIEW salary_with_tax AS
SELECT id, name, salary, salary * 0.9 AS after_tax_salary
FROM employees;

-- DISTINCT가 포함된 뷰
CREATE VIEW distinct_departments AS
SELECT DISTINCT department
FROM employees;

-- LIMIT이 포함된 뷰
CREATE VIEW top_3_highest_paid AS
SELECT *
FROM employees
ORDER BY salary DESC
LIMIT 3;

-- 서브퀴리가 포함된 뷰
CREATE VIEW high_salary_employees AS
SELECT id, name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- 뷰에 포함되지 않은 NOT NULL 컬럼이 있는 경우
CREATE VIEW employee_names AS
SELECT name -- id가 빠짐
FROM employees;
  • 뷰에서 UPDATEINSERT를 하려면 NOT NULL컬럼이 모두 포함되어 있어야 한다.

WITH CHECK OPTION

뷰에 맞지 않는 데이터는 넣거나 바꿀 수 없게 한다.

WITH CHECK OPTION은 뷰를 통해 데이터를 수정할 때, 뷰에서 정의한 조건을 유지하도록 강제하는 옵션이다.

뷰는 실제 테이블의 일부만 보여줄 수 있다. 예를 들어 특정 부서만 보여주는 뷰가 있다고 할 때, 그 뷰를 통해 다른 부서로 옮기는 업데이트가 가능해지면 논리적 일관성이 깨질 수 있기 때문이다.
이러한 문제를 방지하기 위해 WITH CHECK OPTION

예제

테이블 스키마와 뷰는 위와 동일하다.

UPDATE engineering_employees
SET department = 'HR'
WHERE name = 'lee';
  • 이 쿼리의 실행 결과로 lee는 더이상 엔지니어링 부서가 아니기에 뷰에서 사라진다.
  • 뷰가 보여주는 데이터 범위를 벗어난 수정이 가능해진 것이다.
  • 이는 의도하지 않은 결과를 불러올 수 있다.
CREATE OR REPLACE VIEW engineering_employees AS
SELECT *
FROM employees
WHERE department = 'Engineering'
WITH CHECK OPTION; -- WITH CHECK OPTION 사용

이렇게 WITH CHECK OPTION을 붙이면 조건에 맞는 수정만 가능해진다.

-- 수정 가능
UPDATE engineering_employees
SET salary = 9000
WHERE name = 'park';
-- OK

-- 수정 불가능
UPDATE engineering_employees
SET department = 'HR'
WHERE name = 'lee';

정리하면 아래와 같다.

항목설명
WITH CHECK OPTION 없음뷰 조건과 관계없이 수정 가능
WITH CHECK OPTION 있음뷰 조건을 벗어나는 수정은 금지됨
목적뷰를 통한 데이터 무결성 보장

뷰와 인덱스

  • 뷰에는 인덱스가 없고, 실행 시 원본 테이블의 인덱스를 사용한다.
  • 복잡한 뷰를 자주 사용하는 경우, 물리적인 테이블로 전환해야 한다.
    • MySQL에는 없지만 다른 DBMS에는 존재하는 Materialized View를 사용하는 방법도 있다.

뷰와 권한 통제

뷰는 권한 통제를 할 때도 사용할 수 있다.

-- 원본 테이블은 관리자만 접근 가능
GRANT SELECT ON engineering_employees TO 'readonly_user'@'%';
-- employees 테이블에 대한 권한은 안 줌

이렇게 하면 뷰만 접근 가능한 사용자를 만들 수 있다.

주의점

뷰는 항상 최신 데이터를 반영하지만 성능 이슈가 발생할 수 있다.

  • 뷰는 실행 시마다 SELECT 쿼리를 수행하므로, 복잡하거나 JOIN이 많은 뷰는 성능 저하를 일으킬 수 있다.
  • 이런 경우에는 뷰 대신 임시 테이블 또는 캐싱 구조를 고려해야 한다.
profile
백엔드 개발자를 목표로 공부하는 대학생

0개의 댓글