728x90

제가 일하고 있는 분야에서 RDBMS 에 보단 NoSql(Elasticsearch) 를 주로 쓰다 보니 공부하는 겸 공유를 하게 되었습니다.

예전부터 궁금했던것들중에 하나가 선착순으로 지급해주는 이벤트성은 DB에서 어떻게 처리할까? 였습니다. 

DB lock에서 어느정도 궁금증을 해소하게 되었습니다. 혹시나 저처럼 이러한 생각을 한 분들은 이미 DB lock에 대해서 공부를 하셨다고 생각이 들지만 그럼에도 글을 공유하게 되었습니다.


DataBase는 데이터를 영속적으로 저장하는 시스템입니다. 즉 같은 자원에 대해서 동시에 접근하는 경우가 생길 수밖에 없습니다.

 

Lock 이란 트랜잭션 처리의 순차성을 보장하는 방법이라고 했습니다. 트랜잭션이란 DB의 나누어지지 않는 최소한의 처리 단위입니다. 

2가지의 lock 종류가 존재하는데 Shared LockExclusive Lock이 있습니다. Shared Lock은 다른 말로 Read Lock이라고 불리며 Exclusive Lock 은 Write Lock이라고 불립니다. 

 

Shared Lock( 공유락) 공유 Lock 은 데이터를 읽을 때 사용되어지는 lock 이다. 
공유 Lock 끼리는 동시에 접근이 가능합니다.
즉, 하나의 데이터를 읽는 것은 여러 사용자가 동시에 할수 있다는 뜻입니다. 하지만 공유 Lock이 설정된 데이터에 베타 Lock을 사용할 수 없습니다.
Exclusive Lock(베타락) 데이터를 변경하고 할때 사용됩니다. 트랜잭션이 완료될 때까지 유지됩니다. 베타락은 Lock이 해제될 때까지 다른 트랜잭션(읽기 포함)은 해당 리소스에 접근할 수 없습니다. 또한 해당 LocK은 다른 트랜잭션이 수행되고 있는 데이터에 대해서는 접근 하여 함께 Lock을 설정할 수 없습니다.

 

간단한 예를 들어, 서비스를 제공하는 있는 회사에서 이벤트 성으로 선착순 100명에게 커피 쿠폰을 뿌린다고 가정했을 때를 생각해 봅시다.

 

동시다발적으로 100명 이상의 사람들이 접속을 하였지만 누군가에겐 당첨 / 꽝이 나올 겁니다. 이러한 이유는 바로 데이터베이스 잠금을 통해서입니다. 즉 DB lock은 동시에 여러 사용자가 데이터를 접근하려고 할 때 데이터 일관성을 유지하기 위해 사용된다. 

 

흐름을 한번 가정해 봅시다.

 - 이벤트 준비 단계

  •   데이터베이스 테이블 설계 :  이벤트 참여자 정보를 저장할 테이블을 설계한다. 예를 들어) 테이블에는 참여자의 이름, 이메일, 발급된 쿠폰 여부 등의 필드가 포함될 수 있습니다.

 - 쿠폰 발급 과정 : 

  • 사전 준비 : 이벤트 시작 전에 DB Lock을 설정하고, 쿠폰 발급을 준비해야 합니다.
  • 참여자의 요청 처리 : 참여자가 이벤트 페이지에 접속하여 쿠폰을 신청하면, DB lock을 걸어 다른 사용자가 동시에 같은 자원에 접근하지 못하도록 합니다.
  • 조건 확인 : DB에서 현재까지 발급된 쿠폰 수를 확인하여, 발급 가능한 쿠폰의 잔여 수가 100개 이내인지 확인합니다.

 - 쿠폰 발급 및 DB lock 해제

  • 쿠폰 발급 : 잔여 쿠폰 수가 100개 이내일 경우, 새로운 참여자에게 쿠폰을 발급하고, DB lock을 해제합니다.
  • 쿠폰 발급 실패 시 처리 : 잔여 쿠폰 수가 100개 이상이라면, 쿠폰 발급을 실패로 처리하고, 참여자에게 해당 사실을 통보한다.

- 동시 접근 관리 

  • 여러 사용자가 동시에 쿠폰을 신청할 때 DB loc을 통해 데이터 일관성을 유지하고, 데드락(deadlock)이나 경합 상태(race condition)를 방지합니다. 

 - 로그와 모니터링 

  • 쿠폰 발급 로그를 기록하고, 이벤트 참여 현황을 모니터링하여, 문제 발생 시 빠르게 대응할 수 있는 시스템을 유지합니다.

   

