사전 열
개념

열

gabury1고친 사람 github-actions[bot]

열은 테이블에 어떤 값이 들어올 수 있는지를 미리 정해 둡니다. 회원 명단을 담은 테이블이라면 나이가 들어가는 세로 한 줄이 열입니다. 표 계산 프로그램이나 행렬의 세로 한 줄도 열이라고 부릅니다. 이 항목은 데이터베이스 테이블의 열을 다룹니다.

쉽고 빠른 이해

열은 테이블에서 같은 뜻을 가진 값들이 들어가는 세로 줄입니다. 회원 명단을 담은 테이블이라면 나이가 들어가는 줄 하나가 열입니다.

열을 미리 정해 두지 않으면 어떤 회원은 나이가 숫자로, 어떤 회원은 글자로 들어옵니다. 읽는 쪽은 값을 볼 때마다 이게 무슨 종류인지 짐작해야 합니다. 열은 그 짐작을 없앱니다.

어떻게 도나:

  1. 테이블을 만들 때 열 이름과 그 열에 들어갈 값의 종류를 정합니다
  2. 자료를 한 건 넣을 때마다 데이터베이스가 약속에 맞는 값인지 검사합니다
  3. 읽을 때는 열 이름을 대서 원하는 열만 꺼냅니다

대가는 한 번 정한 약속을 나중에 바꾸기 어렵다는 것입니다. 열을 지우거나 값의 종류를 바꾸면 이미 쌓인 자료와 그 열을 읽던 코드를 함께 손봐야 합니다.

담을 항목이 건마다 달라야 한다면 열을 미리 정하는 방식이 맞지 않습니다. 그럴 때는 열을 미리 정해 두지 않는 저장 방식을 고릅니다.

상세

학급 출석부를 떠올려 봅니다. 맨 윗줄에 「이름」과 「생년월일」과 「연락처」가 인쇄되어 있습니다. 학생이 몇 명 늘어도 그 제목은 바뀌지 않습니다.

열은 테이블 안에서 같은 뜻을 가진 값들이 모이는 세로 줄입니다. 테이블 하나는 열 여럿을 가로로 늘어놓은 것입니다. 자료는 그 아래로 한 줄씩 쌓입니다. 그 가로 한 줄이 행입니다.

둘은 늘어나는 방식이 다릅니다. 행은 자료가 들어올 때마다 늘고 지워지기도 합니다. 열은 테이블을 설계할 때 정해 두고 오래 바꾸지 않습니다. 그래서 이 테이블이 무엇을 담는지는 열 이름만 훑어도 대강 읽힙니다.

행과 열이 나누어 맡는 몫

아래는 회원 세 건을 담은 members 테이블입니다. 가로 한 줄이 회원 한 명이고, 세로 한 줄이 열입니다.

id name age
1 유미 3
2 태호 5
3 지연 4

행은 한 건을 통째로 가리킵니다. 「2번 회원」이라고 하면 이름과 나이가 함께 따라옵니다. 열은 한 종류를 가리킵니다. 「age 열」이라고 하면 회원이 몇 명이든 나이만 모입니다.

행과 열이 만나는 한 칸이 셀입니다. 위 표에서 2번 행과 age 열이 만나는 셀의 값은 5 입니다. 이 문서는 세로 줄을 열, 그 줄과 행이 만나는 한 칸을 셀이라고 적습니다.

이 셀을 필드라고 부르는 문서도 많습니다. 둘을 가려 쓰는 문서에서 열은 설계상의 세로 줄입니다. 필드는 한 행 안에서 그 열에 든 값 하나입니다. 다른 글에서 필드를 만나면 셀을 가리키는지 열을 가리키는지만 보고 읽으면 됩니다.

관계형 모델을 다루는 문서는 열을 속성이라고 적습니다. 낱말이 갈릴 뿐 가리키는 것은 같습니다. 어느 말을 쓰는지 먼저 맞춰 두면 됩니다.

