빅쿼리 뷰

뷰 활용 및 관리

BigQuery에서 뷰(View)를 활용한 데이터 추상화, 보안, 재사용성 향상을 위한 종합 가이드입니다.


목차

  1. 뷰의 개념과 정의
  2. 뷰의 종류와 특징
  3. 뷰 생성과 관리
  4. 뷰 보안과 권한 관리
  5. 성능 최적화 전략
  6. 뷰 vs 머터리얼라이즈드 뷰
  7. 실제 사용 사례
  8. 모범 사례와 주의점

1. 뷰의 개념과 정의

1.1 뷰란?

뷰(View)는 하나 이상의 테이블로부터 파생된 가상 테이블입니다.

  • 논리적 테이블: 실제 데이터를 저장하지 않고 쿼리 결과만 정의
  • 동적 실행: 뷰 조회 시마다 기본 쿼리가 실행됨
  • 데이터 추상화: 복잡한 쿼리를 단순한 테이블처럼 사용

1.2 뷰의 주요 장점

-- 복잡한 기본 쿼리
SELECT 
  c.customer_id,
  c.customer_name,
  c.region,
  COUNT(o.order_id) as total_orders,
  SUM(o.total_amount) as total_spent,
  AVG(o.total_amount) as avg_order_value,
  MAX(o.order_date) as last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE c.status = 'active'
  AND o.order_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 365 DAY)
GROUP BY c.customer_id, c.customer_name, c.region;

-- 뷰로 단순화
CREATE VIEW customer_summary AS
SELECT 
  c.customer_id,
  c.customer_name,
  c.region,
  COUNT(o.order_id) as total_orders,
  SUM(o.total_amount) as total_spent,
  AVG(o.total_amount) as avg_order_value,
  MAX(o.order_date) as last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE c.status = 'active'
  AND o.order_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 365 DAY)
GROUP BY c.customer_id, c.customer_name, c.region;

-- 간단한 사용
SELECT * FROM customer_summary WHERE region = 'Asia';

주요 장점:

  • 재사용성: 공통 쿼리 로직을 여러 곳에서 재사용
  • 보안성: 민감한 컬럼을 숨기고 필요한 데이터만 노출
  • 단순화: 복잡한 JOIN과 집계를 단순한 테이블처럼 사용
  • 일관성: 동일한 비즈니스 로직을 여러 사용자가 일관되게 사용

2. 뷰의 종류와 특징

2.1 일반 뷰 (Standard View)

-- 기본 뷰 생성
CREATE VIEW sales_view AS
SELECT 
  product_id,
  product_name,
  category,
  SUM(quantity) as total_quantity,
  SUM(revenue) as total_revenue
FROM sales_table
WHERE sale_date >= '2023-01-01'
GROUP BY product_id, product_name, category;

특징:

  • 쿼리 실행 시마다 기본 테이블에서 데이터 조회
  • 실시간 데이터 반영
  • 저장 공간 사용하지 않음

2.2 승인된 뷰 (Authorized View)

-- 승인된 뷰 생성 (특별한 권한 부여)
CREATE VIEW secure_customer_data AS
SELECT 
  customer_id,
  SUBSTR(customer_name, 1, 1) || '***' as masked_name,
  region,
  total_orders
FROM customer_summary
WHERE region IN ('Korea', 'Japan');

특징:

  • 기본 테이블에 대한 직접 접근 권한 없이도 뷰 접근 가능
  • 데이터 보안과 프라이버시 보호
  • 세밀한 접근 제어

2.3 파티션된 테이블의 뷰

-- 파티션된 테이블 기반 뷰
CREATE VIEW recent_events AS
SELECT 
  event_id,
  event_type,
  user_id,
  event_timestamp
FROM events_partitioned
WHERE DATE(event_timestamp) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY);

특징:

  • 파티션 pruning 효과 유지
  • 성능 최적화 가능
  • 동적 파티션 필터링

3. 뷰 생성과 관리

3.1 기본 뷰 생성

-- 기본 뷰 생성 구문
CREATE VIEW [project_id.]dataset_id.view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

