more about databases

SSamYang·2024년 10월 10일

데이터베이스는 하나 이상의 관련 조직의 유용한 데이터를 모아놓은 것으로, 데이터를 조직의 자산으로 만들기 위해 구조화된 방식으로 저장됩니다. 데이터베이스 관리 시스템은 대규모 데이터 모음을 효율적으로 유지하고 추출하는 데 도움을 주기 위해 설계된 소프트웨어입니다.

ORMs

ORM(Object-Relational Mapping)은 객체 지향 프로그래밍 언어에서 데이터베이스와의 상호작용을 보다 쉽게 하기 위해, 데이터베이스 테이블을 객체로 매핑하는 기술을 말합니다. ORM을 사용하면 SQL 쿼리문을 직접 작성하지 않고도, 데이터베이스와 상호작용할 수 있으며, 객체 지향적인 방식으로 데이터를 다룰 수 있게 됩니다.

1. ORM의 개념:

  • 객체관계형 데이터베이스 테이블 간의 매핑을 제공하는 라이브러리나 프레임워크입니다.
  • 객체 지향 언어(예: Python, Java)에서 데이터베이스를 다룰 때, 객체(Object)를 데이터베이스의 테이블에 매핑하여 SQL 쿼리를 추상화합니다.

2. ORM의 주요 기능:

  • CRUD 기능: Create, Read, Update, Delete 작업을 객체 지향적으로 수행할 수 있습니다.
  • 데이터 매핑: 데이터베이스의 테이블을 클래스(class)로, 테이블의 행(row)을 객체(object)로 매핑합니다.
  • 자동 쿼리 생성: ORM을 통해 개발자는 직접 SQL을 작성하지 않고, ORM이 필요한 SQL 쿼리를 자동으로 생성해 줍니다.
  • 트랜잭션 관리: 데이터베이스 트랜잭션을 자동으로 처리하고, 롤백이나 커밋을 관리할 수 있습니다.

3. ORM의 장점:

  • 생산성 향상: ORM은 SQL을 직접 작성하는 수고를 덜어주고, 코드의 재사용성을 높여 생산성을 향상시킵니다.
  • 유지보수 용이: ORM은 데이터베이스 의존성을 줄이기 때문에, 데이터베이스 시스템이 변경되어도 코드 수정을 최소화할 수 있습니다.
  • 보안 강화: ORM은 자동으로 SQL 인젝션을 방지하는 기능을 포함하여, 보안 문제를 줄일 수 있습니다.
  • 객체 지향적 프로그래밍과의 자연스러운 통합: 데이터베이스 작업이 객체 지향 방식으로 수행되므로 개발자가 익숙한 방식으로 데이터베이스를 다룰 수 있습니다.

4. ORM의 단점:

  • 복잡한 쿼리 성능 문제: ORM은 단순한 쿼리에는 적합하지만, 복잡한 SQL 쿼리(특히 조인 등)를 자동으로 최적화하기 어렵기 때문에 성능 문제가 발생할 수 있습니다.
  • 추상화로 인한 제어 부족: ORM이 자동으로 SQL을 생성하다 보니, SQL 쿼리에 대한 세밀한 제어가 어려울 수 있습니다.
  • 학습 곡선: ORM 자체의 동작 방식과 문법을 배우는 데 시간이 필요할 수 있습니다.

5. ORM 사용 예시:

  • SQLAlchemy (Python):
    python
    코드 복사
    from sqlalchemy import create_engine, Column, Integer, String
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker
    
    Base = declarative_base()
    
    class User(Base):
        __tablename__ = 'users'
        id = Column(Integer, primary_key=True)
        name = Column(String)
        age = Column(Integer)
    
    engine = create_engine('sqlite:///:memory:')
    Base.metadata.create_all(engine)
    
    Session = sessionmaker(bind=engine)
    session = Session()
    
    # Create
    new_user = User(name='Alice', age=25)
    session.add(new_user)
    session.commit()
    
    # Read
    user = session.query(User).filter_by(name='Alice').first()
    print(user.name, user.age)
    
  • Hibernate (Java):
    java
    코드 복사
    @Entity
    @Table(name = "users")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(name = "name")
        private String name;
    
        @Column(name = "age")
        private int age;
    
        // Getters and setters
    }
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction transaction = session.beginTransaction();
    
    // Create
    User user = new User();
    user.setName("Alice");
    user.setAge(25);
    session.save(user);
    
    transaction.commit();
    session.close();
    

