4 분 소요

이 장에서 배울 것

이번 장에서는 데이터베이스(database)와 SQL을 배웁니다. 데이터베이스는 데이터를 규칙 있게 저장하고 찾기 위한 시스템입니다. SQL은 데이터베이스에 질문을 던지는 언어입니다.

핵심 용어를 먼저 정리하겠습니다.

  • 데이터베이스(database): 데이터를 체계적으로 저장하고 관리하는 시스템입니다.
  • 테이블(table): 행과 열로 이루어진 표입니다.
  • 행(row): 한 개체에 대한 기록입니다. 예를 들어 환자 한 명, 샘플 하나, 유전자 하나가 한 행이 될 수 있습니다.
  • 열(column): 기록의 속성입니다. 예를 들어 환자 나이, 샘플 ID, 유전자 이름이 열이 될 수 있습니다.
  • 기본키(primary key): 각 행을 구분하는 고유한 값입니다.
  • 외래키(foreign key): 다른 테이블의 기본키를 가리키는 값입니다.
  • 조인(join): 두 테이블을 공통 열을 기준으로 연결하는 작업입니다.
  • 인덱스(index): 검색을 빠르게 하기 위한 자료구조입니다.
  • SQL: 테이블에서 원하는 데이터를 찾고, 걸러내고, 연결하는 데 쓰는 언어입니다.

데이터베이스와 SQL

가장 쉬운 비유: 여러 장의 출석부를 연결하기

한 표에는 학생 이름과 학번이 있고, 다른 표에는 학번과 시험 점수가 있다고 해 봅시다. 두 표를 학번으로 연결하면 “학생 이름과 시험 점수”를 함께 볼 수 있습니다.

생물정보학도 비슷합니다. 환자 정보 표, 샘플 정보 표, 유전자 발현 표, 변이 표가 따로 있을 수 있습니다. 이 표들을 샘플 ID나 환자 ID로 연결해야 제대로 해석할 수 있습니다.

테이블의 기본 구조

예를 들어 환자 테이블은 이렇게 생길 수 있습니다.

patient_id   age   disease
P001         54    cancer
P002         40    normal
P003         62    cancer

여기서 patient_id는 각 환자를 구분하는 값입니다. 같은 환자 ID가 두 번 나오면 헷갈리므로 기본키로 쓰기 좋습니다.

샘플 테이블은 이렇게 생길 수 있습니다.

sample_id   patient_id   tissue
S001        P001         tumor
S002        P001         normal
S003        P002         blood

여기서 patient_id는 환자 테이블과 연결되는 값입니다.

SELECT: 원하는 열 가져오기

SQL의 기본 형태는 다음과 같습니다.

SELECT patient_id, age
FROM patients;

뜻은 patients 테이블에서 patient_idage 열을 가져오라는 말입니다.

모든 열을 가져오려면 *를 쓸 수 있습니다.

SELECT *
FROM patients;

하지만 실제 분석에서는 필요한 열만 가져오는 습관이 좋습니다.

WHERE: 조건으로 걸러내기

암 환자만 보고 싶다면 조건을 붙입니다.

SELECT *
FROM patients
WHERE disease = 'cancer';

나이가 50 이상인 환자를 고를 수도 있습니다.

SELECT *
FROM patients
WHERE age >= 50;

JOIN: 표 연결하기

환자 테이블과 샘플 테이블을 연결하려면 조인을 씁니다.

SELECT p.patient_id, p.age, s.sample_id, s.tissue
FROM patients p
JOIN samples s
  ON p.patient_id = s.patient_id;

여기서 ps는 테이블 별명입니다. 긴 이름을 매번 쓰지 않기 위해 붙입니다. ON 뒤에는 두 테이블을 어떤 열로 연결할지 적습니다.

GROUP BY: 묶어서 세기

질병 그룹별 환자 수를 세고 싶다면 다음처럼 쓸 수 있습니다.

SELECT disease, COUNT(*)
FROM patients
GROUP BY disease;

결과는 대략 이런 식입니다.

cancer   2
normal   1

인덱스가 필요한 이유

작은 표에서는 검색이 금방 끝납니다. 하지만 수백만 행짜리 변이 테이블에서는 특정 위치나 특정 유전자를 찾는 일이 느릴 수 있습니다. 인덱스는 책의 찾아보기처럼 검색을 빠르게 해 줍니다.

인덱스는 성능을 높일 수 있지만, 아무 열에나 무조건 많이 만드는 것이 정답은 아닙니다. 인덱스도 저장 공간과 관리 비용이 들기 때문입니다.

생물학 데이터베이스

생물정보학에서는 이미 만들어진 생물학 데이터베이스를 자주 씁니다. 예를 들어 유전자 정보, 단백질 정보, 변이 정보, 논문 정보가 데이터베이스로 제공됩니다. NCBI, Ensembl, UniProt 같은 이름을 자주 보게 됩니다.

이런 데이터베이스를 잘 쓰려면 “내가 찾는 것이 유전자인가, 전사체인가, 단백질인가, 변이인가?”를 먼저 분명히 해야 합니다.