위 흐름에서 쿠폰 발급 과정 2단계, 즉 이용자가 이벤트 참여를 클릭하고 서버에 요청을 보낼 때 잠금을 수행하는 것이 가장 좋다고 생각을 할 수 있습니다.

 

예제 코드

-- MySQL syntax

-- 트랜잭션 시작
START TRANSACTION;

-- 사용 가능한 쿠폰이 있는지 확인합니다(쿠폰이라는 테이블이 있다고 가정).
SELECT COUNT(*) INTO @remaining_coupons FROM coupons WHERE used = 0;

-- 사용 가능한 쿠폰이 남아 있는지 확인
IF @remaining_coupons < 100 THEN
    -- Rollback the transaction if there are not enough coupons
    ROLLBACK;
    SELECT 'No more coupons available' AS message;
ELSE
    -- 현재 사용자에 대해 사용 가능한 첫 번째 쿠폰을 업데이트합니다(쿠폰_배정이라는 테이블이 있다고 가정).
    UPDATE coupons 
    SET used = 1, user_id = 'user_id_here' -- Replace '해당 이용자 ID' 실제 ID
    WHERE coupon_id = (
        SELECT coupon_id 
        FROM coupons 
        WHERE used = 0 
        ORDER BY coupon_id ASC 
        LIMIT 1
    );

    -- 쿠폰 할당이 성공하면 거래를 커밋합니다.
    COMMIT;
    SELECT 'Coupon assigned successfully' AS message;
END IF;

 

좀 더 쉽게 설명을 해드리자면,

  1. 트랜잭션이 시작 : 데이터 일관성을 유지하기 위해 트랜잭션을 시작한다.
  2. 남은 쿠폰 수 조회 : 사용하지 않은 쿠폰의 수를 조회하여 '@remaining_coupons' 변수에 저장합니다.
  3. 쿠폰 수 체크 : '@remaining_coupons' 변수를 이용하여 남은 쿠폰 수가 100개 미만인지 확인합니다.
  4. 쿠폰 발급 : 남은 쿠폰 수가 100개 이상일 경우, 사용하지 않은 첫 번째 쿠폰을 해당 사용자에게 할당합니다.  'UPDATE' 문을 사용하여 'coupons' 테이블에서 'used' 상태를 '1'로 업데이트하고, 사용자 ID를 저장합니다. 
  5. 트랜잭션 완료('COMMIT;') : 쿠폰 할당이 성공적으로 이루어졌을 때, 트랜잭션을 커밋하여 변경 사항을 영구적으로 반영합니다.
  6. 오류 처리 : 남은 쿠폰이 100개 미만이면 롤백을 수행하여 이전 상태로 복구하고, 쿠폰이 모두 소진되었음을 사용자에게 알린다.

정말 간단한 예시이며, 실제 환경에서는 보안 및 성능을 고려해서 추가적인 작업들이 필요하다고 생각이 듭니다. 

(사용자 인증, 인덱스 설정 등...) DB 종류에 따라 문법이 다를 수 있다는 점 유의 하시면 좋겠습니다.

 

 

728x90
728x90

오늘은 JPA N+1의 문제 해결에 대해서 글을 공유해드리려고 합니다. 

* Java 백엔드 개발자를 위한 데이터베이스 쿼리 최적화에 적합한 내용입니다.

개발자가 직면하는 가장 일반적인 성능 병목 현상 중 하나가 N+1입니다.
애플리케이션이 단 한 번의 쿼리로 동일한 결과를 얻을 수 있는데도 N+1번의 데이터베이스 쿼리를 수행할 때 발생합니다.
과도한 데이터베이스 Hit는 느린 응답 시간, 높은 서버 부하, 열약한 사용자 경험으로 이어질 수 있습니다. 
 
원인을 함께 파악해 보고 개발자가 이러한 문제를 어떻게 완화할지에 대해서 다양한 전략과 기법에 대해서 적어보겠습니다.

앞서, N+1 문제가 무엇인지 알아보도록 하겠습니다.

N+1 문제란 무엇인가?

애플리케이션이 개체목록(예시: 제품, 사용자 또는 게시물 목록)을 가져온 다음 목록의 각 객체애 대해 추가 데이터베이스 쿼리를 수행하여 관련 데이터를 검색할 때 발생을 하게 됩니다.
예를 들어 작성자 정보와 함께 블로그 게시물 목록을 표시하는 Java 애플리케이션을 생각해 보자.
애플리케이션이 글 목록을 가져온 다음 각 글의 작성자 정보를 검색하기 위해 별도의 쿼리를 수행하면 N+1 쿼리가 발생하며, 여기서 N은 글의 수입니다. 이러한 비효율적인 쿼리 패턴은 많은 수의 데이터베이스 HIT로 빠르게 이어질 수 있습니다.
 