6. ORM의 주요 프레임워크:

  • Hibernate (Java): Java에서 가장 널리 사용되는 ORM 프레임워크로, 관계형 데이터베이스를 객체 모델로 매핑하여 효율적으로 관리합니다.
  • SQLAlchemy (Python): 강력하고 유연한 ORM으로, 다양한 관계형 데이터베이스와 호환됩니다.
  • Django ORM (Python): Django 프레임워크에 내장된 ORM으로, 데이터베이스 작업을 객체 지향 방식으로 쉽게 처리할 수 있습니다.
  • Entity Framework (C#): Microsoft에서 제공하는 ORM으로, .NET 환경에서 데이터베이스 작업을 쉽게 처리할 수 있습니다.

7. 결론:

  • ORM은 객체 지향 언어와 데이터베이스를 연결하는 중요한 도구로, 개발 생산성을 높이고 코드의 유지보수를 쉽게 할 수 있습니다.
  • 그러나 복잡한 쿼리나 성능 이슈에 주의해야 하며, ORM 사용 시에는 효율적인 쿼리 작성 방법이나 데이터베이스 최적화 기술을 함께 고려하는 것이 중요합니다.

ACID

ACID는 데이터베이스 시스템에서 트랜잭션이 안전하고 신뢰성 있게 처리되기 위한 4가지 핵심 속성을 의미합니다. ACID는 데이터 무결성과 일관성을 보장하며, 각 속성은 다음과 같습니다:

1. Atomicity (원자성):

  • 트랜잭션 내의 작업들이 전부 성공하거나 전부 실패하는 것을 보장합니다. 트랜잭션이 중간에 실패하면 그동안 수행된 모든 작업이 롤백되어, 데이터베이스는 트랜잭션 시작 이전의 상태로 복구됩니다.
  • 예를 들어, 은행 계좌 이체에서 돈을 출금한 후에 입금이 실패한다면, 출금 역시 취소되어야 합니다. 둘 다 성공하거나, 둘 다 실패해야 합니다.

2. Consistency (일관성):

  • 트랜잭션이 완료된 후에도 데이터베이스가 일관된 상태를 유지해야 합니다. 즉, 데이터베이스는 트랜잭션 전후로 규칙과 제약 조건을 항상 만족해야 합니다.
  • 예를 들어, 은행 계좌 이체 후에도 총 잔액은 변하지 않아야 하며, 데이터의 무결성이 유지되어야 합니다.

3. Isolation (고립성):

  • 동시에 실행되는 여러 트랜잭션이 서로의 작업에 영향을 미치지 않도록 보장합니다. 즉, 하나의 트랜잭션이 완료되기 전에 다른 트랜잭션은 해당 트랜잭션의 중간 상태를 볼 수 없습니다.
  • 예를 들어, 두 트랜잭션이 동시에 실행될 때, 한 트랜잭션이 완료되기 전까지 다른 트랜잭션은 그 작업을 참조하거나 수정할 수 없습니다.

4. Durability (지속성):

  • 트랜잭션이 성공적으로 완료되면 그 결과는 영구적으로 저장되어, 시스템 장애가 발생하더라도 손실되지 않아야 합니다. 이를 위해 데이터는 디스크나 영구 저장 매체에 기록됩니다.
  • 예를 들어, 트랜잭션이 완료된 후 서버가 다운되더라도, 완료된 트랜잭션의 결과는 데이터베이스에 남아 있어야 합니다.

ACID 속성 요약

속성설명
원자성트랜잭션이 전부 성공하거나 전부 실패함. 중간에 실패 시 롤백
일관성트랜잭션 전후에 데이터베이스가 일관된 상태를 유지
고립성동시 실행 트랜잭션이 서로 영향을 미치지 않음
지속성트랜잭션 완료 후 그 결과가 영구적으로 저장됨

ACID의 중요성

ACID 속성은 트랜잭션 처리에서 데이터 무결성과 신뢰성을 보장하며, 금융, 전자상거래, 의료 데이터 등 중요한 데이터를 다루는 시스템에서 필수적입니다.

4o

Transactions

  • *트랜잭션(Transactions)은 데이터베이스에서 일련의 작업을 하나의 논리적 단위로 묶은 것입니다. 이 논리적 단위는 여러 작업을 하나의 작업처럼 처리하여 데이터 무결성을 유지하는 데 중요한 역할을 합니다. 트랜잭션은 성공적으로 수행되면 모든 작업이 데이터베이스에 반영되고, 실패하면 중간에 수행된 작업들이 모두 취소(롤백)되어 일관된 상태**를 유지합니다.

트랜잭션의 주요 특성 (ACID)

트랜잭션은 데이터 무결성을 보장하기 위해 다음 네 가지 ACID 특성을 가져야 합니다:

  1. Atomicity (원자성): 트랜잭션 내의 모든 작업이 완전히 이루어지거나 전혀 이루어지지 않아야 합니다. 중간에 오류가 발생하면 전체 트랜잭션이 실패하고, 트랜잭션 시작 전 상태로 롤백됩니다.
  2. Consistency (일관성): 트랜잭션이 성공적으로 완료된 후 데이터베이스는 항상 일관된 상태로 유지되어야 합니다. 데이터베이스의 규칙이나 제약 조건이 트랜잭션 후에도 만족해야 합니다.
  3. Isolation (고립성): 동시에 실행되는 여러 트랜잭션은 서로 영향을 미치지 않아야 합니다. 하나의 트랜잭션이 완료되기 전에는 다른 트랜잭션이 그 중간 결과를 볼 수 없습니다.
  4. Durability (지속성): 트랜잭션이 성공적으로 끝나면 그 결과는 시스템 장애가 발생해도 영구적으로 저장됩니다.

트랜잭션의 상태

트랜잭션은 다음과 같은 여러 상태를 거칩니다:

  1. Active (활성): 트랜잭션이 실행 중인 상태입니다.
  2. Partially Committed (부분 완료): 트랜잭션의 마지막 명령이 실행된 후의 상태로, 아직 커밋되지 않은 상태입니다.
  3. Committed (커밋됨): 트랜잭션이 성공적으로 완료되고 데이터베이스에 반영된 상태입니다.
  4. Failed (실패): 트랜잭션이 실패한 상태로, 오류가 발생하여 중단된 상태입니다.
  5. Aborted (중단됨): 트랜잭션이 실패하여 롤백된 상태입니다. 트랜잭션이 중단된 후 데이터베이스는 트랜잭션 시작 전 상태로 복원됩니다.

트랜잭션의 두 가지 주요 작업

  • Commit: 트랜잭션이 성공적으로 완료되어 모든 변경 사항을 데이터베이스에 영구적으로 반영하는 작업입니다.
  • Rollback: 트랜잭션이 실패할 경우, 트랜잭션 내의 모든 변경 사항을 취소하고 데이터베이스를 트랜잭션 시작 전 상태로 되돌리는 작업입니다.

트랜잭션의 예시

은행 계좌 이체를 생각해보면:

  1. 계좌 A에서 일정 금액을 출금.
  2. 계좌 B에 동일한 금액을 입금.

이 두 가지 작업은 하나의 트랜잭션으로 묶여야 합니다. 만약 A에서 출금은 되었으나 B에 입금이 실패하면, 출금 작업도 취소되어야 합니다. 그렇지 않으면 데이터 무결성이 깨지게 됩니다.

트랜잭션의 중요성

트랜잭션은 특히 금융, 전자 상거래, 재고 관리 등 중요한 데이터가 다뤄지는 시스템에서 핵심적입니다. 트랜잭션을 통해 데이터베이스의 일관성과 무결성을 유지하고, 예상치 못한 오류나 장애로부터 데이터를 보호할 수 있습니다.

N plus one problem

N+1 문제는 데이터베이스를 사용하는 애플리케이션에서 자주 발생하는 성능 문제 중 하나입니다. 주로 ORM(Object-Relational Mapping)을 사용할 때 많이 발생합니다. 이 문제는 다음과 같은 방식으로 발생합니다:

1. N+1 문제의 개념:

  • N개의 데이터를 가져오기 위해 1번의 쿼리를 실행한 뒤, 각 데이터에 대한 세부 정보를 가져오기 위해 N번의 추가 쿼리를 실행하는 상황을 말합니다.
  • 즉, 총 N+1번의 쿼리가 실행되는 것으로, 필요 이상으로 많은 쿼리가 발생해 성능 저하가 일어나는 문제입니다.

2. 예시:

예를 들어, 블로그 포스트와 각 포스트의 댓글을 불러오는 상황을 생각해봅시다.

  • 첫 번째 쿼리로 블로그 포스트 목록을 가져옵니다: SELECT * FROM posts;
  • 그런 다음, 각 블로그 포스트마다 댓글을 불러오기 위해 N개의 추가 쿼리가 실행됩니다:
    SELECT * FROM comments WHERE post_id = ?;

이렇게 하면 총 1 + N번의 쿼리가 실행됩니다.

3. 문제점:

  • 이렇게 쿼리가 많이 발생하면, 데이터베이스 서버에 과부하가 걸리고, 애플리케이션의 성능이 심각하게 저하될 수 있습니다.
  • 네트워크 지연, 쿼리 실행 시간 등이 누적되면서 불필요한 리소스를 소모하게 됩니다.

4. 해결 방법:

  • Lazy LoadingEager Loading 전략을 적절히 사용하여 이 문제를 해결할 수 있습니다.
    • Eager Loading: 한 번의 쿼리로 관련된 데이터를 미리 가져오는 방식입니다. 예를 들어, JOIN을 사용하여 포스트와 댓글을 한 번에 가져옵니다:SELECT * FROM posts LEFT JOIN comments ON posts.id = comments.post_id;
    • Lazy Loading: 데이터를 실제로 필요할 때 가져오는 방식입니다. 필요할 때마다 데이터를 가져오기 때문에 N+1 문제가 발생할 가능성이 있습니다.
  • Batch Fetching: 여러 개의 개별 쿼리를 묶어서 한 번에 데이터를 가져오는 방식입니다.
  • 페치 조인(Fetch Join): ORM에서 제공하는 기능으로, 연관된 데이터를 미리 가져오는 기능을 사용하여 쿼리 수를 줄일 수 있습니다.

5. 결론:

N+1 문제는 쿼리 수가 불필요하게 증가하는 성능 문제로, 이를 해결하기 위해 데이터베이스 쿼리 최적화나 ORM의 적절한 설정이 필요합니다.

profile
공부 기록장📕

0개의 댓글