행
고친 사람 github-actions[bot]
행은 테이블에 담긴 자료 한 건을 가로 한 줄로 묶어 둡니다. 회원 명단을 담은 테이블이라면 회원 한 명이 행 하나입니다. 행렬의 가로 줄이나 글의 한 줄도 행이라고 부릅니다. 이 항목은 데이터베이스 테이블의 행을 다룹니다.
쉽고 빠른 이해
행은 테이블에서 자료 한 건을 담는 가로 줄입니다. 회원 테이블이라면 태호의 이름과 나이가 한 줄에 모여 행 하나가 됩니다.
한 사람의 이름과 나이가 따로 흩어져 있으면 어느 이름이 어느 나이와 짝인지 알 수 없습니다. 행은 한 건에 딸린 값들을 한 줄에 묶어 둡니다. 그래서 넣고 고치고 지우는 일을 한 건씩 할 수 있습니다.
어떻게 도나:
- 자료가 한 건 들어올 때마다 행이 하나 늘어납니다
- 행마다 회원 id 처럼 겹치지 않는 값을 붙입니다. 그 값으로 행 하나를 집어 찾습니다
- 고치거나 지울 때도 조건에 맞는 행을 골라서 합니다
대가는 한 칸에 값 하나만 들어간다는 것입니다. 전화번호가 둘인 회원은 전화번호를 다른 테이블의 행 둘로 나누어 적습니다. 다시 한 화면에 모아 보려면 두 테이블을 맞춰 읽어야 합니다.
상세
가계부를 떠올려 봅니다. 한 줄에 날짜와 쓴 곳과 금액을 적습니다. 커피를 한 잔 사면 줄이 하나 늡니다. 그 한 줄이 지출 한 번입니다.
행은 테이블 안에서 자료 한 건을 이루는 값들을 가로로 묶은 줄입니다. 테이블은 세로 줄인 열 여럿으로 짜입니다. 행은 그 열마다 값을 하나씩 채운 한 줄입니다.
열과 행은 늘어나는 방식이 다릅니다. 열은 테이블을 설계할 때 정해 두고 오래 바꾸지 않습니다. 행은 자료가 들어올 때마다 늘어납니다. 지우면 줄어듭니다. 테이블이 「무엇을 담나」는 열이 정합니다. 「얼마나 담았나」는 행의 개수가 말해 줍니다.
한 행이 한 건을 뜻하는 표
아래는 회원 세 명을 담은 members 테이블입니다. 열은 id·name·age 셋입니다. 행도
셋입니다.
| id | name | age |
|---|---|---|
| 1 | 유미 | 3 |
| 2 | 태호 | 5 |
| 3 | 지연 | 4 |
가로 한 줄이 회원 한 명입니다. 태호의 행을 가리키면 태호라는 이름과 다섯 살이라는 나이가 함께 따라옵니다. 행 하나를 다루면 한 건에 딸린 값을 한꺼번에 다루게 됩니다.
행 안에 든 값 하나는 필드라고 부릅니다. 행과 열이 만나는 한 칸이라서 셀이라고도
합니다. 위 표에서 태호 행의 age 필드 값은 5 입니다.
행을 가리키는 다른 이름도 있습니다. 파일이나 프로그래밍 언어 쪽에서는 행에 해당하는 값 묶음을 레코드라고 부릅니다. 가리키는 것은 같습니다. 이름 붙은 값 한 묶음입니다.
관계형 데이터베이스는 자료를 이런 테이블 여럿에 나누어 담습니다. 이 방식을 떠받치는 이론을 관계형 모델이라고 합니다. 관계형 모델에서는 행을 튜플이라는 이름으로 씁니다.
행을 집어 가리키는 기본 키
행에는 정해진 순서가 없습니다. 관계형 모델은 테이블을 행들의 집합으로 봅니다. 집합에는 첫째와 둘째가 따로 없습니다.
그래서 「세 번째 행」은 믿을 만한 주소가 못 됩니다. 앞의 행 하나를 지우거나 새 행을 넣으면 몇
번째인지가 바뀝니다. 꺼낼 때 순서가 필요하면 무엇으로 줄 세울지를 그때마다 적어 줘야 합니다.
SQL(Structured Query Language, 구조화 질의 언어)에서는 ORDER BY 로 그 기준을 적습니다.
순서 대신 행을 가리키는 것이 값입니다. 행마다 다른 행과 겹치지 않는 값을 하나 둡니다. 그 값으로
행을 부릅니다. 이 값을 담는 열이 기본 키입니다. 위 표에서는 id 가 기본 키입니다.
기본 키는 두 가지를 지킵니다. 두 행이 같은 값을 가질 수 없습니다. 값이 비어 있을 수도 없습니다. 이 둘이 지켜지면 기본 키 값 하나가 행 하나를 가리킵니다.
데이터베이스에 자료를 달라고 보내는 요청을 질의라고 합니다. 아래는 id 가 2인 행에서 이름을
꺼내는 질의입니다.
SELECT name FROM members
WHERE id = 2; -- 태호
WHERE 뒤의 조건이 행을 고릅니다. SELECT 뒤에 적은 것이 그 행에서 꺼낼 열입니다. 기본 키로
고르면 돌아오는 행은 많아야 하나입니다.
기본 키가 없으면 똑같은 값을 가진 행이 둘 들어갈 수 있습니다. SQL 테이블은 키를 걸어 두지 않으면 중복 행을 막지 않습니다. 그때는 둘 중 하나만 고치거나 지울 방법이 없습니다.
값이 여럿 딸리는 항목
한 칸에는 값을 하나만 넣습니다. 태호의 전화번호 둘을 쉼표로 이어 한 칸에 넣었다고 해 봅니다. 그 칸에 든 것은 전화번호 둘이 붙은 긴 문자열 하나입니다.
그러면 「010-3333-4444 의 주인은 누구인가」를 값이 같은지로 물을 수 없습니다. 칸의 값은 그 전화번호와 같지 않기 때문입니다. 칸마다 값 하나만 두는 규칙을 제1정규형이라고 합니다.
그러면 전화번호가 둘인 회원은 어떻게 적을까요. 전화번호를 담을 테이블을 따로 둡니다. 전화번호
하나가 그 테이블의 행 하나가 됩니다. 아래 phones 테이블은 id·member_id·number 세 열로
되어 있습니다.
| id | member_id | number |
|---|---|---|
| 10 | 2 | 010-1111-2222 |
| 11 | 2 | 010-3333-4444 |
두 행 모두 member_id 가 2 입니다. 두 전화번호가 모두 태호의 것이라는 뜻입니다. 이렇게 한 건에
딸린 값이 여럿이면 행을 나누어 다른 테이블에 적습니다. 테이블을 이렇게 나누어 가는 설계가
정규화입니다.
다른 테이블의 행을 가리키는 외래 키
phones 의 member_id 처럼 다른 테이블의 행을 가리키는 열이 외래 키입니다. 외래 키에는
가리킬 테이블의 기본 키 값을 적습니다. 전화번호 행 하나가 회원 행 하나를 가리키는 셈입니다.
flowchart TD
subgraph P["phones 테이블"]
P1["id 10 · member_id 2 · 010-1111-2222"]
P2["id 11 · member_id 2 · 010-3333-4444"]
end
subgraph M["members 테이블"]
M2["id 2 · 태호 · 5살"]
end
P1 -->|"member_id = 2"| M2
P2 -->|"member_id = 2"| M2
그림에서 전화번호 행 둘이 같은 회원 행 하나를 가리킵니다. 회원 한 명에 전화번호가 몇 개 붙든 회원 행은 하나로 남습니다.
외래 키를 걸어 두면 데이터베이스가 가리키는 행이 실제로 있는지 검사합니다. members 에 없는 id
를 member_id 로 적은 전화번호 행은 넣을 수 없습니다. 이 성질을 참조 무결성이라고 합니다.
전화번호 행이 가리키고 있는 회원 행을 지우려 할 때 흔히 쓰는 선택은 둘입니다. 삭제를 거절하거나 그 회원의 전화번호 행까지 함께 지웁니다. 어느 쪽으로 할지는 외래 키를 만들 때 정해 둡니다.
나누어 적은 값은 읽을 때 다시 모읍니다. 태호의 이름과 전화번호 둘을 한 번에 보려면 두 테이블에서
member_id 와 id 가 같은 행끼리 짝지어 읽습니다. 이렇게 행을 키로 맞춰 한 줄로 합치는 일이
조인입니다.
행 단위로 넣고 고치고 지우는 명령
자료를 바꾸는 명령은 행을 단위로 움직입니다. INSERT 는 행을 새로 넣습니다. UPDATE 는 조건에
맞는 행들의 값을 바꿉니다. DELETE 는 조건에 맞는 행들을 지웁니다.
아래는 앞의 members 테이블에 명령 셋을 차례로 보낸 것입니다. 오른쪽 주석이 명령마다 건드린 행의
수입니다.
INSERT INTO members
VALUES (4, '민수', 2); -- 1행 추가
UPDATE members SET age = 6
WHERE id = 2; -- 1행 변경
DELETE FROM members
WHERE age > 3; -- 2행 삭제
세 번째 명령에서 조건에 맞는 행은 여섯 살이 된 태호와 네 살인 지연입니다. 그래서 두 행이
지워집니다. 유미와 민수가 남습니다. WHERE 를 빠뜨리면 모든 행이 대상이 됩니다.
명령을 마치면 데이터베이스는 몇 행을 건드렸는지를 숫자로 돌려줍니다. 애플리케이션은 이 수를 보고
뜻한 만큼 바뀌었는지 확인합니다. 한 행만 고치려던 UPDATE 가 0 을 돌려주면 고를 행이 없었다는
뜻입니다.
애플리케이션으로 돌아오는 행
SELECT 로 꺼낸 자료도 행으로 돌아옵니다. 앞의 WHERE id = 2 질의는 태호의 이름 하나가 든 행
하나를 돌려줍니다. 조건에 맞는 행이 여럿이면 여럿이 한꺼번에 옵니다. 질의가 돌려준 행들의 묶음을
결과 집합이라고 합니다.
애플리케이션 코드는 대개 돌아온 행 하나를 객체 하나로 옮겨서 다룹니다. members 의 행 하나가
Member 객체 하나가 되는 식입니다. 그래야 코드 안에서 필드를 이름으로 꺼내 쓰기 편합니다. 그
옮기는 일을 맡는 도구가 ORM(Object-Relational Mapping, 객체-관계 매핑)입니다.
같은 행을 동시에 고치는 요청
두 요청이 태호의 나이를 동시에 한 살씩 올린다고 해 봅니다. 둘 다 5를 읽고 저마다 6을 씁니다. 두 번 올렸는데 나이는 6에 머뭅니다. 한쪽의 변경이 다른 쪽에 덮여 사라진 것입니다.
이를 막으려고 데이터베이스는 행을 고치는 동안 그 행에 잠금을 겁니다. 잠긴 행을 고치려는 다른 요청은 앞의 요청이 끝날 때까지 기다립니다.
많은 데이터베이스는 테이블 전체가 아니라 고치는 행만 잠급니다. 이를 행 잠금이라고 합니다. 태호의 행을 고치는 동안에도 지연의 행은 다른 요청이 고칠 수 있습니다.
행마다 따로 잠그면 서로 기다리다 멈추는 일이 생길 수 있습니다. 요청 하나는 태호의 행을 잠근 채 지연의 행을 기다립니다. 다른 요청은 지연의 행을 잠근 채 태호의 행을 기다립니다. 둘 다 끝나지 못하는 이 상태가 데드락입니다.
행을 디스크에 적는 방식
질의 결과로 받아 보면 행은 늘 표의 가로 한 줄입니다. 하지만 디스크에 적는 방식은 둘로 갈립니다. 한 행의 값들을 붙여 적는 방식이 행 지향 저장입니다.
행 지향 저장은 한 건을 읽고 쓰는 일이 빠릅니다. 회원 한 명의 값이 한데 모여 있어 한 번에 읽힙니다. 건별로 읽고 쓰는 업무 시스템이 대개 행 지향 저장을 씁니다.
한 열의 값들을 붙여 적는 방식이 열 지향 저장입니다. 나이 평균처럼 한 열만 훑는 집계에서는 이쪽이 빠릅니다. 쓰지 않는 이름 열은 읽지 않고 넘어가기 때문입니다. 행 지향 저장이었다면 안 쓸 이름까지 함께 읽고 지나갑니다.
관련 항목
행이 모여 이루는 데이터 단위
테이블 · 릴레이션 · 결과 집합 · 스키마 · 데이터베이스 · 관계형 데이터베이스
행 하나를 이루는 구성 요소
행에 해당하는 다른 모델의 단위
행을 식별하고 이어 주는 키
기본 키 · 외래 키 · 후보 키 · 대리 키 · 자연 키 · 복합 키 · 참조 무결성
행을 넣고 고치고 지우는 명령
SQL · INSERT · UPDATE · DELETE · SELECT · DML · UPSERT · ORDER BY
흩어진 행을 합치고 거르는 질의 연산
조인 · WHERE · 집계 함수 · GROUP BY · 서브쿼리
동시에 고치는 행을 지키는 장치
트랜잭션 · 락 · 행 잠금 · MVCC · 데드락 · 격리 수준
행을 디스크에 적는 방식
행 지향 저장 · 열 지향 저장 · 페이지 · 인덱스
행 설계에서 자주 터지는 문제
정규화 · 제1정규형 · 반정규화 · EAV · 이상 현상 · 중복 행
행을 코드의 객체로 옮기는 도구
ORM · 액티브 레코드 · 데이터 매퍼 · 엔티티 · DTO
행이라는 낱말을 함께 쓰는 다른 분야
행렬 · 스프레드시트 · CSV · 텍스트 편집기
다른 이름: row · rows · 로우