실전 보강: patient_id와 sample_id를 헷갈리면 생기는 문제

생물정보학 데이터에서는 환자 한 명에게 샘플이 여러 개 있을 수 있습니다.

patients
patient_id   disease
P001         cancer
P002         normal

samples
sample_id   patient_id   tissue
S001        P001         tumor
S002        P001         normal
S003        P002         blood

여기서 patient_id는 사람을 구분하고, sample_id는 실제 측정된 샘플을 구분합니다. 환자 단위 분석인지 샘플 단위 분석인지 헷갈리면 같은 환자를 여러 번 세거나, tumor/normal paired 분석을 잘못할 수 있습니다.

실전 보강: JOIN은 붙이기가 아니라 매칭입니다

JOIN은 두 표를 그냥 옆으로 붙이는 작업이 아닙니다. 공통 key가 맞는 행끼리 매칭합니다.

SELECT samples.sample_id, patients.disease
FROM samples
JOIN patients
ON samples.patient_id = patients.patient_id;

이 쿼리는 sample마다 해당 환자의 disease 정보를 붙입니다. 만약 key가 중복되거나 잘못되면 행 수가 예상보다 늘어날 수 있습니다. 이것은 생물정보학에서 아주 흔한 오류입니다.

숫자 감각: JOIN 결과 행 수 확인하기

SQL에서도 작은 계산 감각이 필요합니다. 예를 들어 환자 2명과 샘플 3개가 있을 때, 샘플 테이블을 기준으로 환자 정보를 JOIN하면 보통 결과는 샘플 수인 3행이 됩니다.

patients: P001, P002 → 2행
samples:  S001(P001), S002(P001), S003(P002) → 3행
JOIN 결과: 샘플마다 환자 정보를 붙이므로 3행

그런데 같은 patient_id가 양쪽 테이블에 중복되어 many-to-many로 매칭되면 행 수가 예상보다 커질 수 있습니다. 생물정보학에서는 이런 중복 JOIN 때문에 샘플 수, 변이 수, 발현값 집계가 부풀려지는 일이 흔합니다.

초보자가 자주 하는 오해

  • 오해 1: ID 이름이 비슷하면 같은 뜻이다. patient_id, sample_id, run_id는 서로 다른 수준의 ID입니다.
  • 오해 2: JOIN하면 항상 행 수가 유지된다. one-to-many 관계에서는 행 수가 늘 수 있습니다.
  • 오해 3: NULL은 0과 같다. NULL은 값이 없거나 모른다는 뜻입니다.
  • 오해 4: 인덱스는 무조건 좋다. 검색은 빨라질 수 있지만 저장공간과 업데이트 비용이 듭니다.

이전 개념과 다음 개념의 연결

SQL은 E13 count matrix, E14 변이 주석, E15 single-cell metadata를 정리하는 데 쓰입니다. API로 받은 데이터(E18)도 결국 테이블 구조로 정리해야 분석하기 쉽습니다.

미니 실습 블록: SQL로 sample metadata와 결과 연결하기

이 실습은 SQL로 sample metadata와 결과 연결하기를 직접 손으로 확인하는 연습입니다. 왜 필요한가 하면, 분석 결과표와 샘플 정보를 안전하게 연결하려면 어떤 키로 JOIN하는지 이해해야 하기 때문입니다.

SELECT c.sample_id, m.condition, c.gene_id, c.count
FROM counts AS c
JOIN metadata AS m
  ON c.sample_id = m.sample_id
WHERE m.condition = 'treated';

각 코드 요소의 의미를 풀어보면 다음과 같습니다. JOIN ... ON은 두 테이블의 공통 키를 기준으로 행을 연결합니다. 여기서는 sample_id가 count와 metadata를 연결하는 열쇠입니다.

생물정보학/계산생물학에서 쓰이는 장면은 분명합니다. 여러 실험 결과를 데이터베이스에 저장하고 조건별로 필요한 행만 조회할 때 쓰입니다.

흔한 오해 또는 주의점도 있습니다. sample_id가 중복되거나 누락되면 JOIN 결과가 예상보다 많아지거나 줄어들 수 있습니다.

핵심 정리

데이터베이스는 큰 표들을 체계적으로 저장하는 시스템이고, SQL은 그 표에 질문을 던지는 언어입니다. SELECT, FROM, WHERE, JOIN, GROUP BY를 이해하면 생물정보학 데이터의 상당 부분을 조회하고 연결할 수 있습니다.

문제 풀이

데이터베이스와 SQL

0 / 42
Gemini AI 채점

주관식 답안은 Gemini API로 채점합니다. API 키는 이 브라우저에만 저장됩니다.