N+1 문제 원인

1. 지연 로딩(Lazy Loading) : 
수많은 Java ORM 프레임워크들, 가령 Hibernate에서 기본적으로 지연 로딩을 사용합니다.
지연 로딩이란 관련된 데이터를 가져올때만  데이터베이스에 가져오는 것을 의미합니다. 개발자가  컬렉션의 각 항목에 대한 관련 데이터에 접근할 때 N+1 쿼리를 발생할 수 있습니다.  
 
2.비효율적인 쿼리(Inefficient Queries)
개발자는 관련 데이터를 반복해서 가져오는 코드를 작성하여 최적화된 단일 쿼리로 충분할 수 있는 데이터베이스 쿼리를 여러 번 수행하게 될 수 있습니다.
 
3. 일괄 가져오기 부족 (Lack of Batch Fetching)
일부 ORM 프레임워크에서 제공하는 기술인 일괄 가져오기를 사용하면 단일 쿼리에서 여러 개체에 대한 관련 데이터를 검색할 수 있습니다.
개발자들은 이 기능을 간과하거나 오용하는 경우가 많습니다.
 

N+1 문제를 완화하기 위한 전략들

N+1 문제를 해결하고 과도한 데이터베이스 히트를 최소화하기 위해 Java 백엔드 엔지니어는 다양한 전략과 모범 사례를 활용할 수 있습니다

 

1. 에저 로딩 

에지 로딩을 사용하면 관련 데이터를 미리 불러와 추가 쿼리의 필요성을 줄일 수 있습니다. 대부분의 ORM 프레임워크는 관련 데이터를 로드할 시기와 방법을 지정하는 메커니즘을 제공하므로 데이터베이스 쿼리를 최적화할 수 있습니다.

2. 일괄 가져오기

ORM 프레임워크에서 제공하는 일괄 가져오기 기능을 사용하여 관련 데이터를 하나씩 가져오지 않고 일괄적으로 검색하세요. 이렇게 하면 데이터베이스 쿼리 횟수를 크게 줄일 수 있습니다. 

3. DTO 투영

데이터베이스에서 필요한 데이터만 가져오려면 DTO(데이터 전송 객체) 투영을 사용하는 것이 좋습니다. 이 접근 방식을 사용하면 검색되는 데이터의 양을 최소화하여 쿼리 속도를 높일 수 있습니다.

4. 캐싱

캐싱 메커니즘을 구현하여 자주 액세스하는 데이터를 메모리에 저장하세요. 캐싱은 반복적인 데이터베이스 쿼리의 필요성을 줄여 응답 시간을 개선하고 데이터베이스 부하를 줄이는 데 도움이 될 수 있습니다.

5. 페이지 매김 및 필터링

페이지 매김 및 필터링을 구현하여 단일 쿼리에서 검색되는 레코드 수를 제한하세요. 이는 대규모 데이터 세트를 다룰 때 특히 유용할 수 있습니다.

6. 쿼리 최적화

데이터베이스 쿼리를 정기적으로 검토하고 최적화하세요. 쿼리 실행 계획을 분석하고 데이터베이스 프로파일링 도구를 사용해 성능 병목 현상을 파악하고 해결하세요.
 

마치며

N+1 문제와 과도한 데이터베이스 히트는 Java 백엔드 엔지니어가 직면하는 일반적인 성능 문제입니다. 개발자는 N+1 문제의 원인을 이해하고 일괄 로딩, 배치 가져오기, DTO 예측, 캐싱, 페이지 매김 및 쿼리 최적화와 같은 효과적인 전략을 채택함으로써 애플리케이션의 성능을 크게 향상해 원활한 사용자 경험을 보장하고 서버 부하를 줄일 수 있습니다. N+1 문제를 해결한다는 것은 단순히 데이터베이스 쿼리를 최적화하는 것만이 아니라 사용자에게 효율적이고 확장 가능한 백엔드 솔루션을 제공하는 것입니다.
 

728x90

'DB' 카테고리의 다른 글

Database Lock 이란?  (1) 2024.06.18
PL/SQL 이란  (0) 2022.01.10
데이터베이스 모델링 -1  (0) 2022.01.07
SQL 사용자 권한  (0) 2022.01.05
SQUENCE INDEX(순차 적으로 증가하는 값)  (0) 2022.01.05
728x90

