생성된 컬럼 (Generated columns)
D1의 생성된 컬럼(generated columns)을 소개하는 문서예요. 데이터를 테이블에 쓰거나 읽을 때 자동으로 정규화해서, 쿼리를 더 쉽게 만들고 복잡한 애플리케이션 로직의 필요를 줄여줘요.
출처: 문서
본문
Generated columns
이 기능은 데이터를 테이블에 쓰거나 읽을 때 데이터를 정규화할 수 있게 해줘서, 쿼리가 더 쉬워지고 복잡한 애플리케이션 로직이 덜 필요해져요.
생성된 컬럼에는 인덱스를 정의할 수도 있어요. 자주 쿼리하는 필드에 대해 쿼리 성능을 크게 높일 수 있거든요.
생성된 컬럼의 유형
생성된 컬럼에는 두 가지 유형이 있어요.
-
VIRTUAL(기본값): 컬럼이 읽을 때 생성돼요. 저장 공간을 소모하지 않는다는 장점이 있지만, 특히 큰 쿼리에서는 컴퓨팅 시간이 늘어나(따라서 쿼리 성능이 떨어질 수 있어요)요. -
STORED: 컬럼이 행이 쓰일 때 생성돼요. 일반 컬럼처럼 저장 공간을 차지하지만, 읽을 때마다 컬럼을 생성할 필요가 없어서 읽기 쿼리 성능을 높일 수 있어요.
생성된 컬럼 표현식에서 생략하면 생성된 컬럼은 기본적으로 VIRTUAL 유형이 돼요. 생성된 컬럼이 컴퓨팅 집약적일 때는 STORED 유형을 권장해요. 예를 들어 큰 JSON 구조를 파싱할 때요.
생성된 컬럼 정의하기
생성된 컬럼은 CREATE TABLE 문으로 테이블을 만들 때 정의하거나, 이후에 ALTER TABLE 문으로 정의할 수 있어요.
생성된 컬럼을 정의하는 테이블을 만들려면 AS 키워드를 사용해요.
CREATE TABLE some_table (
-- other columns omitted
some_generated_column AS <function_that_generates_the_column_data>
)
구체적인 예로, 다음 JSON 센서 데이터에서 location 값을 자동으로 추출하려면 JSON 데이터의 원본 표현을 저장하는 raw_data 컬럼을 기반으로 location(유형 TEXT)라는 생성된 컬럼을 정의할 수 있어요.
{
"measurement": {
"temp_f": "77.4",
"aqi": [21, 42, 58],
"o3": [18, 500],
"wind_mph": "13",
"location": "US-NY"
}
}
$.measurement.location 값을 가진 생성된 컬럼을 정의하려면 json_extract 함수를 사용해 그 행에 쓸 때마다 raw_data 컬럼에서 값을 추출할 수 있어요.
CREATE TABLE sensor_readings (
event_id INTEGER PRIMARY KEY,
timestamp INTEGER NOT NULL,
raw_data TEXT,
location as (json_extract(raw_data, '$.measurement.location')) STORED
);
생성된 컬럼은 선택적으로 column_name GENERATED ALWAYS AS <function> [STORED|VIRTUAL] 구문으로 지정할 수 있어요. GENERATED ALWAYS 구문은 선택사항이며 생략해도 생성된 컬럼의 동작은 바뀌지 않아요.
기존 테이블에 생성된 컬럼 추가하기
생성된 컬럼은 기존 테이블에도 추가할 수 있어요. sensor_readings 테이블에 생성된 location 컬럼이 없다면 ALTER TABLE 문으로 추가할 수 있어요.
ALTER TABLE sensor_readings
ADD COLUMN location as (json_extract(raw_data, '$.measurement.location'));
이것은 각 읽기 쿼리에서 json_extract를 실행하는 VIRTUAL 생성된 컬럼을 정의해요.
생성된 컬럼 정의는 직접 수정할 수 없어요. 생성된 컬럼이 데이터를 생성하는 방식을 바꾸려면 ALTER TABLE table_name REMOVE COLUMN 후 ADD COLUMN으로 생성된 컬럼을 다시 정의하거나, 새 정의로 ADD COLUMN을 호출하기 전에 ALTER TABLE table_name RENAME COLUMN current_name TO new_name으로 기존 컬럼 이름을 바꾸면 돼요.
예시
생성된 컬럼은 json_extract 같은 JSON 함수에만 국한되지 않아요. 생성된 컬럼이 어떻게 생성될지 정의하는 데 거의 모든 사용 가능한 함수를 쓸 수 있어요.
예를 들어 앞선 sensor_reading 테이블의 timestamp 컬럼을 기반으로 date 컬럼을 생성해서, 데이터베이스 안에서 Unix 타임스탬프를 YYYY-MM-dd 형식으로 자동 변환할 수 있어요.
ALTER TABLE your_table
-- date(timestamp, 'unixepoch') converts a Unix timestamp to a YYYY-MM-dd formatted date
ADD COLUMN formatted_date AS (date(timestamp, 'unixepoch'))
또는 미래 날짜를 계산하는 expires_at 컬럼을 정의하고, 쿼리에서 그 날짜를 기준으로 필터링할 수도 있어요.
-- Filter out "expired" results based on your generated column:
-- SELECT * FROM your_table WHERE current_date() > expires_at
ALTER TABLE your_table
-- calculates a date (YYYY-MM-dd) 30 days from the timestamp.
ADD COLUMN expires_at AS (date(timestamp, '+30 days'));
추가 고려 사항
-
테이블에는 생성되지 않은 컬럼이 최소 1개 이상 있어야 해요. 생성된 컬럼만으로 테이블을 정의할 수는 없어요.
-
표현식은 같은 테이블과 행의 다른 컬럼만 참조할 수 있으며, 결정적 함수 (deterministic functions) ↗︎만 사용해야 해요.
random()같은 함수, 서브쿼리, 집계 함수는 생성된 컬럼을 정의하는 데 사용할 수 없어요. -
ALTER TABLE ... ADD COLUMN으로 기존 테이블에 추가하는 컬럼은VIRTUAL이어야 해요. 기존 테이블에는STORED컬럼을 추가할 수 없어요.