스크립트
00:00:00모든 것에 Postgres를 쓰라고 하던 개발자들의 말이 훨씬 더 옳았다는 사실이 드러났습니다.
00:00:04그래프 쿼리에 대한 네이티브 지원을 포함하는 다가오는 Postgres 19 버전과 함께 말이죠.
00:00:10정말 멋진 기능인데요. 그래서 오늘 영상에서는 Postgres 19의 주요 기능들을 살펴보고
00:00:16특히 그래프 쿼리를 더 자세히 알아보려고 합니다. 왜냐하면 이것이 우리가 쿼리를 설계하고
00:00:21Postgres를 사용하는 방식을 근본적으로 바꿀 수 있다고 생각하기 때문입니다.
00:00:30자, 첫 번째 기능은 on conflict do select라는 기능입니다. 행이 존재하지 않을 때만 삽입하고 싶고
00:00:35어느 쪽이든 그 행을 결과로 반환받고 싶을 때, 보통은 두 개의 쿼리가 필요했습니다.
00:00:40즉 삽입(insert)과 조회(select)인데 이는 아주 흔한 워크플로입니다. 그래서 예시를 보면
00:00:45users 테이블의 email과 name에 값을 삽입한다고 말하고 해당 값을 전달한 다음
00:00:50마지막에 on conflict for email do nothing returning star를 적습니다. do nothing은 행이 이미 존재할 때
00:00:56아무것도 반환하지 않으므로 select를 뒤에 붙이게 되지만, 이 둘은 원자적(atomic)이지 않습니다. 19 버전에서는
00:01:03단 하나의 쿼리로 이를 수행할 수 있습니다. users에 email과 name을 넣고 on conflict email do select
00:01:11returning star라고 적으면 됩니다. 그리고 동일한 쿼리에서 수정하고 싶다면 insert into users를 하고
00:01:16다시 값을 넣은 뒤 on conflict for email do select for update returning id and name을 쓸 수 있습니다. 단일 구문이므로
00:01:23원자적으로 작동하여 매번 삽입하거나 조회하게 되며, 이는 매우 흔한 유스케이스로서
00:01:29정말 유용할 것입니다. 다음은 그래프입니다만, 이 내용이 흥미로우셨다면
00:01:34betterstack을 구독하고 최신 기술 동향을 확인해 보세요. 앞서 말씀드린 것처럼
00:01:39이것이 제 생각에는 가장 핵심적인 기능입니다. 쇼핑몰을 위한 일반적인 스키마가 있다고 가정해 봅시다.
00:01:44고객, 주문, 상품이 있고 이들을 연결하는 두 개의 조인 테이블이 있는데, 특정 고객이
00:01:50실제로 어떤 상품을 구매했는지 알고 싶다고 해봅시다. SQL에서는 5개 테이블 전부를 가로지르는 조인 체인이 되는데
00:01:56여기서는 그럭저럭 관리할만 하지만 더 복잡한 관계에서는 금방 지저분해집니다. 그런데 이제는
00:02:02이 모든 것을 그래프로 쿼리할 수 있어서, 복잡한 조인 구문 대신 새로운 그래프 구문을 사용할 수 있습니다. 그리고
00:02:08특히 복잡한 조인에서 엄청난 이점을 보게 될 것입니다. 자, 데이터베이스 뷰어 안에 들어와 있습니다.
00:02:14상품, 주문, 이벤트 같은 모든 테이블이 있고 고객도 있으며
00:02:20이 모든 데이터를 연결하는 피벗 테이블도 있습니다. 주문 항목과 고객 주문 테이블이 있는데
00:02:25이제 이 모든 테이블을 대상으로 쿼리를 실행해 보겠습니다. 예를 들어서
00:02:30앨리스라는 유저가 있다고 하고, 앨리스가 주문한 모든 것을 알아내고 싶다고 해봅시다. 이를 위해서는
00:02:35그 모든 테이블을 연결하기 위해 여러 개의 서로 다른 조인 쿼리를 거쳐야 합니다. 그래서 4개의 개별 조인 문이
00:02:41포함된 이 쿼리를 실행하게 되는데, 작성하기에 엄청나게 어렵지는 않지만
00:02:46매우 지저분합니다. 하지만 이를 실행해보면 앨리스가 주문한 모든 것, 즉 기계식 키보드와 인체공학적 마우스를
00:02:51볼 수 있습니다. 하지만 이제 그래프 구문을 사용하면 이를 대폭 단순화할 수 있습니다.
00:02:57이 모든 것을 새로운 그래프 구문으로 교체하고 다시 실행하면
00:03:03동일한 결과가 나오는 것을 볼 수 있으며, 이 구조를 나열해 보면 가독성이 훨씬 좋아집니다.
00:03:07고객에서 고객 주문으로, 주문으로, 주문 항목으로, 상품으로 이어지는 것을 볼 수 있습니다. 따라서
00:03:13이 단순한 흐름을 따라가기만 하면 전체 그래프를 통과할 수 있으며, 제 생각에는 훨씬 더 읽기 쉽습니다.
00:03:19여러 열을 선택하고 싶을 때도 그렇게 할 수 있습니다. 상단에는 동일한
00:03:23그래프 쿼리가 있고, 하단에 열을 정의한 다음 표시하고 싶은 모든 열을 선택하면
00:03:27실행 결과가 하단에 나타납니다. 물론 애초에 그래프를 생성하지 않았다면 이 중 아무것도 작동하지 않으므로
00:03:32그 그래프를 생성하기 위해 사용한 쿼리는 여기에 있습니다. create property graph라고 말하고
00:03:37이름을 my shop으로 지정한 다음, 정점(vertex) 테이블을 개괄합니다. 고객, 주문, 상품이 될 것이며
00:03:42이것들이 실제로 데이터를 담고 있는 것들입니다. 그리고 간선(edge) 테이블이 있는데
00:03:47이는 실제로 연결을 만들어주는 것들, 즉 우리의 경우 피벗 테이블인
00:03:52고객 주문과 주문 항목이 됩니다. 이에 대한 구문은 매우 간단해서, 고객 주문의 소스는 고객이고
00:03:57목적지는 주문이며, 주문 항목의 소스는 주문이고 목적지는 상품이라고 말합니다.
00:04:02이것이 설정되면, 포스트그레스는 그래프 쿼리를 실행할 때마다 해당 관계가 어떻게 정의되었는지 인식하게 됩니다.
00:04:08이것이 작동하려면 그래프를 생성해야 하지만, 그렇다고 새로운 테이블 등을 만드는 것은 아닙니다.
00:04:14이미 가지고 있는 5개의 테이블을 가리키기만 하면 됩니다. 데이터를 실제로 담고 있는 3개는 정점이 되고
00:04:192개의 조인 테이블은 간선이 됩니다. 뷰와 매우 유사하게 작동하므로 이전 스키마는
00:04:23완전히 변경되지 않은 채 유지되고 그 위에 이 추가 기능이 얹어지는 것입니다. 따라서 여기서는
00:04:29create property graph를 선언하고 my shop이라고 부른 다음
00:04:35그 관계가 실제로 어떻게 작동하는지 기술하기 시작합니다. 바로 여기서 그래프를 위한 모든 작업을 수행하며
00:04:40이는 각 조인 구문에 비해 쿼리를 훨씬 더 가볍게 만들어 줄 수 있음을 의미합니다. 그렇다면 이것이 neo4j 대체재일까요?
00:04:45그래프 스토리지와 트래버설 성능 때문에 그래프 데이터베이스가 필요하다면, 아닙니다. 전용 그래프 데이터베이스가
00:04:52여전히 더 나은 선택일 것입니다. 하지만 SQL에서 10개의 테이블 조인을 작성하는 것이 고통스럽고 지저분해서
00:04:58이 기능을 원하신다면 확실히 큰 도움이 될 것이며
00:05:03비교했을 때 훨씬 더 만족스러울 것입니다. 세 번째 신기능은 repack인데
00:05:09디스크 공간을 다시 확보하는 것에 관한 기능입니다. 포스트그레스토어는
00:05:15절대로 행을 제자리에서(in-place) 업데이트하지 않고 새 버전을 쓴 뒤 이전 버전을 남겨두며, vacuum은
00:05:21그 죽은 공간을 재사용 가능하다고 표시만 하기 때문에 디스크 사용량이 실제로 줄어들지는 않습니다. repack은 낭비되는 공간 없이
00:05:27전체 테이블을 새로운 파일로 다시 작성하며, 그것이 바로 운영체제에 공간을 다시 돌려주는 방식입니다.
00:05:33실제로 vacuum full을 통해 이미 이 작업을 수행할 수 있었지만, 이는 전체 재작성 동안 테이블을 잠그므로
00:05:38대용량 데이터에는 절대 실행할 수 없었습니다. 이것이 바로 사람들이 pg_repack 같은 확장 프로그램을
00:05:42설치했던 이유입니다. 하지만 이제는 포스트그레스에 직접 내장되어 제공됩니다. 여기에 concurrently 키워드를 사용하면
00:05:49repack이 작동하는 동안에도 테이블을 읽고 쓸 수 있게 유지해 줍니다. 다만 한 가지 주의할 점은
00:05:54테이블의 두 번째 복사본과 그 모든 인덱스를 위한 충분한 여유 디스크 공간이 필요하다는 것입니다. 따라서 공간을 더 확보하려면
00:06:00여유 공간이 필요하므로, 이것이 pg_repack을 완벽히 대체하는 것은 아니지만 일반 테이블의 경우
00:06:06확장 프로그램 없이도 역할을 해냅니다. 자, 이제 19 버전의 남은 기능들에 대해 빠르게 짚어보겠습니다.
00:06:11첫 번째는 쿼리 힌트입니다. 포스트그레스는 쿼리를 실제로 어떻게 실행할지 스스로 결정하며
00:06:17시간이 지나면서 마음이 바뀔 수 있습니다. 따라서 1년 동안 잘 작동하던 쿼리가 갑자기 느려지고
00:06:22코드에는 아무것도 변경되지 않았을 때, pg_plan_advice라는 새 모듈을 사용하면 쿼리가 여전히 빠를 때의 플랜을 캡처하여
00:06:28고정함으로써 항상 그 상태를 유지할 수 있게 해줍니다. JIT는 이제 기본적으로 꺼집니다. 포스트그레스는 무거운 쿼리를
00:06:36머신 코드로 컴파일하지만, 플래너의 비용 견적을 바탕으로 언제 신경 쓸지 결정해 왔습니다. 릴리스 노트에 따르면
00:06:41그 비용 산정이 사실 신뢰할 수 없었기 때문에, 실제로 필요하지 않은 쿼리에서도 작동하고 있었다고 합니다.
00:06:46또한 이제 vacuum이 여러 워커를 통해 병렬로 인덱스를 정리할 수 있으므로 큰 테이블을 vacuum하는 데 소요되는 시간이 줄어듭니다.
00:06:52다만 이 기능은 직접 켜야 합니다. 열을 추가하여 select를 수행한 다음
00:06:58group by에도 동일한 열을 추가해야 할 때가 오면, 이 기능이 그 모든 것을 알아서 처리해 줍니다.
00:07:03그리고 copy 키워드로 이제 JSON으로 바로 내보낼 수 있게 되었습니다. 그동안 CSV로 덤프한 뒤
00:07:09나중에 변환해 왔다면 이제 그럴 필요가 없습니다. Postgres 19 베타 2가 7월에 출시되었고
00:07:15정식 릴리스는 9월에서 10월 사이로 예상되므로, 이전 버전을 사용 중이시다면 지금 베타 버전을 다운로드하여
00:07:21테스트해 볼 가치가 있습니다. 그리고 Postgres에 대해 더 자세히 알고 싶다면
00:07:25내구성 있는 워크플로를 Postgres 내부에 직접 구축해 주는 pg_durable 분석 내용을 확인해 보세요. 저는 betterstack의 워렌이었고
00:07:31시청해주셔서 감사하며 다음 영상에서 뵙겠습니다.