데이터 서브언어
고친 사람 github-actions[bot]
데이터 서브언어는 데이터베이스에 데이터를 묻고 바꾸는 일만 맡는 언어입니다. 프로그램의 나머지 일은 다른 언어가 합니다. 둘이 일을 나눠 맡기 때문에 이름에 「서브」가 붙었습니다. 백엔드 개발자가 매일 쓰는 Structured Query Language, 곧 SQL이 대표입니다.
쉽고 빠른 이해
데이터 서브언어는 데이터를 다루는 일만 하는 작은 언어입니다. 자바 서버가 「7번 사용자의 이름을 주세요」를 데이터베이스에 보낼 때 쓰는 문장이 그것입니다.
이렇게 나누는 까닭은 데이터 일을 데이터베이스에 넘기려는 데 있습니다. 프로그램은 원하는 결과만 적습니다. 찾는 방법은 데이터베이스가 정합니다. 찾는 길을 코드에 적지 않으니 저장 방식이 바뀌어도 프로그램을 고치지 않아도 됩니다. 자바든 파이썬이든 같은 문장을 보낼 수 있습니다.
어떻게 도나:
- 프로그램은 평소 쓰는 언어로 흐름과 계산을 짭니다
- 데이터가 필요할 때만 데이터 서브언어로 문장을 써서 데이터베이스에 보냅니다
- 데이터베이스가 결과를 돌려주면 프로그램이 받아서 이어 씁니다
무엇이 나빠지나 — 언어가 둘이라 둘이 만나는 곳이 번거롭습니다. 결과는 여러 행으로 옵니다. 프로그램은 변수 하나씩 다룹니다. 문장을 문자열로 이어 붙이다가 사용자 입력이 문장에 섞여 드는 사고도 납니다.
상세
은행 창구에서는 하고 싶은 말을 아무렇게나 하지 않습니다. 정해진 신청서에 계좌와 금액을 적어 냅니다. 신청서로는 은행 일만 할 수 있습니다. 점심을 무엇으로 먹을지는 신청서 밖에서 정합니다.
프로그램에서 이 신청서에 해당하는 것이 데이터 서브언어입니다. 프로그램이 하는 여러 일 가운데 데이터를 다루는 부분만 맡는 언어입니다. 신청서 밖에서 정하던 나머지 일은 다른 언어가 맡습니다. 이름의 서브(sub)는 「일부」라는 뜻입니다.
아래에서는 먼저 나머지 일을 맡는 언어와 일을 어떻게 나누는지 코드로 봅니다. 이어서 왜 따로 떼었는지, 무엇을 할 줄 알아야 하는지, 둘이 만나는 곳에서 무엇이 번거로운지를 차례로 봅니다.
호스트 언어와 나누는 일
나머지 일을 맡는 언어를 호스트 언어라고 부릅니다. 데이터 서브언어 문장을 품어 주는 쪽이라 「주인(host)」이라는 이름이 붙었습니다. 자바·파이썬·고 같은 범용 언어가 이 노릇을 합니다.
범용 언어는 반복과 분기, 화면 출력, 파일 쓰기, 네트워크 요청을 다 할 수 있는 언어입니다. 그래서 프로그램의 흐름은 호스트 언어가 쥡니다. 데이터가 필요한 순간에만 데이터 서브언어 문장 하나가 데이터베이스로 건너갑니다.
flowchart TD
subgraph P["프로그램 · 호스트 언어로 짠다"]
A["입력을 받는다"] --> B["SQL 문장을 만든다"]
C["결과로 화면을 그린다"]
end
B -->|"데이터 서브언어 문장"| DB[("데이터베이스")]
DB -->|"결과 행"| C
그림에서 데이터베이스로 건너가는 것은 SQL 문장 하나뿐입니다. 입력을 받는 일과 화면을 그리는 일은 프로그램 안에 남습니다.
백엔드 코드에서 늘 보는 모습입니다. 아래 두 코드는 7번 사용자의 이름을 읽는 같은 일을 자바와 파이썬으로 합니다. 오른쪽 주석이 그 줄이 내는 값입니다.
String sql =
"SELECT name FROM users WHERE id = ?";
var ps = conn.prepareStatement(sql);
ps.setInt(1, 7);
var rs = ps.executeQuery();
rs.next();
rs.getString("name"); // "김유미"
cur = conn.execute(
"SELECT name FROM users WHERE id = ?", (7,))
cur.fetchone()[0] # '김유미'
두 코드에서 따옴표 안의 SQL 문장은 글자 하나 다르지 않습니다. 연결을 여는 법, 7을 넘기는 법, 결과를 변수에 받는 법은 언어마다 갈립니다. 갈리는 쪽은 호스트 언어의 몫입니다. 같은 쪽은 데이터 서브언어의 몫입니다.
문장 속 물음표는 값이 나중에 채워질 빈칸입니다. 7은 문장에 섞이지 않고 따로 넘어갑니다. 이렇게 따로 넘기는 까닭은 아래 「두 언어가 만나는 곳의 비용」 소절에서 봅니다.
호스트 언어가 문장을 데이터베이스에 보내는 통로는 언어마다 라이브러리가 맡습니다. 자바에서는 JDBC(Java Database Connectivity)가 그 통로입니다.
이렇게 함수를 불러 문장을 보내는 방식 말고, 호스트 언어 소스에 SQL 을 직접 섞어 쓰는 임베디드 SQL도 있습니다. 섞어 쓴 소스는 컴파일 전에 전처리기가 함수 호출로 바꿉니다.
따로 떼어 낸 까닭
데이터 서브언어가 생기기 전에는 프로그램이 데이터를 따라 걸어 다녔습니다. IMS(Information Management System) 같은 계층형 데이터베이스가 그랬습니다. 고객 아래에 그 고객의 주문이 매달리는 식으로 데이터를 나무 모양으로 묶어 두는 데이터베이스입니다.
프로그램은 고객 한 건을 읽습니다. 그 건에 적힌 주문의 위치를 보고 주문 한 건으로 넘어갑니다. 찾는 길이 코드에 박혀 있어서 저장 구조가 바뀌면 코드도 고쳐야 했습니다.
데이터 일을 언어째 떼어 내면 찾는 길을 코드에서 뺄 수 있습니다. 문장에는 「7번 사용자의 이름」이라는 원하는 결과만 적힙니다. 어떻게 찾을지는 적지 않습니다. 무엇을 원하는지만 적는 이런 방식을 선언형이라고 부릅니다.
찾는 방법은 데이터베이스가 문장을 받은 뒤 스스로 고릅니다. 어느 표(테이블)를 먼저 읽을지, 어떤 길로 찾을지를 그때 정합니다. 이 고르는 일을 질의 최적화라고 합니다.
고를 수 있는 길 가운데 하나가 인덱스입니다. 책 뒤의 찾아보기처럼, 빨리 찾으려고 값과 그 값이 있는 위치를 따로 정리해 둔 것입니다. 인덱스가 있으면 표를 처음부터 다 읽지 않아도 됩니다.
찾는 길을 데이터베이스가 고르는 덕에 저장 방식이 바뀌어도 문장은 안 바뀝니다. 데이터베이스가 파일 배치를 바꾸거나 인덱스를 새로 만들어도 같은 문장이 같은 결과를 냅니다. 데이터 독립성은 프로그램과 저장 방식을 이렇게 떼어 놓는 성질입니다.
호스트 언어도 가리지 않게 됩니다. 자바 서버와 파이썬 배치 작업이 같은 데이터베이스에 같은 문장을 보낼 수 있습니다. 사람이 데이터베이스 콘솔에 직접 쳐 보는 문장도 같은 언어입니다.
관계형 모델에서 온 이름
데이터 서브언어라는 말은 관계형 모델을 내놓은 Codd(에드거 F. 커드)가 1970년 논문에서 썼습니다. 관계형 모델은 데이터를 행과 열로 된 표로 다루는 방식입니다. Codd 는 그 표들을 다룰 언어를 호스트 언어와 따로 세우자고 했습니다. SQL 은 이 생각을 이어받아 만든 언어입니다.
Codd 는 뒤에 관계형 데이터베이스가 갖출 조건을 목록으로 정리했습니다. 흔히 「Codd 의 12규칙」이라고 부르는 목록입니다. 그 가운데 다섯째가 「포괄적 데이터 서브언어」 규칙입니다.
이 규칙은 적어도 언어 하나가 정해진 문법을 따르는 문자열로 적혀야 한다고 요구합니다. 글자로 적힌 문장이어야 프로그램이 데이터베이스에 보낼 수도 있고, 사람이 콘솔에 직접 칠 수도 있기 때문입니다. 그리고 그 언어 하나로 아래 소절의 여섯 가지 일을 모두 해내야 합니다.
포괄적 데이터 서브언어가 맡는 일
포괄적이라는 말은 데이터베이스를 다루는 일이 이 언어 하나로 다 된다는 뜻입니다. 아래 표가 그 여섯 가지 일입니다. 오른쪽 칸은 SQL 에서 그 일을 맡는 문장입니다.
| 일 | 무엇을 하나 | SQL 문장 |
|---|---|---|
| 데이터 정의 | 표와 열의 틀을 만든다 | CREATE TABLE |
| 뷰 정의 | 저장된 표를 가공해 보여 주는 가상의 표를 만든다 | CREATE VIEW |
| 데이터 조작 | 행을 찾고, 넣고, 고치고, 지운다 | SELECT · INSERT · UPDATE · DELETE |
| 무결성 제약 | 들어가면 안 되는 값을 막는다 | PRIMARY KEY · FOREIGN KEY · CHECK |
| 권한 | 누가 무엇을 할 수 있는지 정한다 | GRANT · REVOKE |
| 트랜잭션 경계 | 여러 문장을 한 묶음으로 확정하거나 되돌린다 | BEGIN · COMMIT · ROLLBACK |
여섯이 한 언어에 모이면 데이터베이스를 다루는 길이 하나가 됩니다. 표를 바꾸는 일도, 권한을 주는 일도 프로그램에서 문장 하나로 보낼 수 있습니다. 데이터 조작은 프로그램에서 보내도 되고 사람이 콘솔에 쳐도 됩니다. 어느 쪽이든 같은 문장입니다.
이 가운데 데이터 정의를 맡는 문장들을 DDL(Data Definition Language, 데이터 정의 언어)이라고 따로 부르기도 합니다. 데이터 조작을 맡는 문장들은 DML(Data Manipulation Language, 데이터 조작 언어)이라고 부릅니다. 둘 다 데이터 서브언어의 한 부분입니다.
서브언어가 하지 않는 일
데이터 서브언어는 혼자서 프로그램 하나를 다 짜려고 만든 언어가 아닙니다. 사용자에게 화면을 보여 주거나, 다른 서버에 요청을 보내거나, 파일을 쓰는 문장이 없습니다. 이런 일은 호스트 언어가 결과를 받아서 합니다.
경계가 칼같이 잘리지는 않습니다. 오라클의 PL/SQL(Procedural Language/SQL), PostgreSQL 의 PL/pgSQL 처럼 많은 데이터베이스가 반복과 분기를 쓸 수 있는 저장 프로시저 언어를 덧붙여 왔습니다. 그래도 데이터를 묻고 바꾸는 중심 문장은 서브언어의 몫으로 남습니다.
두 언어가 만나는 곳의 비용
언어를 둘로 나눈 대가는 둘이 만나는 곳에서 치릅니다. 백엔드 개발자가 자주 겪는 번거로움이 둘입니다. 하나는 결과의 모양이 다르다는 것입니다. 다른 하나는 문장이 문자열이라는 것입니다.
데이터 서브언어의 결과는 행 여러 개로 된 표입니다. 호스트 언어는 변수 하나, 객체 하나씩 다룹니다. 그래서 결과를 한 행씩 꺼내 객체에 옮겨 담는 코드가 따로 필요합니다. 이 어긋남을 임피던스 불일치라고 부릅니다.
결과 표에서 지금 읽는 행을 가리키는 표시를 커서라고 합니다. 앞의 자바 코드에서 rs.next() 가 커서를 다음 행으로 옮기는 호출입니다. 행이 백 개면 이 호출을 백 번 되풀이합니다. 그때마다 한 행씩 옮겨 담습니다.
이 옮겨 담기를 대신 해 주는 도구가 ORM(Object-Relational Mapping, 객체-관계 매핑)입니다. 자바의 Hibernate, 파이썬의 SQLAlchemy 가 대표입니다. 객체를 저장하라고 부르면 ORM 이 SQL 문장을 만들어 보냅니다. 데이터 서브언어가 없어진 것이 아니라 도구 뒤로 숨은 것입니다.
두 번째 번거로움은 문장이 호스트 언어 안에서 문자열이라는 데서 옵니다. 사용자 입력을 그 문자열에 이어 붙이면 입력이 문장의 일부가 될 수 있습니다. 입력에 ' OR '1'='1 같은 글자가 섞이면 조건이 바뀌어 남의 데이터까지 나옵니다. 이 공격이 SQL 인젝션입니다.
앞 코드의 물음표가 이 사고를 막습니다. 값을 문장과 따로 넘기면 데이터베이스는 그 값을 문장으로 읽지 않고 값으로만 씁니다. 이렇게 값을 따로 넘기는 방식이 파라미터 바인딩입니다.
SQL 밖의 데이터 서브언어
데이터베이스 종류마다 자기 질의 언어가 있습니다. Neo4j 같은 그래프 데이터베이스는 Cypher 를, InfluxDB 같은 시계열 데이터베이스는 InfluxQL 을 씁니다. 이 언어들도 같은 꼴로 씁니다. 호스트 언어 안에서 문장을 만들어 데이터베이스에 보내고 결과를 받습니다. 문법은 달라도 데이터 일만 맡는다는 점은 같습니다.
관련 항목
데이터 서브언어로 쓰이는 질의 언어
SQL · QUEL · QBE · Datalog · 질의
데이터 서브언어를 이루는 문장 갈래
DDL · DML · DCL · TCL
포괄적 데이터 서브언어가 다루는 대상
데이터 서브언어를 품는 호스트 언어와 연결 수단
호스트 언어 · 범용 프로그래밍 언어 · 임베디드 SQL · JDBC · ODBC · 데이터베이스 드라이버 · 저장 프로시저
두 언어가 만나는 곳에서 생기는 문제와 대책
임피던스 불일치 · 커서 · ORM · SQL 인젝션 · 파라미터 바인딩 · 준비된 문장
데이터 서브언어가 비롯된 관계형 이론
Codd · 관계형 모델 · Codd 의 12규칙 · 관계 대수 · 관계 해석 · 관계형 데이터베이스
데이터 서브언어가 지키게 하는 성질
데이터 독립성 · 선언형 프로그래밍 · 질의 최적화 · 실행 계획
데이터 서브언어 문장을 받는 시스템
데이터베이스 · 데이터베이스 관리 시스템 · 관계형 데이터베이스 관리 시스템 · 그래프 데이터베이스 · 시계열 데이터베이스
다른 이름: data sublanguage · Data Sublanguage · 데이터 하위 언어 · 데이터 부분 언어