-- 실제 예시
CREATE VIEW analytics.monthly_sales AS
SELECT 
  EXTRACT(YEAR FROM order_date) as year,
  EXTRACT(MONTH FROM order_date) as month,
  COUNT(*) as order_count,
  SUM(total_amount) as total_revenue,
  AVG(total_amount) as avg_order_value
FROM orders
GROUP BY 1, 2
ORDER BY 1, 2;

3.2 뷰 수정 및 업데이트

-- 뷰 수정 (OR REPLACE 사용)
CREATE OR REPLACE VIEW analytics.monthly_sales AS
SELECT 
  EXTRACT(YEAR FROM order_date) as year,
  EXTRACT(MONTH FROM order_date) as month,
  region,  -- 새로운 컬럼 추가
  COUNT(*) as order_count,
  SUM(total_amount) as total_revenue,
  AVG(total_amount) as avg_order_value
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id  -- JOIN 추가
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3;

3.3 뷰 삭제

-- 뷰 삭제
DROP VIEW analytics.monthly_sales;

-- 존재하는 경우에만 삭제
DROP VIEW IF EXISTS analytics.monthly_sales;

3.4 뷰 메타데이터 조회

-- 데이터셋 내 모든 뷰 조회
SELECT 
  table_name,
  table_type,
  creation_time,
  last_modified_time
FROM analytics.INFORMATION_SCHEMA.TABLES
WHERE table_type = 'VIEW';

-- 뷰 정의 조회
SELECT view_definition
FROM analytics.INFORMATION_SCHEMA.VIEWS
WHERE table_name = 'monthly_sales';

4. 뷰 보안과 권한 관리

4.1 데이터 마스킹을 통한 보안

-- 개인정보 마스킹 뷰
CREATE VIEW secure_user_info AS
SELECT 
  user_id,
  CONCAT(
    SUBSTR(email, 1, 2),
    '***@',
    SUBSTR(email, STRPOS(email, '@') + 1, LENGTH(email))
  ) as masked_email,
  SUBSTR(phone, 1, 3) || '-****-' || SUBSTR(phone, -4) as masked_phone,
  registration_date
FROM users;

4.2 행 수준 보안 (Row-Level Security)

-- 지역별 데이터 접근 제한
CREATE VIEW regional_sales AS
SELECT 
  order_id,
  customer_id,
  product_id,
  total_amount,
  order_date
FROM orders
WHERE region = 
  CASE 
    WHEN SESSION_USER() LIKE '%asia%' THEN 'Asia'
    WHEN SESSION_USER() LIKE '%europe%' THEN 'Europe'
    ELSE 'Americas'
  END;

4.3 승인된 뷰 설정

-- 1. 기본 테이블에 대한 뷰 생성
CREATE VIEW finance_summary AS
SELECT 
  department,
  SUM(budget) as total_budget,
  AVG(expense_ratio) as avg_expense_ratio
FROM confidential_finance_data
GROUP BY department;

-- 2. 특정 사용자/그룹에게만 뷰 접근 권한 부여
GRANT SELECT ON finance_summary TO 'user:analyst@company.com';

-- 3. 기본 테이블 접근은 제한하고 뷰 접근만 허용
-- (Google Cloud Console 또는 bq 명령어로 설정)

5. 성능 최적화 전략

5.1 효율적인 뷰 설계

-- ❌ 비효율적인 뷰 (매번 전체 테이블 스캔)
CREATE VIEW inefficient_view AS
SELECT *
FROM large_table
WHERE some_condition = 'value';

-- ✅ 효율적인 뷰 (필요한 컬럼만 선택, 파티션 활용)
CREATE VIEW efficient_view AS
SELECT 
  id,
  name,
  created_date,
  status
FROM large_table
WHERE DATE(created_date) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND status IN ('active', 'pending');

5.2 파티션 Pruning 활용

-- 파티션된 테이블의 뷰에서 파티션 필터 포함
CREATE VIEW recent_logs AS
SELECT 
  log_id,
  user_id,
  action_type,
  log_timestamp
FROM partitioned_logs
WHERE DATE(log_timestamp) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY);

5.3 인덱스 활용 고려

