내가 postgres에서 놓치고 있던 것들
2026. 03. 09.
DB에도 차이점이 있었다.
강의를 듣다 보면 postgres를 활용하는 강의가 많아서 자연스레 postgres를 기본 db로 사용해왔었다. 그리고 db가 강의 주제가 아니다 보니 db를 생성하고 prisma orm을 통해 테이블이나 컬럼을 생성하고 수정하는 정도로 다루고 넘어가는 경우가 많았는데, 이번에 db 강의를 듣다 보니 추구하는 방향이 달라서 설정도 다르다는 것을 느끼게 되어 정리하게 되었다.
트랜잭션 격리 수준 차이
트랜잭션은 4가지 격리 수준으로 나눠져있다.
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
위의 4개의 격리 수준에서 1번인 READ UNCOMMITTED는 아무 것도 막아주지 않는 가장 낮은 수준으로 더티 리드(Dirty Read)도 막아주지 않기 때문에 정합성 이슈가 많아 사용되지 않고, 4번인 SERIALIZABLE은 동시성 문제를 완벽하게 차단하지만, 트랜잭션을 거의 순서대로 실행시켜 병목이 될 가능성이 매우 높아 거의 사용하지 않는다고 한다.
즉 대부분의 DB가 READ COMMITTED이거나 REPEATABLE READ의 격리 수준을 기본값으로 선택한다는 것이다.
대표적으로 mysql의 트랜잭션 격리 수준은 REPEATABLE READ이고, postgres의 트랜잭션 격리 수준은 READ COMMITTED이다.
웹 애플리케이션은 '하나의 요청 = 하나의 짧은 트랜잭션'으로 동작하는 경우가 대부분이고 READ COMMITTED로 격리 수준을 해두면 불필요한 락(Lock)들을 사용하지 않게 되어 기다리는 시간이 줄어들고 전체적인 처리량이 향상될 수 있다. 동시성과 단순한 규칙을 추구하는 postgres의 철학이 이해되는 부분이다.
인덱스 생성 차이
mysql에서는 외래키를 만들면 자동으로 인덱스를 생성한다. 하지만 postgres에서는 외래키에 대해서 자동으로 인덱스를 생성하지 않고 필요하면 직접 생성해야 한다.
인덱스를 생성하면 쓰기 성능이 감소 & 인덱스 만큼 디스크 사용이 증가 되고 모든 외래키 컬럼이 조회 조건으로 사용되는 것도 아니기 때문에 기본적으로 생성하지는 않고 단순하게 만들고 개발자가 필요하다고 생각되는 순간에 생성한다는 postgres의 철학이 느껴지는 부분이다.
하지만 현대 개발에서 외래키에 대해서 인덱스를 생성한 만큼의 디스크 사용은 크게 문제가 되지 않고, full table scan이 일어나지 않도록 하는 이점이 훨씬 많기 때문에 postgres를 사용할 때는 잊지 말고 외래키에 대해 인덱스를 생성해야 한다.