본문 바로가기
TIL,WIL

면접카타 [DB] - 21,22 무결성, JOIN

by GREEN나무 2025. 2. 21.
728x90

21. 무결성(Integrity)에 대해 말해보시오.

무결성이란 데이터베이스에서 데이터의 정확성, 일관성, 신뢰성을 유지하는 것을 의미합니다. 데이터 무결성을 보장하지 않으면 데이터 손상이나 오류가 발생할 수 있으며, 이는 시스템의 신뢰도를 낮출 수 있습니다.

무결성의 종류

  1. 개체 무결성(Entity Integrity)
    • 각 테이블의 기본 키(Primary Key)는 유일(unique) 하고 NULL 값을 가질 수 없습니다.
    • 예: 학생 테이블에서 학번을 기본 키로 설정하면, 같은 학번을 가진 학생이 존재할 수 없으며, 학번이 없는 학생도 있을 수 없습니다.
  2. 참조 무결성(Referential Integrity)
    • 외래 키(Foreign Key)는 참조하는 테이블의 기본 키 값만 가져야 하며, 없는 값을 가질 수 없습니다.
    • 예: 수강 정보 테이블에서 학생 ID가 학생 테이블의 학번을 참조하는 경우, 학생 테이블에 존재하지 않는 학생 ID는 사용할 수 없습니다.
  3. 도메인 무결성(Domain Integrity)
    • 특정 컬럼이 가질 수 있는 값의 범위를 제한합니다.
    • 예: 나이 컬럼의 값은 0 이상이어야 하며, 성별 컬럼에는 '남', '여' 값만 들어가야 합니다.
  4. 고유 무결성(Unique Integrity)
    • 특정 컬럼 또는 컬럼 조합이 고유한 값을 가져야 합니다.
    • 예: 사용자 테이블의 이메일은 유일해야 하며, 같은 이메일을 가진 사용자는 존재할 수 없습니다.
  5. 키 무결성(Key Integrity)
    • 기본 키(Primary Key), 후보 키(Candidate Key), 대체 키(Alternate Key) 등 데이터베이스에서 설정한 키의 제약 조건을 유지하는 것.
    • 예: 기본 키는 반드시 고유해야 하며, 중복될 수 없습니다.
  6. 업무 규칙 무결성(Business Rule Integrity)
    • 특정 업무 로직에 따라 데이터를 제한하는 것.
    • 예: 할인율이 50%를 초과할 수 없도록 설정하는 경우.

꼬리질문

  1. 데이터 무결성을 유지하기 위한 방법은 무엇이 있나요?
    • 답: 제약 조건(Constraints), 트랜잭션(Transaction), 정규화(Normalization) 등을 활용하여 유지할 수 있습니다.
  2. 무결성을 위반하면 어떤 문제가 발생하나요?
    • 답: 중복 데이터, 참조되지 않는 데이터 발생, 데이터 일관성 저하 등이 발생할 수 있습니다.
  3. 무결성과 정규화의 관계는 무엇인가요?
    • 답: 정규화는 데이터베이스의 중복을 줄이고, 이상 현상을 방지하여 무결성을 유지하는 데 기여합니다.

22. JOIN이 무엇인지 설명해주세요.

JOIN은 두 개 이상의 테이블을 연결하여 데이터를 조회하는 SQL 연산입니다. 관계형 데이터베이스에서는 테이블이 분리되어 있어, 여러 테이블의 데이터를 하나의 결과 집합으로 가져오려면 JOIN을 사용해야 합니다.

4.1 INNER JOIN

  • 교집합 역할을 하며, 양쪽 테이블에서 공통된 데이터만 반환합니다.
  • 두 테이블에서 조건을 만족하는 데이터만 결과에 포함됩니다.
  • 예제:
    SELECT 학생.이름, 수강.과목
    FROM 학생
    INNER JOIN 수강 ON 학생.학번 = 수강.학생ID;
    
    • 학생 테이블과 수강 테이블을 학번(학생ID) 기준으로 조인하여, 수강 내역이 있는 학생만 결과에 포함됩니다.

4.2 LEFT JOIN (LEFT OUTER JOIN)

  • 왼쪽 테이블의 모든 데이터와, 일치하는 오른쪽 테이블 데이터를 반환합니다.
  • 오른쪽 테이블에 일치하는 데이터가 없으면 NULL 값을 반환합니다.
  • 예제:
    SELECT 학생.이름, 수강.과목
    FROM 학생
    LEFT JOIN 수강 ON 학생.학번 = 수강.학생ID;
    
    • 학생 테이블의 모든 데이터를 포함하며, 수강 테이블에 해당하는 데이터가 없으면 NULL로 표시됩니다.

4.3 RIGHT JOIN (RIGHT OUTER JOIN)

  • 오른쪽 테이블의 모든 데이터와, 일치하는 왼쪽 테이블 데이터를 반환합니다.
  • 왼쪽 테이블에 일치하는 데이터가 없으면 NULL 값을 반환합니다.
  • 예제:
    SELECT 학생.이름, 수강.과목
    FROM 학생
    RIGHT JOIN 수강 ON 학생.학번 = 수강.학생ID;
    
    • 수강 테이블의 모든 데이터를 포함하며, 학생 테이블에 일치하는 데이터가 없으면 NULL이 표시됩니다.

4.4 FULL OUTER JOIN

  • LEFT JOIN + RIGHT JOIN을 합친 것과 같습니다.
  • 두 테이블의 모든 데이터를 가져오며, 일치하는 값이 없으면 NULL을 반환합니다.
  • 예제:
    SELECT 학생.이름, 수강.과목
    FROM 학생
    FULL OUTER JOIN 수강 ON 학생.학번 = 수강.학생ID;
    
    • 학생 또는 수강 테이블 중 어느 한쪽이라도 데이터가 존재하면 결과에 포함됩니다.