-- 클러스터링된 테이블의 뷰 (클러스터링 컬럼 활용)
CREATE VIEW user_activities AS
SELECT 
  user_id,  -- 클러스터링 컬럼
  activity_type,
  activity_timestamp,
  details
FROM clustered_activity_table
WHERE user_id IS NOT NULL;

6. 뷰 vs 머터리얼라이즈드 뷰

6.1 비교표

특성 일반 뷰 머터리얼라이즈드 뷰
데이터 저장 ❌ (쿼리만 저장) ✅ (결과 저장)
실행 시점 조회 시마다 생성/새로고침 시
실시간성 ✅ 완전 실시간 ⚠️ 새로고침 주기에 따라
성능 기본 쿼리에 의존 ✅ 빠른 조회
저장 비용 ❌ 없음 ✅ 있음
복잡한 집계 ⚠️ 매번 재계산 ✅ 미리 계산됨

6.2 사용 시나리오

-- 일반 뷰: 실시간 데이터가 중요한 경우
CREATE VIEW real_time_inventory AS
SELECT 
  product_id,
  available_quantity,
  reserved_quantity,
  available_quantity - reserved_quantity as sellable_quantity
FROM inventory
WHERE available_quantity > 0;

-- 머터리얼라이즈드 뷰: 복잡한 집계, 성능이 중요한 경우
CREATE MATERIALIZED VIEW daily_sales_summary AS
SELECT 
  DATE(order_timestamp) as order_date,
  product_category,
  COUNT(*) as order_count,
  SUM(total_amount) as revenue,
  COUNT(DISTINCT customer_id) as unique_customers
FROM orders
WHERE DATE(order_timestamp) >= DATE_SUB(CURRENT_DATE(), INTERVAL 365 DAY)
GROUP BY 1, 2;

7. 실제 사용 사례

7.1 비즈니스 인텔리전스 대시보드

-- KPI 대시보드용 뷰
CREATE VIEW kpi_dashboard AS
SELECT 
  'Daily Active Users' as metric_name,
  COUNT(DISTINCT user_id) as metric_value,
  CURRENT_DATE() as metric_date
FROM user_activities
WHERE DATE(activity_timestamp) = CURRENT_DATE()

UNION ALL

SELECT 
  'Daily Revenue' as metric_name,
  COALESCE(SUM(total_amount), 0) as metric_value,
  CURRENT_DATE() as metric_date
FROM orders
WHERE DATE(order_timestamp) = CURRENT_DATE()

UNION ALL

SELECT 
  'New Registrations' as metric_name,
  COUNT(*) as metric_value,
  CURRENT_DATE() as metric_date
FROM users
WHERE DATE(created_timestamp) = CURRENT_DATE();

7.2 데이터 품질 모니터링

-- 데이터 품질 체크 뷰
CREATE VIEW data_quality_checks AS
SELECT 
  'orders' as table_name,
  'null_customer_id' as check_name,
  COUNT(*) as failed_records,
  CURRENT_TIMESTAMP() as check_timestamp
FROM orders
WHERE customer_id IS NULL

UNION ALL

SELECT 
  'orders' as table_name,
  'negative_amount' as check_name,
  COUNT(*) as failed_records,
  CURRENT_TIMESTAMP() as check_timestamp
FROM orders
WHERE total_amount < 0

UNION ALL

SELECT 
  'users' as table_name,
  'invalid_email' as check_name,
  COUNT(*) as failed_records,
  CURRENT_TIMESTAMP() as check_timestamp
FROM users
WHERE email NOT LIKE '%@%.%';

7.3 다중 환경 데이터 통합

-- 프로덕션과 스테이징 환경 통합 뷰
CREATE VIEW unified_user_metrics AS
SELECT 
  'production' as environment,
  COUNT(*) as total_users,
  COUNT(CASE WHEN status = 'active' THEN 1 END) as active_users,
  AVG(session_duration) as avg_session_duration
FROM prod_dataset.users

UNION ALL

SELECT 
  'staging' as environment,
  COUNT(*) as total_users,
  COUNT(CASE WHEN status = 'active' THEN 1 END) as active_users,
  AVG(session_duration) as avg_session_duration
