SQL 뷰 설명: 예제를 통해 함정 생성, 사용 및 방지
뷰는 테이블처럼 사용할 수 있는 저장된 쿼리입니다. 뷰를 만드는 방법, 뷰가 보고서의 일관성을 유지하는 이유, 성능을 위해 수행하는 작업과 수행하지 않는 작업, 이를 깨뜨리는 함정에 대해 알아보세요.
- 뷰는 테이블처럼 선택할 수 있는 명명된 저장된 쿼리입니다.
- 일반 보기는 데이터를 저장하지 않으므로 항상 현재 결과를 표시합니다.
- 보기는 복잡한 쿼리를 단순화하고 비즈니스 논리를 일관되게 유지하며 열에 대한 액세스를 제한할 수 있습니다.
- 구체화된 뷰는 가능하지만 쿼리 자체만으로는 더 빠르게 쿼리를 수행할 수 없습니다.
동일한 20줄의 보고서 쿼리가 5개의 대시보드에 복사되었으며 각 복사본은 조금씩 표류되었습니다. 하나는 취소된 주문을 계산하지만 다른 하나는 취소된 주문을 계산하지 않습니다. SQL 뷰는 데이터베이스에서 명확한 이름으로 해당 논리를 한 번 정의하여 이 문제를 해결합니다.
아래의 모든 예제를 SQLite 3.50에서 실행했으며 표시된 결과는 해당 실행에서 나온 것입니다. 뷰는 표준 SQL이지만 뷰를 통한 업데이트, 구체화된 뷰, 종속성 처리와 같은 세부 사항은 데이터베이스마다 다르므로 이를 지적합니다.
뷰란 무엇입니까?
뷰는 데이터베이스에 이름으로 저장된 SELECT 문입니다. 뷰를 쿼리하면 데이터베이스는 저장된 쿼리를 실행합니다. 이는 읽기를 위한 테이블처럼 작동하지만 일반 뷰는 자체 데이터 복사본을 보유하지 않습니다.
스프레드시트에 저장된 필터를 생각해 보세요. 필터는 시트의 두 번째 복사본이 아닙니다. 항상 최신 값을 반영하는 동일한 데이터를 보는 방식입니다.
샘플 테이블
CREATE TABLE customers (
id INT PRIMARY KEY, name TEXT, city TEXT, email TEXT, credit_limit INT
);
CREATE TABLE orders (
id INT PRIMARY KEY, customer_id INT, total INT, status TEXT
);
INSERT INTO customers VALUES
(1,'Asha','Pune','asha@example.com',50000),
(2,'Ben','Delhi','ben@example.com',20000),
(3,'Chitra','Pune','chitra@example.com',80000);
INSERT INTO orders VALUES
(101,1,1200,'paid'), (102,1,800,'paid'),
(103,2,300,'pending'), (104,3,2500,'paid');
보기 만들기
이 보기에는 각 고객의 주문이 요약되어 있습니다. 하나의 간단한 이름 뒤에 결합, 그룹화 및 CASE 표현식을 숨깁니다.
CREATE VIEW customer_sales AS
SELECT c.id, c.name, c.city,
COUNT(o.id) AS orders,
COALESCE(SUM(CASE WHEN o.status = 'paid' THEN o.total END), 0) AS paid_total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name, c.city;
이제 작동 방식을 몰라도 누구나 사용할 수 있습니다.
SELECT * FROM customer_sales ORDER BY paid_total DESC;
-- 3 | Chitra | Pune | 1 | 2500
-- 1 | Asha | Pune | 2 | 2000
-- 2 | Ben | Delhi | 1 | 0
SELECT name, paid_total FROM customer_sales WHERE city = 'Pune';
-- Asha | 2000
-- Chitra | 2500
뷰가 LEFT JOIN과 COALESCE를 사용하기 때문에 Ben은 0으로 표시됩니다. 이와 같은 결정은 뷰에서 한 번만 이루어지면 보고서의 일관성이 유지됩니다. NULL 처리에 대한 이해를 다시 높이려면 SQL NULL 값을 참조하세요.
뷰는 항상 최신 상태입니다.
일반 보기는 매번 쿼리를 실행하므로 새 데이터가 즉시 나타납니다. Ben에 대한 유료 주문을 추가하고 뷰를 다시 쿼리했습니다.
INSERT INTO orders VALUES (105, 2, 900, 'paid');
SELECT name, paid_total FROM customer_sales WHERE name = 'Ben';
-- Ben | 900
새로 고침 단계도 없었고 동기화할 사본도 없었습니다. 이것이 쿼리 결과를 별도의 테이블에 저장하는 것과 주요 차이점입니다.
열 숨기기
뷰는 사람이나 애플리케이션에 필요한 열만 표시하는 데 자주 사용됩니다. 여기서는 이메일 주소와 신용 한도가 제외됩니다.
CREATE VIEW public_customers AS
SELECT id, name, city FROM customers;
-- columns: id, name, city
PostgreSQL, SQL Server, MySQL과 같이 권한이 있는 데이터베이스에서는 보고 사용자에게 보기에 대한 액세스 권한을 부여할 수 있지만 기본 테이블에 대한 액세스 권한은 부여할 수 없습니다. SQLite에는 사용자 계정이 없으므로 열 제한 자체만 표시할 수 있습니다. 뷰를 하나의 보호 계층으로 취급합니다. 민감한 데이터에는 여전히 적절한 액세스 제어가 필요하며 일부 데이터베이스는 사용자별로 행을 필터링하기 위한 행 수준 보안을 제공합니다.
성능: 뷰는 속도 향상이 아닙니다.
일반적인 통념은 뷰가 쿼리를 더 빠르게 만든다는 것입니다. 일반 뷰는 쿼리할 때 해당 정의로 대체되므로 데이터베이스는 전체 쿼리를 직접 작성한 것처럼 동일한 작업을 수행합니다. 우리의 실행 계획은 쿼리의 일부로 실행되는 뷰의 조인 및 그룹화를 보여줍니다.
EXPLAIN QUERY PLAN SELECT * FROM customer_sales WHERE city = 'Pune';
-- CO-ROUTINE customer_sales
-- SCAN c ...
-- SEARCH o USING AUTOMATIC COVERING INDEX (customer_id=?) LEFT-JOIN
-- USE TEMP B-TREE FOR GROUP BY
-- SCAN customer_sales
따라서 느린 쿼리에 대한 뷰는 여전히 느린 쿼리입니다. 속도는 SQL 쿼리 최적화 및 SQL 인덱스 설명에서 다룬 것처럼 인덱스와 우수한 쿼리 설계에서 비롯됩니다. 다른 뷰 위에 구축된 뷰도 주의하세요. 중첩 레이어를 사용하면 눈치채지 못한 채 동일한 대형 테이블을 여러 번 쉽게 조인할 수 있습니다.
구체화된 뷰
구체화된 뷰않습니다캐시된 테이블처럼 결과를 저장합니다. 읽기는 빠르지만 데이터는 마지막 새로 고침만큼만 최신 상태입니다.
-- PostgreSQL
CREATE MATERIALIZED VIEW daily_sales AS
SELECT order_date, SUM(total) AS revenue FROM orders GROUP BY order_date;
REFRESH MATERIALIZED VIEW daily_sales;
| 특징 | 일반보기 | 구체화된 뷰 |
|---|---|---|
| 데이터를 저장합니다 | 아니요 | 예 |
| 신선도 | 항상 최신 | 마지막 새로고침 기준 |
| 읽기 속도 | 쿼리와 동일 | 빠르게 |
| 보관 비용 | 없음 | 예 |
| 다음에 좋습니다 | 단순화, 일관성 | 무거운 보고서 및 대시보드 |
지원은 다양합니다. PostgreSQL과 Oracle에는 구체화된 뷰가 있고 SQL Server에서는 자체 규칙이 있는 인덱싱된 뷰를 제공합니다. SQLite와 MySQL에는 이러한 기능이 부족하므로 사람들은 일정에 따라 새로 고쳐지는 일반 요약 테이블을 사용합니다. 이 기사에서는 PostgreSQL 예제를 실행하지 않았습니다.
팁: 구체화된 뷰를 생성하기 전에 데이터의 유효 기간이 얼마나 허용되는지 결정하세요. “매시간 새로 고침”은 보고서를 읽는 사람들이 받아들일 수 있어야 하므로 그들에게 알려주십시오.
보기를 업데이트할 수 있나요?
데이터베이스와 뷰에 따라 다릅니다. 그룹화 또는 DISTINCT 없이 단일 테이블에 대한 간단한 보기는 PostgreSQL, MySQL 및 SQL Server에서 업데이트될 수 있으며 변경 사항이 테이블로 전달되는 경우가 많습니다. 조인이나 집계가 포함된 뷰는 일반적으로 변경할 수 없습니다. 데이터베이스가 변경할 행을 알 수 없기 때문입니다.
SQLite는 뷰에 대한 직접 쓰기를 전혀 허용하지 않습니다. 우리의 시도는 실패했습니다:
INSERT INTO customer_sales (name) VALUES ('X');
-- cannot modify customer_sales because it is a view
일부 데이터베이스는 뷰를 쓰기 가능하게 만드는 INSTEAD OF 트리거를 지원하고, 많은 제안은 뷰를 통해 표시되지 않는 쓰기를 중지하는 WITH CHECK OPTION를 제공합니다. 실제로 대부분의 팀은 뷰를 읽기 전용으로 유지하고 테이블에 씁니다.
종속성과 파손
뷰는 읽는 테이블에 따라 달라집니다. 테이블에 뷰를 만든 다음 테이블을 삭제했습니다.
CREATE TABLE ghost AS SELECT 1 AS x;
CREATE VIEW v_ghost AS SELECT x FROM ghost;
DROP TABLE ghost;
SELECT * FROM v_ghost;
-- no such table: main.ghost
SQLite는 삭제를 허용했고 나중에 뷰가 사용될 때만 실패했습니다. PostgreSQL과 같은 다른 데이터베이스는 뷰도 제거하는 CASCADE을 추가하지 않는 한 뷰가 의존하는 테이블 삭제를 거부합니다. 어느 쪽이든 열 이름을 바꾸거나 열을 삭제하면 뷰가 손상될 수 있으므로 스키마 변경 후 회귀 테스트에서 확인하세요.
뷰에 SELECT *이 있는 미묘한 함정도 있습니다. CREATE VIEW star AS SELECT * FROM customers를 생성한 다음 테이블에 열을 추가했습니다. SQLite에서는 뷰가 새 열을 선택했습니다. PostgreSQL을 포함한 다른 데이터베이스는 뷰가 생성될 때 열 목록을 확장하므로 새 열이 표시되지 않습니다. 따라서 열을 명시적으로 나열하십시오. 뷰를 문서화하고 어디에서나 동일하게 작동합니다.
보기 관리
| 작업 | 일반적인 구문 |
|---|---|
| 만들기 | SELECT로 VIEW 이름 만들기 ... |
| 바꾸기 | CREATE OR REPLACE VIEW (PostgreSQL, MySQL, 오라클) |
| SQL Server에서 바꾸기 | 보기 생성 또는 변경 |
| 제거 | 드롭뷰 이름 |
| 안전하게 제거하세요 | 존재하는 경우 보기 삭제 이름 |
뷰를 삭제하면 저장된 쿼리만 제거됩니다. 테스트에서는 public_customers를 삭제한 후에도 customers 테이블에 여전히 세 개의 행이 모두 남아 있었습니다. 마이그레이션과 함께 버전 제어에 뷰 정의를 유지하여 변경 사항이 다른 코드와 마찬가지로 검토되도록 합니다.
보기 vs CTE vs 테이블
| 옵션 | 평생 | 데이터를 저장합니다 | 다음에 가장 적합 |
|---|---|---|---|
| 보기 | 삭제될 때까지 | 아니요 | 많은 쿼리에서 사용되는 공유 논리 |
| CTE | 하나의 진술 | 아니요 | 단일 복잡한 쿼리 구성 |
| 구체화된 뷰 | 삭제될 때까지 | 예 | 비용이 많이 드는 결과를 빠르게 읽음 |
| 테이블 | 삭제될 때까지 | 예 | 실제 데이터 |
일반적인 실수
- 속도 향상이 예상됩니다. 일반 보기는 매번 쿼리를 실행합니다.
- 뷰에서
SELECT *를 사용합니다. 테이블이 변경되면 데이터베이스마다 동작이 다릅니다. - 깊은 중첩. 뷰를 기반으로 구축된 뷰는 비용이 많이 드는 조인을 숨깁니다.
- 뷰 내에서 ORDER BY 사용. 쿼리할 때 순서가 보장되지 않으므로 외부 쿼리에서 정렬하세요.
- 불명확한 이름.
v_와 같은 접두사 또는customer_sales과 같은 명확한 명사가 도움이 됩니다. - 마이그레이션 중에 뷰를 잊어버립니다. 스키마가 변경될 때마다 뷰를 테스트하세요.
마무리
뷰는 중요한 논리를 데이터베이스에 하나의 홈으로 제공하는 간단한 방법입니다. 이를 사용하여 성능 트릭이 아닌 보고서의 일관성을 유지하고 불필요한 열을 숨길 수 있습니다. 시작하려면 코드의 여러 위치에 나타나는 쿼리를 찾아서 명시적인 열이 있는 보기로 전환하고 각 호출자가 이를 가리키도록 합니다.
자주 묻는 질문
SQL의 뷰란 무엇입니까?
뷰는 이름이 있는 저장된 SELECT 쿼리입니다. 테이블처럼 쿼리하면 데이터베이스가 매번 기본 쿼리를 실행하므로 결과는 항상 최신 상태입니다.
SQL 뷰는 데이터를 저장합니까?
일반 뷰는 데이터를 저장하지 않고 쿼리만 저장합니다. 구체화된 뷰는 결과를 저장하므로 최신 상태를 유지하려면 새로 고쳐야 합니다.
뷰가 테이블보다 빠르나요?
아니요. 일반 보기는 기본 쿼리와 동일한 작업을 수행합니다. 구체화된 뷰는 저장 및 신선도를 희생하면서 읽기 속도를 높일 수 있습니다.
뷰에 삽입할 수 있나요?
때때로. 간단한 단일 테이블 보기는 PostgreSQL, MySQL 및 SQL Server에서 업데이트가 가능한 경우가 많습니다. 조인이나 그룹화가 포함된 뷰는 일반적으로 그렇지 않으며 SQLite에서는 이를 허용하지 않습니다.
테이블이 삭제되면 뷰는 어떻게 되나요?
데이터베이스에 따라 다릅니다. 일부는 뷰가 테이블에 의존하는 동안 테이블 삭제를 거부하는 반면, 다른 일부는 이를 허용하고 쿼리 시 뷰가 실패합니다.
계속 학습하세요
테스트, WordPress 또는 SEO에 도움이 필요하십니까?
우리는 팀이 더 나은 소프트웨어를 출시하고 사이트를 성장시킬 수 있도록 돕습니다. 현재 진행 중인 작업을 알려주시면 명확한 다음 단계를 제안해 드리겠습니다.
추가 가이드 테스트, AI 및 최신 개발
이 기사가 마음에 드셨나요? 주제를 선택하고 최신 튜토리얼로 바로 이동하세요.
AI 환각 설명: 언어 모델이 사물을 구성하는 이유와 이를 줄이는 방법
AI 환각은 그것이 무엇인지, 언어 모델이 환각을 생성하는 이유, 일반적인 유형, 접지 및 프롬프트를 통해 환각을 줄이는 방법, 그리고 우리가 실행한 간단한 점검에 대해 설명했습니다.
기사 읽기 →DevOps환경 변수 설명: .env 파일, 비밀 및 구성이 올바르게 완료되었습니다.
우리가 실행한 Python 예제를 통해 설명된 환경 변수: 읽기 및 설정, 모든 값이 문자열인 이유, .env 파일, 프로세스 상속, 비밀 및 유효성 검사.
기사 읽기 →소프트웨어 개발API 속도 제한 설명: 알고리즘, 헤더 및 429 오류 처리
우리가 실행한 시뮬레이션을 통해 설명된 API 속도 제한: 토큰 버킷, 고정 창, 슬라이딩 창, 429 응답, 속도 제한 헤더, 백오프를 사용한 재시도 및 테스트 제한.
기사 읽기 →테스트 자동화Python에서 조롱: unittest.mock, 패치 및 테스트를 거짓말로 만드는 실수
Unittest.mock을 사용하여 Python에서 모의, 테스트됨: 모의 및 return_value, 부작용, 이름이 사용되는 패치, 사양 및 자동 사양, 모의 날짜 및 일반적인 실수.
기사 읽기 →소프트웨어 테스트코드 커버리지 설명: 회선 커버리지와 분기 커버리지 및 100%의 실제 의미
실제 Coverage.py 실행을 통해 설명되는 코드 적용 범위: 라인, 분기 및 조건 적용 범위, 보고서 읽기, 100% 적용 범위가 여전히 버그를 놓칠 수 있는 이유 및 합리적인 대상.
기사 읽기 →데이터베이스 및 SQLSQL의 DELETE vs TRUNCATE vs DROP: 차이점, 롤백 및 사용 시기
테스트된 SQL을 통해 DELETE 대 TRUNCATE 대 DROP에 대해 설명합니다. 각각의 제거, 롤백, 트리거, ID 재설정, 속도 및 PostgreSQL, MySQL, SQL Server 및 SQLite의 차이점.
기사 읽기 →데이터베이스 및 SQLSQL 뷰 설명: 예제를 통해 함정 생성, 사용 및 방지
우리가 실행한 쿼리로 설명된 SQL 뷰: 뷰 생성, 실시간 결과, 열 숨기기, 성능, 업데이트 가능하고 구체화된 뷰, 손상된 종속성 및 모범 사례.
기사 읽기 →소프트웨어 개발TypeScript 인터페이스와 유형: 실제 차이점, 컴파일러로 테스트
TypeScript 인터페이스 대 유형, 실제 컴파일러로 확인: 둘 다 할 수 있는 것, 하나만 할 수 있는 것, 선언 병합, 확장 대 교차점 및 따라야 할 간단한 규칙.
기사 읽기 →소프트웨어 개발Python *args 및 **kwargs 설명: 명확한 예가 포함된 유연한 함수
Python *args 및 **kwargs는 우리가 실행한 코드(패킹 및 언패킹, 매개변수 순서, 키워드 전용 및 위치 전용 인수, 데코레이터 및 일반적인 오류)를 설명했습니다.
기사 읽기 →소프트웨어 개발Python Lambda 함수: 구문, 실제 사용 및 사용하지 말아야 할 경우
Python 람다 함수는 구문, 키를 사용한 정렬, 맵 및 필터, 클로저, 후기 바인딩 트랩, 일반 def가 더 나은 선택인 경우 등 우리가 실행한 코드로 설명되었습니다.
기사 읽기 →인공지능AI 에이전트란 무엇입니까? 작동 방식, 간단한 에이전트 루프를 사용하여 실행할 수 있음
AI 에이전트란 무엇입니까? 우리가 실행한 작은 Python 루프, 실제 위험 및 간단한 챗봇이 더 나은 선택일 때 에이전트 루프, 도구, 메모리 및 가드레일에 대한 일반 가이드입니다.
기사 읽기 →DevOps모니터링과 관찰 가능성: 로그, 지표, 추적을 통한 실제 차이점
모니터링과 관찰 가능성 설명: 알려진 오류와 알려지지 않은 오류, 로그, 지표 및 추적, 결제 사건 안내, 골든 신호, OpenTelemetry 및 유용한 경고.
기사 읽기 →DevOpsDocker 볼륨과 바인딩 마운트: 컨테이너 데이터를 올바른 방식으로 유지
Docker 볼륨과 바인드 마운트 설명: 컨테이너 데이터가 사라지는 이유, 명명된 볼륨, 바인드 마운트, tmpfs, Compose 예제, 백업, 권한 및 각 사용 시기.
기사 읽기 →테스트 자동화TDD와 BDD: 주요 차이점, 두 가지 방식으로 구축된 하나의 기능 및 각 사용 시기
TDD와 BDD는 두 가지 방식으로 구축된 하나의 할인 기능, 즉 우리가 실행한 코드를 사용한 적록 리팩토링, 주어진 시점 시나리오, 도구, 장단점 및 각 사용 시기를 설명합니다.
기사 읽기 →소프트웨어 개발Git merge vs rebase: 차이점, 예제, 언제 무엇을 쓸까
Git merge vs rebase를 실제 로그 출력, 비교표, rebase의 황금률, 안전한 팀 워크플로로 설명합니다.
기사 읽기 →소프트웨어 개발파이썬 리스트 컴프리헨션: 문법, 예제, 피해야 할 때
파이썬 리스트 컴프리헨션 설명: 문법, 필터링, if-else, 중첩 반복문, 실제 측정 시간, 그리고 일반 for 반복문이 더 나은 경우.
기사 읽기 →데이터베이스 및 SQL예제로 쉽게 배우는 SQL JOIN (Inner, Left, Right, Full)
샘플 테이블과 쿼리로 SQL JOIN을 단계별로 이해하세요. INNER, LEFT, RIGHT, FULL, CROSS, SELF와 흔한 실수, 성능 팁까지 정리했습니다.
기사 읽기 →