열 하나가 정해 두는 약속

열을 만드는 일은 세로 줄을 하나 긋는 일이 아니라 그 줄에 관한 약속을 적는 일입니다. 약속은 네 가지로 나뉩니다.

무엇을 정하나 정해 두면 안 정하면
이름 이 열을 부를 말이 생깁니다 몇 번째 열인지로만 부르게 됩니다
데이터 타입 숫자 열에 글자가 들어오는 일을 막습니다 읽는 쪽이 매번 종류를 확인합니다
비어 있어도 되는지 빠뜨린 값을 넣는 시점에 잡습니다 값이 없는 행을 나중에 발견합니다
값의 범위 나이가 음수인 행이 안 생깁니다 어긋난 값이 섞인 채 쌓입니다

값이 없는 상태를 널이라고 합니다. 숫자 0 이나 빈 글자와는 다릅니다. 「아직 모른다」와 「값이 0 이다」를 가르려고 따로 둔 표시입니다. 열마다 널을 받을지 말지를 정해 둡니다.

값을 안 주고 행을 넣을 때 대신 들어갈 값을 미리 정해 둘 수도 있습니다. 그 값이 기본값입니다. 기본값을 정해 두면 그 열을 빠뜨린 행에도 널 대신 그 값이 들어갑니다.

값의 범위를 제한하는 규칙은 제약입니다. 나이는 음수일 수 없다거나, 같은 이메일이 두 행에 있을 수 없다는 것이 제약입니다. 제약을 열에 붙여 두면 어긋난 값을 넣으려는 시도가 그 자체로 실패합니다.

정해 둔 약속은 값을 넣을 때마다 검사됩니다. 한 군데라도 어긋나면 그 행은 저장되지 않습니다.

flowchart TD
    V["들어온 값"] --> T{"열이 정한 타입인가"}
    T -->|아니다| X["거절하고 행을 안 넣는다"]
    T -->|맞다| C{"열에 걸린 제약을 지키나"}
    C -->|아니다| X
    C -->|맞다| OK["그 행의 그 열에 저장"]

검사를 통과하지 못한 값은 조용히 버려지지 않고 오류로 돌아옵니다. 잘못된 자료가 들어오는 것을 읽는 쪽이 아니라 쓰는 쪽에서 막는 셈입니다.

어떤 열이 있고 각 열이 무엇을 약속하는지를 적어 둔 설계도가 스키마입니다. 스키마는 자료를 넣는 쪽과 읽는 쪽이 함께 보는 문서 노릇을 합니다.

열 이름으로 값을 꺼내는 질의

관계형 데이터베이스에서 자료를 꺼낼 때는 몇 번째 열인지가 아니라 열 이름을 댑니다. 아래는 SQL(Structured Query Language, 구조화 질의 언어)로 적은 질의 둘입니다.

SQL
SELECT name FROM members WHERE id = 2;  -- 태호
SELECT age  FROM members WHERE id = 3;  -- 4

SELECT 뒤에 적은 것이 꺼낼 열입니다. WHERE 뒤에 적은 것이 고를 행의 조건입니다. 가로로 행을 고르고 세로로 열을 고르는 두 축이 질의 한 줄에 함께 들어 있습니다.

flowchart TD
    Q1["members 세 행"] --> Q2["WHERE id = 2 · 행 하나만 남는다"]
    Q2 --> Q3["SELECT name · 그 행에서 name 열만 남는다"]
    Q3 --> Q4["값 하나 · 태호"]

필요한 열만 적으면 쓰지도 않을 값을 읽어 오는 일이 줄어듭니다. 특히 긴 글이 담긴 열이 섞여 있을 때 차이가 납니다. 모든 열을 부르는 * 는 편하지만, 뒤에 열이 하나 더 생기면 그 질의가 꺼내 오는 것도 말없이 달라집니다.