FROM staging_dataset.users;

8. 모범 사례와 주의점

8.1 모범 사례

명명 규칙

-- ✅ 명확한 명명 규칙 사용
CREATE VIEW vw_monthly_sales_summary AS ...;     -- vw_ 접두사
CREATE VIEW sales_summary_monthly AS ...;        -- 의미 있는 이름
CREATE VIEW dim_customer_active AS ...;          -- 차원 테이블 표시

문서화

-- ✅ 뷰 목적과 사용법 주석 포함
CREATE VIEW customer_lifetime_value AS
/*
목적: 고객별 생애 가치(LTV) 계산
사용: 마케팅 타겟팅 및 세그먼테이션
업데이트: 매일 자동 새로고침
작성자: data-team@company.com
*/
SELECT 
  customer_id,
  SUM(order_total) as total_spent,
  COUNT(DISTINCT order_id) as total_orders,
  DATE_DIFF(MAX(order_date), MIN(order_date), DAY) as customer_lifetime_days
FROM orders
GROUP BY customer_id;

성능 고려

-- ✅ 필요한 컬럼만 선택
CREATE VIEW efficient_sales_view AS
SELECT 
  order_id,        -- 필요한 컬럼만
  customer_id,     -- 선택
  total_amount,
  order_date
FROM orders
WHERE order_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 1 YEAR)  -- 적절한 필터링
  AND status = 'completed';

8.2 주의점과 제한사항

성능 고려사항

-- ❌ 피해야 할 패턴 - 복잡한 중첩 뷰
CREATE VIEW complex_nested_view AS
SELECT *
FROM (
  SELECT * FROM view1
  JOIN (
    SELECT * FROM view2
    JOIN view3 ON view2.id = view3.id
  ) ON view1.id = view2.id
);

-- ✅ 대안 - 단순한 구조 유지
CREATE VIEW simple_joined_view AS
SELECT 
  t1.id,
  t1.name,
  t2.category,
  t3.status
FROM base_table1 t1
JOIN base_table2 t2 ON t1.id = t2.id
JOIN base_table3 t3 ON t1.id = t3.id;

권한 관리

-- ✅ 적절한 권한 부여
-- 뷰에 대한 SELECT 권한만 부여
GRANT SELECT ON dataset.customer_summary_view TO 'group:analysts@company.com';

-- 기본 테이블에 대한 직접 접근은 제한
-- REVOKE ALL ON dataset.raw_customer_data FROM 'group:analysts@company.com';

의존성 관리

  • 기본 테이블 스키마 변경 시 뷰 영향 검토
  • 뷰의 의존성 체인이 너무 길어지지 않도록 주의
  • 정기적인 뷰 사용량 및 성능 모니터링

8.3 모니터링과 유지보수

-- 뷰 사용량 모니터링 쿼리
SELECT 
  view_name,
  query_count,
  avg_execution_time_ms,
  total_bytes_processed
FROM (
  SELECT 
    referenced_table.table_id as view_name,
    COUNT(*) as query_count,
    AVG(total_slot_ms) as avg_execution_time_ms,
    SUM(total_bytes_processed) as total_bytes_processed
  FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
  WHERE DATE(creation_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
    AND referenced_table.table_id IN (
      SELECT table_name 
      FROM your_dataset.INFORMATION_SCHEMA.VIEWS
    )
  GROUP BY referenced_table.table_id
)
ORDER BY query_count DESC;

결론

BigQuery의 뷰는 데이터 추상화, 보안, 재사용성을 위한 강력한 도구입니다. 적절히 설계되고 관리된 뷰는 조직의 데이터 거버넌스를 향상시키고, 분석 작업을 효율화할 수 있습니다.

핵심 포인트:

  • 비즈니스 요구사항에 맞는 적절한 뷰 유형 선택
  • 성능과 보안을 고려한 설계
  • 체계적인 명명 규칙과 문서화
  • 정기적인 모니터링과 최적화

뷰를 효과적으로 활용하여 더 나은 데이터 아키텍처를 구축하시기 바랍니다.