API KEY 미등록
  1. 1. [객관식] 객관식

    데이터베이스의 설명으로 적절한 것은?

    선택지
  2. 2. [객관식] 객관식

    테이블(table)에 대한 설명으로 적절한 것은?

    선택지
  3. 3. [객관식] 객관식

    행(row)에 해당하기 쉬운 것은?

    선택지
  4. 4. [객관식] 객관식

    열(column)에 해당하기 쉬운 것은?

    선택지
  5. 5. [객관식] 객관식

    기본키(primary key)의 역할로 적절한 것은?

    선택지
  6. 6. [객관식] 객관식

    외래키(foreign key)의 설명으로 적절한 것은?

    선택지
  7. 7. [객관식] 객관식

    SQL의 역할로 적절한 것은?

    선택지
  8. 8. [객관식] 객관식

    SELECT patient_id, age FROM patients;의 의미로 적절한 것은?

    선택지
  9. 9. [객관식] 객관식

    WHERE disease = 'cancer'의 역할은?

    선택지
  10. 10. [객관식] 객관식

    JOIN의 설명으로 적절한 것은?

    선택지
  11. 11. [객관식] 객관식

    환자 테이블과 샘플 테이블을 연결할 때 적절한 공통 열 예시는?

    선택지
  12. 12. [객관식] 객관식

    GROUP BY disease의 역할로 적절한 것은?

    선택지
  13. 13. [객관식] 객관식

    COUNT(*)의 역할에 가까운 것은?

    선택지
  14. 14. [객관식] 객관식

    인덱스(index)가 유용한 이유는?

    선택지
  15. 15. [객관식] 객관식

    인덱스를 아무 열에나 무조건 많이 만들면 안 되는 이유는?

    선택지
  16. 16. [객관식] 객관식

    생물학 데이터베이스 예로 적절한 것은?

    선택지
  17. 17. [객관식] 객관식

    SELECT * FROM patients;에서 *의 뜻은?

    선택지
  18. 18. [객관식] 객관식

    SQL에서 테이블 별명을 쓰는 이유로 적절한 것은?

    선택지
  19. 19. [객관식] 객관식

    환자 정보와 유전자 발현 정보를 연결할 때 먼저 분명히 해야 할 것은?

    선택지
  20. 20. [객관식] 객관식

    데이터베이스를 사용하는 장점으로 적절한 것은?

    선택지
  21. 21. [객관식] 객관식

    환자 P001에게 샘플 S001, S002 두 개가 있다. 환자 테이블 1행과 샘플 테이블 2행을 patient_id로 JOIN하면 P001 관련 결과 행은?

    선택지
  22. 22. [객관식] 객관식

    patient_idsample_id를 구분해야 하는 가장 중요한 이유는?

    선택지
  23. 23. [객관식] 객관식

    다음 SQL의 의미는?

    선택지
  24. 24. [객관식] 객관식

    NULL의 올바른 의미는?

    선택지
  25. 25. [객관식] 객관식

    JOIN 결과 행 수가 예상보다 크게 늘어난 경우 가장 먼저 의심할 만한 것은?

    선택지
  26. 26. [객관식] 객관식

    유전자 발현 테이블에서 특정 gene_name 검색이 매우 잦을 때 인덱스가 도움되는 이유는?

    선택지
  27. 27. [객관식] 객관식

    기본키(primary key)의 조건으로 가장 적절한 것은?

    선택지
  28. 28. [객관식] 객관식

    외래키(foreign key)의 역할로 적절한 것은?

    선택지
  29. 29. [객관식] 객관식

    샘플 metadata와 count matrix를 연결할 때 가장 안전한 기준은?

    선택지
  30. 30. [객관식] 객관식

    SQL에서 WHERE tissue = "tumor"의 의미는?

    선택지
  31. 31. [실전] 객관식

    위 SQL에서 ON c.sample_id = m.sample_id의 역할은?

    선택지
  32. 32. [실전] 객관식

    JOIN 결과 행 수가 예상보다 갑자기 늘어났다면 의심할 점은?

    선택지
  33. 주관식 33. [응용] 주관식 · Gemini 채점

    테이블, 행, 열을 환자 데이터 예시로 설명하라.

  34. 주관식 34. [응용] 주관식 · Gemini 채점

    기본키와 외래키의 차이를 설명하라.

  35. 주관식 35. [응용] 주관식 · Gemini 채점

    WHERE와 JOIN의 차이를 설명하라.

  36. 주관식 36. [응용] 주관식 · Gemini 채점

    환자 테이블과 샘플 테이블을 patient_id로 연결하는 이유를 설명하라.

  37. 주관식 37. [응용] 주관식 · Gemini 채점

    인덱스가 큰 변이 테이블에서 유용한 이유를 설명하라.

  38. 주관식 38. [응용] 주관식 · Gemini 채점

    SQL을 생물정보학자가 알아야 하는 이유를 설명하라.

  39. 주관식 39. [응용] 주관식 · Gemini 채점

    환자 한 명에게 tumor/normal 두 샘플이 있을 때 patient_id와 sample_id를 구분해야 하는 이유를 설명하라.

  40. 주관식 40. [응용] 주관식 · Gemini 채점

    JOIN 결과 행 수가 예상보다 늘어났을 때 확인해야 할 항목을 설명하라.

  41. 주관식 41. [실습] 주관식 · Gemini 채점

    metadata에서 condition이 treated인 샘플만 고르는 SQL을 작성하라.

  42. 주관식 42. [실습] 주관식 · Gemini 채점

    sample_id가 SQL JOIN에서 중요한 이유를 설명하라.