# region, 스키마, 파티션, 클러스터링

데이터셋과 region의 의미, 서울 위치 선택, DDL 기반 스키마, NOT ENFORCED 기본 키, 날짜 파티션과 클러스터링을 샘플 주문 테이블로 설명합니다.

- 카테고리: BigQuery
- 소요 시간: 약 14분
- 난이도: 중간
- 업데이트: 2026.09.02
- 원문: /wiki/playbook/bigquery-checklist/bigquery-dataset-and-table-design-guide

## 목차

- [데이터셋·리전·테이블](#concepts)
- [1단계 · 데이터셋 만들기](#step-1)
- [2단계 · region 결정](#step-2)
- [3단계 · 설정 확인](#step-3)
- [4단계 · 테이블 DDL](#step-4)
- [파티션과 클러스터링](#partition)
- [스키마와 기본 키](#schema)
- [설계 체크리스트](#checklist)
- [코드로 테이블 조회](#code-examples)
- [자주 묻는 질문](#faq)

BigQuery 설계의 첫 결정은 컬럼이 아니라 **데이터셋 위치(region)**입니다. 데이터셋 위치는 생성 후 바꿀 수 없고 쿼리·적재·내보내기의 경계를 만들기 때문입니다. 그다음 테이블의 스키마, 날짜 파티션, 클러스터링을 함께 설계해야 비용과 성능이 안정됩니다.

> **이 문서 핵심**
>
> - **대상.** 애플리케이션 테이블과 분석 마트를 처음 설계하는 담당자.
>
> - **완료 후.** 서울 region의 데이터셋과 파티션·클러스터링이 적용된 주문 테이블이 준비됩니다.
>
> - **다음.** [안전한 조회와 비용 제어](/wiki/playbook/bigquery-checklist/bigquery-query-and-cost-control-guide)로 이어집니다.

## 프로젝트 아래에 데이터셋, 데이터셋 아래에 테이블

| 개념 | 역할 | 설계 시 결정 |
| --- | --- | --- |
| **프로젝트** | API·IAM·쿼리 작업·비용의 관리 경계 | 환경과 비용 소유자 |
| **데이터셋** | 테이블을 묶는 논리 컨테이너 | region, 기본 만료, 접근 권한 |
| **테이블** | 스키마를 가진 행 저장소 | 컬럼 타입, 파티션, 클러스터링, 제약조건 |

완전한 테이블 이름은 `project.dataset.table`입니다. 예를 들어 `hurdlers-bq-dev-guide-260902.developer_guide.orders`에서 프로젝트·데이터셋·테이블을 각각 구분할 수 있습니다.

![서울 region에서 데이터셋과 날짜 파티션, 클러스터로 이어지는 구조](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/00-region-dataset-table.png)

> **한눈에 보기.** region은 데이터셋의 위치를 고정하고, 테이블 안에서는 날짜 파티션과 클러스터가 읽을 범위를 줄입니다.

## 1단계. 프로젝트 메뉴에서 데이터셋 만들기

BigQuery 탐색기에서 대상 프로젝트의 작업 메뉴를 열고 **데이터 세트 만들기**를 선택합니다.

![BigQuery 프로젝트 작업 메뉴의 데이터 세트 만들기](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/01-create-dataset-menu.png)

> **화면 1.** 데이터셋은 선택한 프로젝트 아래에 생성됩니다.

![BigQuery 데이터셋 생성 빈 폼](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/02-dataset-form-blank.png)

> **화면 2.** 데이터셋 ID와 위치를 입력하는 기본 폼.

데이터셋 ID는 SQL 식별자이므로 짧고 안정적으로 정합니다. 이 문서에서는 `developer_guide`를 사용합니다. 환경이 다르면 `app_dev`, `app_prod`처럼 이름에서 구분하는 방식도 좋습니다.

## 2단계. 데이터 위치를 서울로 고정

위치 유형을 region으로 선택하고 **asia-northeast3(서울)**을 고릅니다. 국내 데이터 거주 요건이나 서울에서 실행되는 워크로드와의 지연 시간을 고려한 예시입니다.

![데이터셋 위치에서 서울 asia-northeast3 선택](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/03-dataset-region-seoul.png)

> **화면 3.** 데이터 위치 목록에서 **서울** 선택.

> **주의**
>
> **데이터셋 위치는 생성 후 변경할 수 없습니다.** 다른 위치로 바꾸려면 새 데이터셋을 만들고 데이터를 복사해야 합니다. 함께 조인할 데이터셋, Cloud Storage 버킷, 예약·연결 리소스의 위치도 시작 전에 맞춥니다.

BigQuery는 일반적으로 한 쿼리에서 참조하는 데이터셋이 같은 위치에 있어야 합니다. 위치 제약과 지원 region은 [BigQuery 위치 문서](https://cloud.google.com/bigquery/docs/locations)에서 확인합니다.

## 3단계. 데이터셋 생성 전 옵션 확인

데이터셋 ID와 위치를 다시 확인합니다. 개발 샘플은 기본 옵션으로 만들되, 운영 데이터는 테이블 만료와 암호화 키 정책을 조직 기준에 맞춥니다.

![developer_guide와 서울 region이 입력된 데이터셋 생성 폼](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/04-dataset-form-filled.png)

> **화면 4.** 데이터셋 ID와 서울 위치 확인 후 생성.

![생성된 developer_guide 데이터셋의 세부정보](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/05-dataset-details.png)

> **화면 5.** 데이터셋 세부정보에서 ID와 위치를 다시 확인.

## 4단계. DDL로 주문 테이블 만들기

UI에서 컬럼을 하나씩 추가하는 대신, 리뷰 가능한 DDL을 저장소에서 관리합니다. 예시는 주문 ID를 논리적 기본 키로 선언하고 주문 날짜로 파티션, 고객과 상태로 클러스터링합니다.

**orders 테이블 DDL**
```sql
CREATE TABLE `hurdlers-bq-dev-guide-260902.developer_guide.orders` (
  order_id STRING NOT NULL OPTIONS(description='주문 고유 ID'),
  customer_id STRING NOT NULL OPTIONS(description='고객 고유 ID'),
  order_status STRING NOT NULL,
  order_amount NUMERIC,
  updated_at TIMESTAMP NOT NULL,
  order_date DATE NOT NULL,
  PRIMARY KEY (order_id) NOT ENFORCED
)
PARTITION BY order_date
CLUSTER BY customer_id, order_status
OPTIONS (
  require_partition_filter = TRUE,
  description = 'BigQuery 실무 가이드용 주문 샘플 테이블'
);
```

![BigQuery SQL 편집기에서 orders 테이블 DDL 실행](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/06-create-table-ddl.png)

> **화면 6.** DDL 전체를 검토한 뒤 실행.

## 파티션과 클러스터링은 서로 다른 범위를 줄입니다

**파티션**은 날짜처럼 큰 구간을 먼저 제외하고, **클러스터링**은 선택된 파티션 안에서 관련 값이 모인 블록을 덜 읽게 합니다. 둘을 함께 쓰면 일반적인 기간+고객 조회에 효과적입니다.

| 기능 | 권장 기준 | 이 예시 |
| --- | --- | --- |
| **파티션** | 대부분의 쿼리가 범위를 제한하는 날짜·시간 | `order_date` |
| **클러스터링** | 자주 필터·조인·그룹화하는 선택도 높은 컬럼 | `customer_id`, `order_status` |
| **파티션 필터 필수** | 전체 기간 실수 조회를 차단할 운영 테이블 | `require_partition_filter = TRUE` |

![orders 테이블의 파티션과 클러스터링 상세정보](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/08-table-partition-cluster.png)

> **화면 7.** 테이블 세부정보에서 파티션·클러스터링 적용 결과 확인.

파티션과 클러스터링의 동작은 [파티션 테이블](https://cloud.google.com/bigquery/docs/partitioned-tables)과 [클러스터링 테이블](https://cloud.google.com/bigquery/docs/clustered-tables)문서를 기준으로 설계합니다.

## 스키마와 기본 키: BigQuery는 무결성을 대신 보장하지 않습니다

![orders 테이블 스키마와 기본 키 제약조건](/wiki-assets/playbook/bigquery-dataset-and-table-design-guide/07-table-schema-primary-key.png)

> **화면 8.** 컬럼 타입·NULL 허용 여부와 기본 키 메타데이터 확인.

BigQuery의 `PRIMARY KEY... NOT ENFORCED`는 옵티마이저와 데이터 모델 문서화를 위한 선언입니다. 중복 행을 삽입할 때 데이터베이스가 거부해 주지 않습니다. 따라서 적재 파이프라인이나 `MERGE` 소스가 `order_id` 유일성을 책임져야 합니다.

- 통화·정밀 소수는 `FLOAT64`보다 `NUMERIC` 우선
- 이벤트 시각은 `TIMESTAMP`, 업무상 날짜는 `DATE`로 의미 분리
- 필수 컬럼은 `NOT NULL`, 단 선택적 값은 억지 기본값 대신 NULL 유지
- 컬럼 설명과 테이블 설명을 DDL에 함께 기록

제약조건의 정확한 의미와 제한은 [기본 키·외래 키 문서](https://cloud.google.com/bigquery/docs/primary-foreign-keys)에서 확인합니다.

## 운영 테이블 설계 체크리스트

- 데이터셋 region이 원본·소비 시스템의 위치와 맞는가
- 파티션 컬럼이 실제 쿼리의 기본 시간 범위와 맞는가
- 파티션 필터 없이 실행되는 쿼리를 차단할 것인가
- 클러스터링 컬럼 순서가 자주 쓰는 필터 순서와 맞는가
- 기본 키가 NOT ENFORCED라는 전제에서 중복 제거 책임이 정해졌는가
- 스키마 변경을 DDL과 코드 리뷰로 추적하는가

DDL 실행 후 날짜 파티션 필터와 region을 명시한 클라이언트 코드로 테이블을 조회해 설계를 검증합니다.

## 자주 묻는 질문

### 멀티 리전 US와 서울 region 중 무엇을 골라야 하나요?

데이터 거주 요건, 원본 위치, 함께 조인할 데이터셋, 실행 워크로드 위치를 먼저 봅니다. 가격만으로 고르기보다 데이터 이동과 규정까지 합쳐 결정해야 합니다.

### 데이터셋 하나에 개발·운영 테이블을 같이 둬도 되나요?

기술적으로 가능하지만 IAM·보존·실수 삭제의 경계가 흐려집니다. 환경별 프로젝트나 데이터셋을 분리하는 편이 운영상 안전합니다.

### 클러스터링 컬럼은 많이 넣을수록 좋은가요?

아닙니다. 실제 필터·조인 패턴에 맞는 소수 컬럼을 순서 있게 선택해야 합니다. 거의 필터하지 않는 컬럼은 이점이 작습니다.

## Navigation

- [전체 플레이북 Markdown sitemap](/wiki/playbook/sitemap.md)

### BigQuery

- [BigQuery](/wiki/playbook/bigquery-checklist)
- [BigQuery 온보딩](/wiki/playbook/bigquery-checklist/bigquery-onboarding-guide)
- [BigQuery 인증 설정](/wiki/playbook/bigquery-checklist/how-to-set-up-bigquery-authentication)
- [BigQuery 데이터셋·테이블 설계](/wiki/playbook/bigquery-checklist/bigquery-dataset-and-table-design-guide) (현재 문서)
- [BigQuery 쿼리·비용 제어](/wiki/playbook/bigquery-checklist/bigquery-query-and-cost-control-guide)
- [BigQuery 쓰기·MERGE·CDC](/wiki/playbook/bigquery-checklist/bigquery-data-write-and-cdc-guide)
- [BigQuery 코드 예제 모음](/wiki/playbook/bigquery-checklist/bigquery-code-examples)
- [BigQuery로 들어오는 GA4 데이터](/wiki/playbook/bigquery-checklist/what-is-ga4-data-in-bigquery)
- [BigQuery Studio 인터페이스 이해하기](/wiki/playbook/bigquery-checklist/what-is-bigquery-studio-interface)
- [BigQuery 예상 비용](/wiki/playbook/bigquery-checklist/how-to-estimate-bigquery-costs)
- [무료 버전(샌드박스) 해제해야 하는 이유](/wiki/playbook/bigquery-checklist/why-upgrade-from-bigquery-sandbox)
- [GA4 BigQuery 데이터를 왜 평탄화해야 하나](/wiki/playbook/bigquery-checklist/why-flatten-ga4-bigquery-data)
- [Log Router란?](/wiki/playbook/bigquery-checklist/what-is-log-router)
- [Pub/Sub이란?](/wiki/playbook/bigquery-checklist/what-is-pubsub)
- [Cloud Functions이란?](/wiki/playbook/bigquery-checklist/what-is-cloud-function-and-run)
- [GA4 export 시점에 예약 쿼리 자동 실행하기](/wiki/playbook/bigquery-checklist/how-to-trigger-scheduled-query-on-ga4-export)
- [테이블 정의서는 왜 필요한가](/wiki/playbook/bigquery-checklist/why-table-definition-doc)
- [Event_Flat 테이블 이해하기](/wiki/playbook/bigquery-checklist/what-is-event-flat-table)
- [Item_Performance 테이블 이해하기](/wiki/playbook/bigquery-checklist/what-is-item-performance-table)