고르는 조건에 자주 쓰이는 열은 그 열로 찾는 일이 빨라지게 해 둡니다. 특정 열의 값으로 행을 빨리 찾도록 곁에 만들어 두는 구조가 인덱스입니다. 어느 열에 인덱스를 둘지는 그 열로 얼마나 자주 찾느냐가 정합니다.

열을 나중에 바꾸는 비용

열을 더하는 일과 지우는 일은 치르는 비용이 다릅니다. 이미 쌓인 행이 몇 건인지, 도는 코드가 그 열을 어떻게 읽고 있었는지가 비용을 정합니다.

바꾸는 일 이미 쌓인 행 그 열을 읽던 코드
열 더하기 기본값을 정해 두었으면 그 값이, 아니면 널이 들어갑니다 모르는 열이라 안 건드립니다
열 이름 바꾸기 그대로 남습니다 옛 이름으로 부르던 질의가 깨집니다
타입 바꾸기 모든 행의 값을 새 종류로 옮겨야 합니다 받는 값의 종류가 달라집니다
열 지우기 그 열에 있던 값이 사라집니다 그 열을 부르던 질의가 깨집니다

그래서 열은 더하는 쪽으로 먼저 움직입니다. 지우는 일은 아무도 그 열을 안 읽는 것을 확인한 뒤로 미룹니다. 새 열을 만들어 값을 옮기고, 읽는 쪽을 새 열로 바꾸고, 마지막에 옛 열을 지우는 식입니다. 이렇게 스키마를 단계로 나누어 바꾸는 일이 스키마 마이그레이션입니다.

flowchart TD
    M1["새 열 추가"] --> M2["값 옮기기"]
    M2 --> M3["읽는 쪽을 새 열로"]
    M3 --> M4["아무도 안 읽는 것 확인"]
    M4 --> M5["옛 열 삭제"]

행이 많이 쌓인 테이블에서는 바꾸는 시간도 따집니다. 모든 행을 손대야 하는 변경은 자료가 많을수록 오래 걸립니다. 그동안 그 테이블을 쓰는 다른 작업이 기다리게 될 수 있습니다.

행 단위 저장과 열 단위 저장

화면에서는 표 한 장으로 보입니다. 디스크에 적는 방법은 둘로 갈립니다. 한 행을 이루는 값들을 붙여 적을 수도 있고, 한 열을 이루는 값들을 붙여 적을 수도 있습니다.

flowchart TD
    subgraph R["행 단위로 적은 경우"]
        R1["행 1: 1 · 유미 · 3"]
        R2["행 2: 2 · 태호 · 5"]
        R3["행 3: 3 · 지연 · 4"]
    end
    subgraph C["열 단위로 적은 경우"]
        C1["id: 1 · 2 · 3"]
        C2["name: 유미 · 태호 · 지연"]
        C3["age: 3 · 5 · 4"]
    end

행 단위로 적으면 한 회원의 모든 값이 한자리에 붙어 있습니다. 열 단위로 적으면 나이만 한자리에 모입니다. 앞쪽이 행 지향 저장이고 뒤쪽이 열 지향 저장입니다. 둘은 잘하는 일이 갈립니다.

행 지향 저장 열 지향 저장
한 건 읽고 쓰기 한 번의 접근으로 끝납니다 흩어진 열마다 값을 나누어 적습니다
여러 행 집계 안 쓸 열까지 함께 읽고 지나갑니다 필요한 열만 훑습니다
압축 한 줄에 여러 종류가 섞여 덜 먹습니다 같은 종류가 이어 붙어 잘 먹습니다
어디에 쓰나 건별로 읽고 쓰는 업무 시스템 몇 개 열만 훑어 집계하는 분석 시스템

어느 쪽이 맞는지는 한 건을 자주 만지나, 한 열을 자주 훑나로 갈립니다.

열을 늘리지 않고 행으로 미는 설계