JOIN 성능 최적화

  • 인덱스 사용: 조인하는 컬럼에 인덱스를 생성하면 속도를 개선할 수 있습니다.
  • 필요한 컬럼만 선택: SELECT * 대신 필요한 컬럼만 조회하여 성능을 향상시킵니다.
  • 조인 순서 최적화: 큰 테이블을 먼저 필터링하고 조인하면 불필요한 연산을 줄일 수 있습니다.

꼬리질문

  1. INNER JOIN과 LEFT JOIN의 차이는 무엇인가요?
    • 답: INNER JOIN은 공통된 데이터만 조회하고, LEFT JOIN은 왼쪽 테이블의 모든 데이터를 포함합니다.
  2. JOIN 시 성능을 높이는 방법에는 어떤 것이 있나요?
    • 답: 인덱스 사용, 필요한 컬럼만 선택, 조인 순서 최적화 등을 활용할 수 있습니다.
  3. FULL OUTER JOIN을 사용할 때 고려해야 할 점은 무엇인가요?
    • 답: 결과 집합의 크기가 매우 커질 수 있으며, NULL 값을 처리할 필요가 있습니다.
  4. 서브쿼리와 JOIN 중 어느 것이 더 성능이 좋은가요?
    • 답: 상황에 따라 다르지만, 일반적으로 대량의 데이터를 다룰 때는 JOIN이 더 효율적입니다.

 

 

 


 

NestJS 에서 사용할 수 있는 class-validator 데코레이터

무결성 유형 관련 데코레이터
개체 무결성 @IsUUID(), @IsNotEmpty(), @IsString(), @IsInt()
참조 무결성 @IsUUID(), @IsNotEmpty()
도메인 무결성 @IsEmail(), @IsBoolean(), @IsEnum(), @Min(), @Max(), @Length()
고유 무결성 Custom Validator (@IsEmailUnique())
JOIN 관련 @IsArray(), @ValidateNested(), @Type(() => Class)

 

 

1. NestJS 에서 무결성과 관련된 class-validator 데코레이터

(1) 개체 무결성(Entity Integrity)

  • @IsNotEmpty() : 필수 값이 비어 있으면 안 됨
  • @IsUUID() : UUID 형식인지 검사
  • @IsInt(), @IsString() : 데이터 타입 검증
import { IsNotEmpty, IsUUID, IsInt, IsString } from 'class-validator';

export class CreateUserDto {
  @IsUUID()
  @IsNotEmpty()
  id: string; // 개체 무결성: ID는 UUID 형식이고 비어 있으면 안 됨

  @IsString()
  @IsNotEmpty()
  name: string; // 개체 무결성: 이름은 문자열이고 필수 값
}

(2) 참조 무결성(Referential Integrity)

  • @IsUUID() : 외래 키가 UUID 형식인지 확인
  • @IsNotEmpty() : 외래 키가 NULL이 아닌지 검사
export class CreateOrderDto {
  @IsUUID()
  @IsNotEmpty()
  userId: string; // 참조 무결성: 존재하는 사용자 ID를 참조해야 함
}

(3) 도메인 무결성(Domain Integrity)

  • @IsEmail() : 이메일 형식 검사
  • @IsBoolean() : true/false 값만 허용
  • @IsEnum() : 특정 값만 허용
  • @Min(), @Max() : 숫자의 최소/최대 값 제한
  • @Length() : 문자열 길이 제한
import { IsEmail, IsBoolean, IsEnum, Min, Max, Length } from 'class-validator';

export enum Role {
  USER = 'USER',
  ADMIN = 'ADMIN',
}

export class CreateUserDto {
  @IsEmail()
  email: string; // 이메일 형식만 허용

  @IsBoolean()
  isActive: boolean; // true 또는 false 값만 허용

  @IsEnum(Role)
  role: Role; // 'USER' 또는 'ADMIN' 값만 허용

  @Min(18)
  @Max(100)
  age: number; // 최소 18세, 최대 100세

  @Length(8, 20)
  password: string; // 비밀번호는 8~20자
}

(4) 고유 무결성(Unique Integrity)

  • class-validator 자체적으로 고유성(Unique)을 직접 검증하는 기능은 없음
  • DB에서 중복 체크 필요 → Custom Decorator 활용
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
import { UserService } from '../user.service';

@ValidatorConstraint({ async: true })
export class IsEmailUniqueConstraint implements ValidatorConstraintInterface {
  constructor(private userService: UserService) {}

  async validate(email: string) {
    const user = await this.userService.findByEmail(email);
    return !user; // 이메일이 존재하지 않으면 true 반환 (유효)
  }

  defaultMessage() {
    return '이메일이 이미 사용 중입니다.';
  }
}

export function IsEmailUnique(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsEmailUniqueConstraint,
    });
  };
}

사용 예시:

export class CreateUserDto {
  @IsEmail()
  @IsEmailUnique({ message: '이미 존재하는 이메일입니다.' })
  email: string;
}

2. NestJS 에서 JOIN과 관련된 class-validator 데코레이터

  • @IsArray() : 배열인지 확인 (JOIN된 데이터가 배열일 경우)
  • @ValidateNested() : 중첩된 객체의 유효성 검사
  • @Type(() => Class) : DTO를 객체 타입으로 변환
import { IsArray, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

export class OrderItemDto {
  @IsNotEmpty()
  productId: string;

  @IsInt()
  @Min(1)
  quantity: number;
}

export class CreateOrderDto {
  @IsUUID()
  @IsNotEmpty()
  userId: string;

  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => OrderItemDto)
  items: OrderItemDto[]; // JOIN된 데이터 (주문 아이템 목록)
}