PL/SQL의 특징

 

  • PL/SQL은 BLOCK 구조로 되어있고 BLOCK 내에는 DML 문장과 QUERY 문장, 그리고 절차형 언어(IF, LOOP) 등을 사용할수 있다.
  • 특징은 저장 모듈 (STORED MODULE)을 이용해서 PL/SQL 을 데이터베이스에 저장하여 독립적으로 실행되거나 다른 프로그램으로부터 실행될 수 있는 완전한 실행 프로그램이다.
  • ORACLE 의 저장 모듈에는 PROCEDURE, USER DEFINED FUNCTION, TRIGGER가 있다.

 


PL/SQL 의 특징은 다음과 같다.

-PL/SQL은 Block 구조로 되어있어 각 기능별 모듈화가 가능하다.

-변수, 상수 등을 선언하여 SQL 문장 간 값을 교환한다.

-IF,Loop 등의 절차형 언어를 사용하여 절차적인 프로그램이 가능하도록 한다.

-DBMS 정의 에러나 사용자 정의 에러를 정의하여 사용할 수 있다.

-PL/SQL 은 Oracle 에 내장되어 있으므로 Oracle 과 PL/SQL 을 지원하는 어떤 서버로도 프로그램을 옮길 수 있다. 

-PL/SQL 은 응용 프로그램의 성능을 향상시킨다.

-PL/SQL 은 여러 SQL 문장을 Block 으로 묶고 한번에 Block 전부를 서버로 보내기 때문에 통신량을 줄 일 수 있다.

 

 

 

 

PL/SQL Block 프로그램을 입력받으면 SQL 문장과 프로그램 문장을 구분하여 처리한다.

즉 프로그램 문장은 PL/SQL 엔진이 처리하고 SQL 문장은 Oracle 서버의 SQL statement Executor 가 실행하도록 작업을 분리하여 처리한다.

기본 PL/SQL 구조입니다.

 

 

DECLARE 에 컬럼명과 %TYPE 을 붙여 선언하는 방식입니다. 같은 값을 나타냅니다.

728x90
728x90

데이터베이스 모델링  또는 데이터베이스 설계라고도 합니다.

 

(-모델링 과목을 많이 하고 하는 만큼 실력이 늘어난다. 혹은 이해할수 있다. )

 

4가지 작업으로 이루어지는 데이터베이스 모델링

 

1.업무파악 : 무엇을 할수 있는가 무엇을 만들건가를 파악해야한다.

화면을 보고 업무파악 혹은 고객사에서 요구하는 요구사항을 글로 읽고 파악하는 단계가 될수도 있다.

글을 읽고도 무엇이 필요한지 깨달을 필요가 있어야한다. 

 

2.개념적 데이터 모델링

- er 다이어그램으로 어떤것들이 필요할거같은 중요 핵심들을 뽑아내서 추출하는 작업

 

3. 논리적 데이터모델링

-er 다이어그램을 보고 단계형 데이터베이스에 맞게끔 표로 전환하는 작업

 

4. 물리적 데이터 모델링

실제 표를 생성하고 만드는 작업 

 

 

개념적 데이터 모델링에서는....

 

개념적 데이터부터 단계적으로 순조롭게 되어야 나머지 단계별들도 잘 작업이 이루어질수 있다.

 

Entity - 엔티티는 Table이 됩니다

Attribute - 속성은 column이 됩니다.

Relation - 엔티티들의 추후 PK,FK로 연결됩니다.

 

Cardinality (관계 대응수)

엔티티와 엔티티의 관계대수

 

Optionality 

엔티티와 엔티티의 필수, 옵션을 표기

개념적 데이터 모델링

1:N 의 관계

EX)

회원에게 댓글은 여러개를 달수있다

회원에게 댓글은 옵션일뿐이다

댓글에게 회원은 한명을 쓴다

댓글에게 회원은 필수이다.

회원은 게시글은 여러개쓸수 있다

회원은 게실글이 옵션이다.

게시글에게는 회원은 하나이다.

게시글에는 회원이 필수이다.

 

 

 

 

게시글에게 댓글은 여러개다.

게시글에게 댓글은 옵션이다

댓글에게 게시글은 필수이다.

댓글에게 게시글은 하나이다. 

 

 

728x90

'DB' 카테고리의 다른 글

