무엇인가
XTDB는 JUXT가 만든 불변·이중 시간 SQL 데이터베이스입니다. 테이블을 만들 때 아무것도 선언하지 않아도 모든 행이 _valid_from·_valid_to(세상의 시간)와 _system_from·_system_to(기록의 시간) 네 열을 갖습니다. 덮어쓰거나 지우는 대신 이전 버전을 닫아 두므로, 스냅숏이나 백업 없이 "그때 무엇이 참이었나"와 "그때 시스템은 무엇을 알았나"를 언제든 물을 수 있습니다.
PostgreSQL 통신 규약으로 접속하므로 psql과 기존 Postgres 드라이버를 그대로 씁니다. README는 SQL:2011이 정한 이중 시간 기능을 구현한 SQL 방언과 자체 질의어 XTQL을 함께 지원한다고 적습니다. 2.0 정식판은 2025년 6월 12일에 나왔고, 2026년 10월 21일 v2.2.0이 나왔습니다.
어떻게 동작하나
SELECT는 "지금 아는 바로, 지금 유효한 행"만 돌려준다. 지난 기간까지 보려면 FOR VALID_TIME ALL을 붙인다.FOR VALID_TIME AS OF를 제공해 FOR SYSTEM_TIME AS OF와 나란히 쓴다. 두 시점을 한 질의에서 모두 못 박는다.ERASE를 쓴다.엔진은 Apache Arrow 기반 열 지향이고 객체 저장소를 염두에 두고 설계됐으며, 분산 구성에서는 로그를 조정의 중심에 둡니다(README의 'inside-out' 구조).
빠른 시작
공식 도커 설치 문서의 명령으로 띄우고 psql -h localhost -U xtdb xtdb로 붙습니다. 아래는 코어닷투데이가 2.1.0에서 돌린 급여 소급 시나리오입니다.
BEGIN READ WRITE WITH (SYSTEM_TIME = TIMESTAMP '2026-01-01 09:00:00Z');
INSERT INTO salaries (_id, emp, monthly, _valid_from) VALUES (1, '김지훈', 3000000, DATE '2026-01-01');
COMMIT;
BEGIN READ WRITE WITH (SYSTEM_TIME = TIMESTAMP '2026-03-15 09:00:00Z');
UPDATE salaries FOR PORTION OF VALID_TIME FROM DATE '2026-02-15' TO NULL
SET monthly = 3500000 WHERE _id = 1;
COMMIT;
-- 급여일의 시스템이 알던 2월 20일 월급: 두 시간축을 모두 고정 → 3000000
SELECT monthly FROM salaries
FOR SYSTEM_TIME AS OF TIMESTAMP '2026-02-28 18:00:00Z'
FOR VALID_TIME AS OF DATE '2026-02-20';
-- 지금 아는 바로 2월 20일 월급 → 3500000
SELECT monthly FROM salaries FOR VALID_TIME AS OF DATE '2026-02-20';
코어닷투데이 실측
2026년 10월 11일 ghcr.io/xtdb/xtdb:2.1.0을 PostgreSQL 18·MariaDB 11.8과 나란히 띄워 같은 시나리오를 넣었습니다.
| 항목 | PostgreSQL 18 (트리거) | MariaDB 11.8 | XTDB 2.1 |
|---|---|---|---|
| 요금제 네 질문의 답 | 같음 | 같음 | 같음 |
| 과거 시각으로 기록 시도 | — | 기본 설정에서 받아들이고 이력 한 줄이 사라짐 | 거부 (invalid-system-time) |
| 적재 (고객 2천 명 · 사건 2만 6천 건) | 44.2초 | 38.9초 | 74.8초 |
| 적재 (고객 1만 명 · 사건 13만 건) | 278.7초 | 249.7초 | 848.2초 |
| 한 고객 · 두 시점 고정 (1만 명) | 0.91ms | 0.78ms | 7.20ms |
| 전체 집계 · 두 시점 고정 (1만 명) | 15.5ms | 38.5ms | 21.5ms |
| 저장 크기 (1만 명) | 30.1MB | 30.6MB | 52MB (데이터 디렉터리) |
이미 7월 3일까지 기록한 상태에서 2월 1일 시각의 트랜잭션을 넣자 XTDB는 specified system-time older than current tx로 거부했습니다. 실습 중 이 때문에 컨테이너를 두 번 새로 띄워야 했는데(2026년을 넣은 뒤에는 2025년 이력을 넣을 수 없었습니다), 바로 그 귀찮음이 감사 기록의 보증입니다. 고객이 다섯 배가 되자 적재 시간은 열한 배가 됐습니다.
언제 쓰고, 언제 피하나
- 잘 맞는다: 감사·규정 준수로 "그때 시스템이 무엇을 알았나"를 재현해야 하는 업무, 소급 정정이 잦은 계약·요금·급여 데이터, 시간 설계를 따로 하기 싫은 새 애플리케이션. 모든 테이블이 이중 시간이라 설계할 것이 없습니다.
- 다른 방법을 먼저 본다: 이미 PostgreSQL·MariaDB 위에 있고 한두 테이블만 시간 기능이 필요하다면 그 DB의 기능(MariaDB의 시스템 버전·
FOR PORTION OF, PostgreSQL 18의WITHOUT OVERLAPS)이 가깝습니다. 대량 이관이 필요하면 묶음 적재 방식을 먼저 확인합니다.
한계와 주의
- 표준과 다른 기본 동작을 팀에 알린다. 조건 없는
UPDATE/DELETE는 '지금부터'에만 적용되고, 기본SELECT는 지난 기간을 숨깁니다. 처음 쓰면 "1~2월 행은 어디 갔지?" 하게 됩니다. - 과거 데이터 이관은 기록 시각 순서대로. 기록 시각이 DB 전체에서 앞으로만 흐르기 때문입니다.
- 적재 수치는 가장 단순한 방식이다. 사건 하나당 SQL 한 번, 세 DB가 한 가상 머신에서 자원을 나눠 쓴 상태였습니다. 묶음 적재는 따로 재지 않았습니다.
- 실측은 2.1.0 기준입니다. 이후 나온 2.1.1·2.2.0은 재지 않았습니다.
- 라이선스는 MPL-2.0입니다. 파일 단위 약한 카피레프트이니 XTDB 소스를 고쳐 배포한다면 조건을 확인합니다.