담을 항목이 자주 늘어나면 열을 계속 더하기가 부담스러워집니다. 그래서 「항목 이름」 열과 「값」 열 둘만 두고, 항목 하나를 행 하나로 적는 설계가 나옵니다. 이 모양을 EAV(Entity-Attribute-Value, 엔티티-속성-값)라고 합니다.

같은 members 를 두 모양으로 적으면 이렇게 갈립니다.

flowchart TD
    subgraph A["열로 둔 members"]
        A1["id"]
        A2["name"]
        A3["age"]
    end
    subgraph B["EAV 로 눕힌 members"]
        B1["1 · name · 유미"]
        B2["1 · age · 3"]
        B3["2 · name · 태호"]
    end

왼쪽은 회원 한 명이 행 하나입니다. 오른쪽은 회원 한 명의 항목 하나가 행 하나라, 회원이 그대로여도 행 수가 항목 수만큼 불어납니다.

열을 안 건드리고 항목을 늘릴 수 있는 것이 이 설계의 이점입니다. 대신 열이 지고 있던 약속을 함께 잃습니다. 잃는 것은 셋입니다.

잃는 것 무엇이 곤란해지나
타입 값 열 하나에 숫자와 날짜와 글자가 섞여 들어옵니다
제약 항목마다 다른 규칙을 걸어 둘 열이 없습니다
조회 항목 셋을 함께 보려면 한 테이블을 세 번 맞춰 읽어야 합니다

세 번 맞춰 읽는다는 것은 같은 회원의 행 셋을 골라 한 줄로 합친다는 뜻입니다. 이렇게 흩어진 행을 키로 맞춰 한 줄로 합치는 일이 조인입니다. 열로 두었으면 한 행을 한 번 읽고 끝날 일입니다.

가르는 기준은 항목 목록이 설계할 때 미리 정해지느냐, 쓰는 사람이 실행 중에 늘리느냐입니다. 설계할 때 정해지는 항목이면 열로 둡니다. 그러면 검사와 질의를 데이터베이스에 맡길 수 있습니다.

쓰는 사람이 마음대로 항목을 만들어야 한다면 열로 감당하기 어렵습니다. 그때는 열을 미리 정해 두지 않는 스키마리스 저장 방식까지 함께 견줍니다.

관련 항목

열이 모여 이루는 데이터 단위

테이블 · 행 · 셀 · 레코드 · 튜플 · 릴레이션 · 결과 집합 · 차수

열 하나를 정의하는 요소

데이터 타입 · 널 · 기본값 · 제약 · 도메인 · 식별자 · 길이 제한

열에 걸어 두는 제약

기본 키 · 외래 키 · 유일 제약 · 검사 제약 · 널 제약 · 참조 무결성

열을 만들고 바꾸는 명령

DDL · CREATE TABLE · ALTER TABLE · SELECT · 스키마 · 스키마 마이그레이션 · 온라인 DDL

흩어진 행과 열을 한 결과로 합치는 질의 연산

조인 · 뷰 · 집계 함수 · 서브쿼리

열을 가리키는 다른 이름

필드 · 속성 · 프로퍼티 · 멤버 변수 · 인스턴스 변수

열로 행을 빨리 찾게 하는 구조

인덱스 · 복합 인덱스 · 커버링 인덱스 · 통계 정보 · 선택도 · 히스토그램

열을 디스크에 적는 방식

행 지향 저장 · 열 지향 저장 · 압축 · Parquet · 데이터 웨어하우스 · SQL · 관계형 데이터베이스

열을 미리 정하지 않는 저장 방식

스키마리스 · 문서 데이터베이스 · NoSQL · 키-값 저장소

열 설계에서 자주 터지는 문제

EAV · 와이드 테이블 · 정규화 · 반정규화 · 스키마 진화 · 하위 호환성

다른 이름: column · 컬럼 · columns