N+1 문제 해결: Java 백엔드 개발자를 위한 데이터베이스 쿼리 최적화  (0) 2024.06.05
PL/SQL 이란  (0) 2022.01.10
SQL 사용자 권한  (0) 2022.01.05
SQUENCE INDEX(순차 적으로 증가하는 값)  (0) 2022.01.05
뷰(View)  (0) 2022.01.05
728x90

권한(Privilege)은 특정 SQL 문장을 실행하기 위한 권리 입니다.

데이터베이스 관리자(DBA) 는 데이터베이스와 그 객체에 대한 엑세스를 사용자에게 부여하는 능력을 갖춘 상급 사용자입니다.

사용자는 데이터베이스에 엑세스하기 위해 시스템 권한( System Privilege)이 필요하고 데이터베이스에서 객체의 내용을 조작하기 위해 객체 권한(Object Privilege) 이 필요합니다.

 

사용자는 관련 관한들의 이름 있는 그룹인 Role 이나 다른 사용자에게 추가로 권한을 부여하기 위해 권한을 가질 수 있습니다.

사용자와 롤에 대해 시스템 권한과 객체 권한을 부여할 수 있습니다.

시스템 권한은 대게 데이터베이스 관리자 (DBA) 에 의해 제공됩니다. 객체 권한은 대게 객체의 소유주에 의해 제공됩니다.


사용자 계정 생성

 

DBA는 CREATE USER 문장을 실행하여 사용자를 생성합니다. 사용자는 이때에는 어떤 권한도 가지지 않습니다. DBA는 이때 그 사용자에게 여러 권한을 부여합니다. 이 권한은 데이터베이스 수준에서 사용자가 할 수 있는 것이 무엇인가를 결정합니다. 슬라이드는 사용자 생성을 위해 요약된 구문을 제공합니다. 

CREATE USER     user_name

INDENTIFIED BY  passward;

구문 형식에서...

--- user_name : 생성되어야 하는 사용자 이름(아이디)입니다.

--- password :  사용자의 로그인 비밀번호를 지정합니다.

 

다음 구문은 사용자를 생성합니다. 사용자를 생성하기 위해서 DBA 권한을 가진 사용자로 접속해야 합니다. 


시스템 권한 역활(ROLE)

 

생성된 계정에 권한 부여

 

일단 사용자가 생성되었다면, DBA는 사용자에 대한 특정 시스템 권한을 부여할 수 있습니다.

DBA는 사용자에게 시스템 권한을 부여하기 위해  GRANT 문장을 사용합니다. 일단 사용자가 권한을 부여받았으면, 사용자는 즉시 그 권한을 사용할 수 있습니다.

다음 구문은 DBA 사용자가 heojk 사용자에게 디폴트 테이블 스페이스를 USERS 테이블 스페이스로 지정합니다. USERS테이블 스페이스를 사용할 수 있는 용량의 최대 제한이 설정합니다.

롤을 사용하려면 우선 DBA는 롤을 생성해야 합니다. 롤이 생성되면, DBA는 롤에 대한 권한뿐만 아니라 롤을 사용자에게 할당하기 위한 GRANT 문장을 사용할 수 있습니다.

CREATE ROLE role_name;

구문형식에서...

role_name : 생성되어야 할 롤의 이름입니다.

 

*오라클에 디폴트로 존재하는 CONNECT, RESOURCE, DBA 롤 등을 이용하면 해당 롤을 이용해서 쉽게 사용자에게 권한을 부여할 수 있습니다. 

 

사용자를 생성해서 테이블을 생성하고 사용할 수 있습니다.

아래 방법은 SYSTEM계정으로 사용자계정 생성과 권한 부여를 초간단 하게 하는 방법입니다.

 

CREATE user jsp INENTIFIED BY jsp;

--이미 지정된 권한 부여(테이블, 시퀸스,뷰)

GRANT connect, resource TO jsp;

 


비밀번호 변경

 

사용자 계쩡이 생성되었을 때, 각 사용자는 DBA 가 초기화한 비밀번호를 갖게 됩니다.

사용자는 ALTER USER 문장을 사용하여 자신의 비밀번호를 수정할 수 있습니다. 

ALTER USER user_name

IDENTIFIED BY password;

 

구문 형식에서 

- user_name: 사용자 이름입니다.

- password : 새 비밀번호를 지정합니다.

 

728x90

'DB' 카테고리의 다른 글

PL/SQL 이란  (0) 2022.01.10
데이터베이스 모델링 -1  (0) 2022.01.07
SQUENCE INDEX(순차 적으로 증가하는 값)  (0) 2022.01.05
뷰(View)  (0) 2022.01.05
DML-1  (0) 2022.01.04

+ Recent posts