SQL vs. NoSQL

subbnisubbni
4 min read

SQL (관계형 DB)

RDBMS의 핵심적인 두 가지 특징

  1. 데이터가 정해진 데이터 스키마에 따라 테이블에 저장된다.

    • 즉, 스키마를 준수하지 않은 레코드는 해당 테이블에 저장될 수 없다.
  2. 데이터는 관계를 통해 여러 테이블에 분산되어 저장된다.

    • 이를 통해 데이터의 중복을 피할 수 있어, 데이터 수정이 발생했을 때 다른 테이블에는 수정이 반영되지 않는 등의 데이터 불일치 위험을 줄일 수 있다.

NoSQL (비관계형 DB)

SQL과 반대로 스키마가 유연하거나 없고, 테이블 간 관계도 없다.

SQL의 레코드(Record) 개념 대신 문서(Document)라는 개념을, 테이블 대신 컬렉션을 사용한다.

문서는 JSON과 비슷한 형태로, 여러 테이블에 조인할 필요없이 필요한 데이터를 한 문서에 담아 컬렉션에 저장하는 것이 NoSQL의 설계 방식이다.

실제로 대부분의 NoSQL에서는 JOIN 연산을 지원하지 않는다.

  • NoSQL에서 JOIN 의 필요성이 있다면?

    1. 데이터 중복 저장

      • 조인 대신 데이터를 중복 저장하여 필요성을 없애는 것이 가장 흔한 접근이다.

      • 장점 : 조회가 빠르고 조인 부하가 없다.

      • 단점 : 데이터 업데이트 시 데이터 일관성 문제가 발생할 수 있다.

        • 당장 생각만 해도 만일 댓글 데이터와 사용자 프로필 데이터가 있다면, 만일 댓글에 해당 사용자의 프로필 정보가 함께 저장된다면? 사용자가 닉네임을 변경하면 해당 사용자가 작성한 댓글 데이터 전체에서 닉네임을 수정해주어야 한다. 이처럼 자주 변경되는 데이터는 다른 방법을 찾아야 한다.
    2. Application 계층에서의 JOIN

      • DB에서 각각의 데이터를 가져온 후, 코드 레벨에서 합치는 방식을 사용한다.

        • NoSQL이 JOIN을 안 해주니까 직접 코딩으로 JOIN 연산을 해주는거다.

        • 예를 들어서, 댓글 데이터에는 사용자 id만을 저장해두고, 해당 사용자 id를 가진 사용자 프로필 데이터를 찾는 쿼리를 작성하여 두 데이터를 어플리케이션 단에서 합치는 방식이다.

      • 장점 : 이렇게 구현하면 모든 NoSQL에서 조인 방식을 사용 가능하다.

      • 단점 : 쿼리를 여러 번 날려야 하므로 네트워크 및 I/O 비용이 늘어나며, 개발 복잡도가 다소 늘어난다.

    3. Aggregation Framework 사용 (일부)

      • 일부 지원되는 NoSQL에서는 JOIN과 비슷한 기능을 제공한다고 한다.

        • 예를 들어, MongoDB는 $lookup 연산으로 RDB의 LEFT OUTER JOIN과 매우 유사한 기능을 제공한다.
      • 장점 : SQL처럼 조인이 가능하고, DB 차원에서 처리하므로 Application Layer JOIN보다 속도가 빠르다.

      • 단점 : 조인 대상이 많거나 데이터가 크면 아무래도 Read 연산 시 성능이 저하된다.


Scaling, 수직적 확장과 수평적 확장

데이터베이스 서버의 확장은 수직적 확장과 수평적 확장으로 나뉜다.

  • 수직적 확장 (scale up) : 기존 서버의 성능을 높이는 방법으로, 서버 한 대의 CPU, RAM, 디스크 용량 등을 더 크게 늘리는 것

  • 수평적 확장 (scale out) : 서버를 추가로 설치하여 여러 대의 서버로 분산 처리하는 것

RDB의 한계, 수평적 확장의 어려움

RDB의 경우 수평적 확장이 어렵다는 한계를 가진다.

왜?

  1. JOIN의 존재

    • RDB의 설계 철학은 데이터를 잘게 나눠 저장한 뒤(정규화), 필요할 때 조인하여 사용하는 것이다.

    • 테이블이 다른 서버로 나뉘게 된다면?

      • 서버 간 데이터 이동이 발생해야 한다.

      • 이에 따라 네트워크 비용과 지연이 발생하고

      • 결론적으로 속도가 매우 느려질 수 있다.

  2. 샤딩(Sharding)의 어려움

    • RDB에서 샤딩을 하려면 모든 쿼리를 다시 설계하여야 한다.

      • count 쿼리가 있다면 두 서버에서 따로 카운트하여 합산 하는 로직을 작성하여야 하고,

      • 다른 서버로 나뉘게 된 두 테이블의 join 쿼리가 있었다면? 더 큰 문제 발생 . . .

하지만 수직적 확장에는 한계가 있다 .. 방대한 데이터 양에 따라 수평적 확장이 필수적이다.

그래서 NoSQL이 등장했다.

  1. JOIN 의존 최소화

    • 애초에 NoSQL의 설계 철학은 JOIN에 의존하지 않고, 필요한 데이터를 한 문서에 저장하는 것

    • 서버 간 데이터 이동이 필요 없고, 문서 하나만 가져오면 처리가 끝나므로 수평 분산과 궁합이 좋다.

  2. 샤딩이 용이

    • NoSQL은 처음부터 샤딩을 고려해 설계하여 데이터를 서버 여러 대에 나누어 저장하고 처리하기가 상대적으로 쉽다.
  3. 읽기/쓰기 성능이 좋다

    • 왜?

      1. JOIN 없이 한 번의 쿼리로 끝 → 읽기 속도 향상

      2. 타입 검사 X

        • 스키마 체크, 타입 체크, FK/PK 제약 조건 등을 확인하는 과정이 없음 → 쓰기 속도 향상
      3. Key-Value 조회

        • 많은 NoSQL에서 Key → Value 매핑으로 데이터를 저장한다.

        • 단일 Key로 B-Tree 탐색 혹은 해시 탐색으로 매우 빠르게 데이터를 찾을 수 있다.


어떨 때 SQL을 써야할까?

  • 데이터 일관성이 매우 중요한 경우

    • 돈, 재고 수량처럼 한 치의 오차도 허용되지 않는 경우

    • RDB에 정규화하여 저장함으로써 일관성을 유지한다.

    • 강력한 트랜잭션 제약을 통해 데이터 정합성을 유지한다.

  • 복잡한 JOIN이 필요한 경우

  • 데이터 구조가 자주 변하지 않는 경우

    • 데이터 모델이 고정되어 있는 것이 사용자와 데이터에 중요한 경우

어떨 때 NoSQL을 써야할까?

  • 정확한 데이터 구조를 확정할 수 없거나 유연성이 필요한 경우

    • 필드 추가나 변경이 자유로운 NoSQL을 사용하면 좋다.
  • 고속 읽기/쓰기 성능이 중요한 경우

  • 막대한 양의 데이터가 예상되어 Scale-Out이 필요할 경우


마무리하며

SQL(RDB)와 NoSQL은 각기 다른 철학과 설계 원리를 가지고 있으며, 상황에 따라 장단점이 뚜렷하다.

“어떤 기술이 더 좋다”가 아니라, 다루려는 데이터와 시스템의 요구사항에 어떤 기술이 적합한가를 올바르게 판단하는 것이 중요한 것 같다.

그리고 서비스가 복잡하고 규모가 커질수록 두 기술을 같이 쓰는 경우가 대부분인 것 같다. 이제는 각 기술의 원리와 한계를 정확하게 이해하고, 이를 미리 고려한 설계가 필요한 시대가 아닐까 싶다.

0
Subscribe to my newsletter

Read articles from subbni directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

subbni
subbni