개발인생/Certificate

정처기 실기[이론2]

forri 2025. 4. 16. 16:04

더보기

<목차>

1. 결합도 유형 (내.공.외.제.스.자) Bad → Good

2. Anotation

  • @Controller @RequestMapping @RequestParam @RequestHeader
  • @PathVariable @CookieValue @ModelAttribute @ResponseBody
  • @RequestBody @Repository @Service @Scheduled

3. 데이터베이스 트랜잭션

- 4가지 성질 (ACID) | 모델링 | 인터페이스 설계 | 세부 설계

4. 논리-물리 데이터 모델 변환

5. 가상테이블 뷰 (View)

6. 관계대수 · 관계해석 · SQL SELECT

7. 스키마 (Schema)

- 스키마 3계층 (외부-개념-내부)

- 3계층 스키마 vs 데이터베이스 설계 3단계 (개념-논리-물리)

▶ 결합도 유형 (내.공.외.제.스.자) Bad->Good

유형 설명
자료 결합도
(Data Coupling)
모듈 간의 인터페이스로 값이 전달되는 경우
스탬프 결합도
(Stamp Coupling)
모듈 간의 인터페이스로 배열이나 오브젝트, 스트럭처 등이 전달되는 경우
제어 결합도
(Control Coupling)
단순 처리할 대상인 값만 전달되는 게 아니라 어떻게 처리를 해야 한다는 제어 요소가 전달되는 경우
외부 결합도
(External Coupling)
어떤 모듈에서 선언한 데이터(변수)를 외부의 다른 모듈에서 참조하는 경우
공통 결합도
(Common Coupling)
파라미터가 아닌 모듈 밖에 선언되어 있는 전역 변수를 참조하고, 전역 변수를 갱신하는 식으로 상호 작용하는 경우
내용 결합도
(Content Coupling)
다른 모듈 내부에 있는 변수나 기능을 다른 모듈에서 사용하는 경우

1. 내용 결합도 (Content Coupling) — 가장 나쁨 (Bad)

  • 정의: 한 모듈이 다른 모듈의 내부(변수, 코드 등)를 직접 접근하는 경우
  • 문제점: 내부 구현이 바뀌면 접근한 모듈도 함께 수정해야 함
// 나쁜 예시
class ModuleA {
    public int value = 10;
}

class ModuleB {
    void printValue(ModuleA a) {
        System.out.println(a.value); // 내부 변수 직접 접근 -> 내용 결합도
    }
}

 

2. 공통 결합도 (Common Coupling)

  • 정의: 여러 모듈이 전역 변수(global variable)를 공유
  • 문제점: 전역 변수의 변경이 모든 모듈에 영향을 줌
// 나쁜 예시
public class Shared {
    public static int sharedValue = 0;
}

class ModuleA {
    void update() {
        Shared.sharedValue = 10; // 공통 변수 변경
    }
}

class ModuleB {
    void read() {
        System.out.println(Shared.sharedValue); // 같은 변수 참조
    }
}

 

3. 외부 결합도 (External Coupling)

  • 정의: 모듈이 외부 포맷(파일, DB 포맷 등)에 의존할 때
  • 문제점: 외부 변경이 모듈 동작에 영향을 줌
// 예시: 외부 파일 포맷에 의존
class Module {
    void loadData(String filePath) {
        // CSV 포맷 고정
        // 만약 JSON으로 바뀌면 이 코드 전체 변경 필요
    }
}

 

4. 제어 결합도 (Control Coupling)

  • 정의: 모듈이 제어 흐름(플래그, 조건)을 인자로 전달
  • 문제점: 한 모듈이 다른 모듈의 실행 흐름을 제어함
// 예시
class Printer {
    void print(boolean isDetailed) {
        if (isDetailed) {
            System.out.println("상세 출력");
        } else {
            System.out.println("간단 출력");
        }
    }
}

 

5. 스탬프 결합도 (Stamp Coupling)

  • 정의: 필요 이상으로 많은 데이터 구조(객체 전체)를 넘기는 경우
  • 문제점: 특정 필드만 쓰는데 객체 전체를 넘김 -> 불필요한 의존성
class Customer {
    String name;
    String address;
    String phone;
}

class Service {
    void greet(Customer customer) {
        System.out.println("Hello " + customer.name); // name만 필요함
    }
}

 

6. 자료 결합도 (Data Coupling) — 가장 이상적 (Good)

  • 정의: 모듈이 순수한 데이터를 인자로 주고받음 (필요한 것만)
  • 장점: 결합도 낮음, 독립적임
class Calculator {
    int add(int a, int b) {
        return a + b; // 필요한 데이터만 전달
    }
}

Anotation

종료 설명
@Controller 스프링 MVC에서 컨트롤러 객체임을 명시. 웹 요청을 처리하는 클래스에 선언
@RequestMapping 클라이언트에서 보낸 URI에 매핑되어 있을 때 명시. 주로 URL 요청을 컨트롤러와 연결할 때 사용
@RequestParam HTTP 요청 파라미터 값을 파라미터 변수에 할당. 주로 단일 파라미터 전달 시 사용
@RequestHeader HTTP 요청 헤더에서 정보를 추출할 때 사용
@PathVariable URI의 경로 변수를 받을 때 사용. 주로 RESTful URI 경로를 처리할 때 유용
@CookieValue 요청의 쿠키 정보 중 특정 값을 컨트롤러 파라미터로 받을 때 사용
@ModelAttribute 자동으로 모델 객체를 바인딩할 때 사용. 요청 파라미터를 객체에 바인딩함
@ResponseBody 메서드의 리턴값을 HTTP 응답 본문으로 전송할 때 사용. 주로 JSON/XML 응답 생성에 사용
@RequestBody HTTP 요청의 본문을 객체로 매핑할 때 사용. 주로 JSON이나 XML 데이터를 자바 객체로 매핑할 때 사용
@Repository DAO 클래스에 선언하여 데이터베이스 연산과 관련된 클래스를 명시함
@Service 비즈니스 계층의 서비스 클래스에 사용
@Scheduled 스프링에서 지원하는 배치 작업을 정의할 때 사용. 정해진 시간 또는 조건에 따라 메서드를 실행함

 

연결 순서

HTTP 요청이 들어오면 아래처럼 흐름이 이어짐

  1. @Controller → 사용자의 요청을 수신
  2. @RequestMapping 또는 @PostMapping, @GetMapping 등 → URL 매핑
  3. @RequestParam, @RequestBody, @ModelAttribute 등으로 요청 데이터 수신
  4. 내부적으로 @Service 호출 → 비즈니스 처리
  5. DB 작업은 @Repository에서 처리
  6. 결과를 View로 응답

회원 등록 시스템 예제(회원 가입 + 회원 수 출력)

  • 회원이 JSON 형식으로 회원가입 요청을 보냄
  • 컨트롤러에서 요청을 받아 서비스로 전달
  • 서비스는 DB에 저장 요청
  • DAO는 DB에 회원 정보 저장
  • 스케줄러가 매일 오전 9시에 회원 수를 출력

1. User 모델 클래스

public class User {
    private String name;
    private int age;
    private String email;

    // 생성자, getter, setter 생략
}

 

 

2. UserController — 사용자 요청 처리 컨트롤러

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;

@Controller // 컨트롤러 지정
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    // 사용자 등록
    @PostMapping("/users/register") // URL 매핑
    @ResponseBody // 문자열을 응답 본문으로 바로 반환
    public String registerUser(
        @RequestBody User user, // JSON 본문을 User 객체로 매핑
        @RequestHeader("User-Agent") String userAgent, // 요청 헤더 읽기
        @CookieValue(value = "ref", defaultValue = "none") String referral // 쿠키값
    ) {
        System.out.println("User-Agent: " + userAgent);
        System.out.println("Referral Code: " + referral);
        userService.register(user);
        return "회원가입 완료";
    }

    // 회원 ID로 정보 조회
    @GetMapping("/users/{userId}")
    @ResponseBody
    public User getUserById(@PathVariable("userId") Long id) {
        return userService.getUser(id); // PathVariable로 URL 경로에서 값 추출
    }

    // 쿼리 파라미터로 이름 검색
    @GetMapping("/users/search")
    @ResponseBody
    public String searchUser(@RequestParam("name") String name) {
        return "검색된 이름: " + name;
    }

    // 폼 방식으로 데이터 전달
    @PostMapping("/users/form-register")
    @ResponseBody
    public String formRegister(@ModelAttribute User user) { // 폼데이터 자동 바인딩
        userService.register(user);
        return "폼 등록 완료";
    }
}

 

3. UserService — 비즈니스 로직

import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;

@Service // 비즈니스 계층
public class UserService {

    private final UserRepository userRepository;
    private final Map<Long, User> cache = new HashMap<>();

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void register(User user) {
        userRepository.save(user);
    }

    public User getUser(Long id) {
        // 간단한 캐시 처리
        return cache.computeIfAbsent(id, userRepository::findById);
    }
}

 

4. UserRepository — DAO 계층

import org.springframework.stereotype.Repository;

@Repository // DB 작업 담당
public class UserRepository {

    // DB 연결은 생략, 단순 출력으로 대체
    public void save(User user) {
        System.out.println("DB에 저장: " + user.getName());
    }

    public User findById(Long id) {
        return new User("가짜이름", 20, "fake@email.com");
    }
}

 

5. UserScheduler — 배치 작업 처리 클래스

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class UserScheduler {

    // 매일 오전 9시에 실행
    @Scheduled(cron = "0 0 9 * * ?")
    public void printUserCount() {
        System.out.println("9시입니다. 현재 사용자 수를 확인하세요!");
    }
}

 

정리된 흐름 구조

  설명 Anotation
1 사용자가 /users/register로 JSON 요청 전송 @RequestBody, @RequestHeader, @CookieValue
2 컨트롤러가 요청 처리 @Controller, @RequestMapping, @ResponseBody
3 서비스 로직 실행 @Service
4 DAO에서 DB 저장 @Repository
5 /users/{id} 요청으로 사용자 조회 @PathVariable
6 /users/search?name=Kim 검색 @RequestParam
7 폼 전송시 사용자 등록 @ModelAttribute
8 매일 아침 9시 자동 실행 @Scheduled

▶ 데이터베이스 트랜잭션

트랜잭션의 개념 → 모델링 → 인터페이스 설계 → 세부 설계

 

1. 트랜잭션이란?

데이터베이스에서 하나의 작업 단위
예: “A가 B에게 1만 원을 송금하는 작업”

  • A의 계좌에서 1만 원을 차감
  • B의 계좌에 1만 원을 더함

이 두 작업은 무조건 함께 성공하거나, 함께 실패해야함.

 

2. 트랜잭션의 4가지 성질 (ACID)

  • Atomicity (원자성): 전부 성공하거나 전부 실패해야 함
  • Consistency (일관성): 트랜잭션이 실행된 후에도 데이터 무결성이 유지되어야 함
  • Isolation (격리성): 동시에 여러 트랜잭션이 실행되어도 서로 영향을 주지 않아야 함
  • Durability (지속성): 성공한 트랜잭션의 결과는 영구적으로 저장되어야 함

 

3. 예제 코드 (Java + SpringBoot + JPA)

@Service
public class BankService {

    @Autowired
    private AccountRepository accountRepository;

    // 트랜잭션 처리
    @Transactional
    public void transferMoney(Long fromId, Long toId, int amount) {
        // 1. 출금
        Account fromAccount = accountRepository.findById(fromId).orElseThrow();
        fromAccount.withdraw(amount);

        // 2. 입금
        Account toAccount = accountRepository.findById(toId).orElseThrow();
        toAccount.deposit(amount);

        // 3. 여기서 예외 발생하면 위 작업 모두 롤백됨
    }
}

 

4. 트랜잭션 모델링이란?

모델링 단계에서는 시스템에서 어떤 작업이 트랜잭션 단위가 될지를 정의함.

예시: 쇼핑몰에서 주문 처리 트랜잭션 모델링

  • 재고 차감
  • 결제 처리
  • 주문 내역 저장

이 세 가지 작업은 하나의 트랜잭션으로 묶어야 함 → 이게 트랜잭션 모델링

 

5. 트랜잭션 인터페이스 설계란?

트랜잭션을 처리할 Service 계층의 메서드 구조를 잡는 것

public interface OrderService {
    void placeOrder(OrderRequestDto request);
}

 

이 메서드 내부에서 다음 작업이 수행됨:

  • 재고 감소
  • 결제 처리
  • 주문 정보 저장

→ 즉, 트랜잭션의 인터페이스는 트랜잭션을 실행하는 비즈니스 로직의 입구

 

6. 트랜잭션 세부 설계란?

세부 설계는 트랜잭션을 이루는 세부 단위 작업을 구체적으로 정의하는 것

@Transactional
public void placeOrder(OrderRequestDto request) {
    // 1. 상품 재고 감소
    productService.reduceStock(request.getProductId(), request.getQuantity());

    // 2. 결제 처리
    paymentService.processPayment(request.getUserId(), request.getAmount());

    // 3. 주문 저장
    orderRepository.save(new Order(...));
}

- 각 단계의 세부 로직을 어떻게 구현할지, 예외 처리 시 어떤 방식으로 롤백할지까지 포함해서 설계하는 게 세부 설계임

 

예제 전체 흐름

public interface OrderService {
    void placeOrder(OrderRequestDto request);  // 트랜잭션 인터페이스
}

@Service
public class OrderServiceImpl implements OrderService {

    @Transactional  // 트랜잭션 처리 시작
    public void placeOrder(OrderRequestDto request) {
        // 세부 설계
        productService.reduceStock(request.getProductId(), request.getQuantity());
        paymentService.processPayment(request.getUserId(), request.getAmount());
        orderRepository.save(new Order(...));
    }
}

▶ 논리 - 물리 데이터 모델 변환

  • Entity를 Table로 변환
  • 속성을 컬럼으로 변환
  • Primary UID를 Primary Key로 변환
  • Secondary(Alternate) UID를 Unique Key로 변환
  • Relationship을 Foreign Key로 변환
  • Business Constraints를 Check Constraints로 변환

👉 논리 모델: "무엇을 저장할 것인가"에 집중 (개념적 모델)

👉 물리 모델: "어떻게 저장할 것인가"에 집중 (현실에 적용되는 구조)

 

1. Entity → Table

  • Entity(엔티티): 현실 세계의 개념적인 객체 (예: 고객, 주문)
  • Table(테이블): 데이터베이스에 실제로 저장되는 표 형태의 구조
  • 변환 이유: 실제로 데이터를 저장하려면 테이블 형태로 만들어야 하니까

2. 속성 → 컬럼

  • 속성(Attribute): 엔티티의 특성 (예: 고객 이름, 주문일자)
  • 컬럼(Column): 테이블에서 실제 데이터가 저장되는 필드
  • 변환 이유: 속성들이 테이블에 저장될 공간이 필요하므로 컬럼으로 바뀜

3. Primary UID → Primary Key

  • Primary UID(식별자): 각 엔티티 인스턴스를 구별하는 고유한 속성
  • Primary Key(기본 키): 테이블에서 각 행을 유일하게 식별하는 컬럼
  • 변환 이유: 테이블에서도 고유값으로 각 행을 구분해야 하기 때문

4. Secondary UID → Unique Key

  • Secondary UID(보조 식별자): Primary는 아니지만 유일한 값을 갖는 속성
  • Unique Key(유일 키): 중복이 허용되지 않는 컬럼
  • 변환 이유: 특정 컬럼이 중복되지 않도록 제약을 걸기 위해 사용

5. Relationship → Foreign Key

  • Relationship(관계): 두 엔티티 간의 연결 (예: 주문은 고객과 관련 있음)
  • Foreign Key(외래 키): 한 테이블이 다른 테이블의 Primary Key를 참조함
  • 변환 이유: 테이블 간의 연결 관계를 표현해야 하므로 외래 키로 구현

6. Business Constraints → Check Constraints

  • Business Constraints(업무 제약조건): 업무 규칙 (예: 수량은 0보다 커야 함)
  • Check Constraints(체크 제약조건): 조건을 설정해 데이터 유효성 보장
  • 변환 이유: 잘못된 데이터가 들어오지 않게 DB에서 직접 제한할 수 있도록 함

 

▶ 가상테이블 뷰

1. 복잡한 쿼리 재사용 및 간소화

  • 예를 들어, 5개의 테이블을 조인해서 만들어야 하는 결과가 있다고 해봐.
  • 이걸 자주 써야 한다면 매번 긴 SQL을 복붙하는 건 비효율적
  • 이럴 때 뷰를 만들어두면 SELECT * FROM order_summary_view;처럼 간단하게 사용 가능

2. 보안과 접근 제어

  • 사용자가 전체 테이블을 보면 안 되는 경우가 있음. 예를 들어 salary나 admin_flag 같은 필드는 숨겨야함
  • 뷰를 통해 보여줄 필드만 노출하면 테이블 전체를 직접 접근하지 않아도 됨
CREATE VIEW public_employee_info AS
SELECT name, department
FROM employees
WHERE role != 'admin';
//이렇게 하면 뷰를 통해 보는 사람은 이름이랑 부서밖에 못봄

3. 읽기 전용 데이터 제공

  • 데이터를 직접 수정하면 안 되는 상황에서, 뷰를 통해 읽기 전용 인터페이스처럼 쓸 수 있음
  • 특히 복잡한 보고서, 분석용 데이터 등은 뷰로 만들어두면 실수로 데이터 변경하는 일도 막을 수 있음

4. 유지보수 및 설계 유연성

  • 테이블 구조가 바뀌더라도 뷰 구조는 동일하게 유지 가능함
  • 애플리케이션은 뷰만 보고 작동하니까, 내부 DB 설계가 바뀌어도 앱 로직 수정 없이 계속 쓸 수 있음

5. 성능 최적화 (경우에 따라)

  • 일부 DBMS는 물리적 뷰(materialized view)를 제공해서 뷰 결과를 캐싱해둬서 성능을 높일 수 있음
  • 단, 일반 뷰는 단순 SQL 재사용일 뿐, 성능 향상 목적은 아님

6. 예제

-- 주문 테이블
CREATE TABLE orders (
    order_id INT,
    customer_id INT,
    product_name VARCHAR(50),
    amount INT
);

-- 고객 테이블
CREATE TABLE customers (
    customer_id INT,
    customer_name VARCHAR(50)
);

 

- 뷰를 만들지 않고 매번 조인해서 사용하는 방식 (안 쓸 때)

-- 고객 이름과 주문 내역을 보고 싶을 때
SELECT o.order_id, c.customer_name, o.product_name, o.amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.amount > 100;
  • 이 긴 쿼리를 계속 반복해서 써야 함
  • 유지보수 힘듦 (조인 방식 바뀌면 전부 수정해야 함)

- 뷰를 만들어서 사용하는 방식 (쓸 때)

-- [설명] 뷰를 만들어두면 복잡한 쿼리를 이름으로 재사용 가능함

CREATE OR REPLACE VIEW high_value_orders AS
SELECT o.order_id, c.customer_name, o.product_name, o.amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.amount > 100;
  • OR REPLACE는 같은 이름의 뷰가 있으면 덮어씀
  • 에러 없이 기존 뷰를 업데이트할 수 있음 (DROP 안 해도 됨)

비교

항복 뷰 안 쓸 때 뷰 쓸 때
재사용성 없음, 매번 쿼리 작성 높음, SELECT 한 줄로 끝
가독성 복잡한 쿼리 반복 간단한 이름으로 호출
보안 전체 테이블 접근 필요 필요한 정보만 제한 노출 가능
유지보수 모든 쿼리 수정 필요 뷰 하나만 수정하면 반영됨
실행 성능 동일 (뷰도 결국 쿼리임) 단, 머티리얼라이즈드 뷰는 캐싱 가능

 

▶ 관계대수, 관계해석, SQL SELECT

1. 관계대수(Relational Algebra) = "절차 중심"

어떻게 데이터를 찾을지를 단계별로 절차적으로 말해주는 방식

 

예시 비유

  • "냉장고에서 우유를 꺼내려면 → 문 열고 → 맨 오른쪽 선반 보고 → 우유 꺼내"
  • 데이터를 어떻게 꺼낼지 알고리즘처럼 말함

관계대수 구문 예시 (σ: 선택, π: 투영, ⨝: 조인)

π name (σ department='영업부' (Employee))
  • '영업부' 직원만 고르고 → 이름만 출력

2. 관계해석(Relational Calculus) = "선언 중심"

무엇을 원하는지 조건만 말하는 방식, 절차는 신경 안 씀

 

예시 비유

  • "나는 영업부 직원 이름을 원해"
  • 어떻게 가져올지는 DB가 알아서 결정

관계해석 구문 예시 (튜플 관계 해석)

{ e.name | Employee(e) AND e.department = '영업부' }
  • 'e'는 Employee의 튜플이고
  • 조건을 만족하는 e의 name만 가져와

3. SQL SELECT문 = "관계해석 기반 + 관계대수 절차 가미"

선언형처럼 보이지만, 내부적으로는 관계대수처럼 동작
그래서 SQL은 관계해석을 바탕으로 한 언어지만, DBMS는 내부에서 관계대수로 처리함

 

SQL 예시

SELECT name FROM Employee WHERE department = '영업부';
  • 보는 입장에선 선언형: “이 조건 만족하는 name 달라”
  • 실제 동작은 절차적: 필터 → 컬럼 추출 순서로 처리함(내부적으로 "관계대수"라는 절차적 언어로 바꿔서 실행)

4. 정리

항목 관계대수 관계해석 SQL (SELECT)
방식 절차적 선언적 선언적 (내부는 절차적)
무엇에 초점 어떻게 구할까 무엇을 원하나 무엇을 원하나 (자동 최적화)
난이도 알고리즘적 수학적 논리 느낌 쉬움 (실무용)
실무 사용 × (이론 전용) × (이론 전용) O (우리가 쓰는 SQL)
  • 관계대수: 데이터를 어떻게 가져올지 단계적으로 지시
  • 관계해석: 필요한 데이터 조건만 정의하고 방법은 신경 안 씀
  • SQL SELECT: 조건만 쓰지만, 내부는 관계대수처럼 실행됨

5. 관계대수/관계해석을 배우는 이유

1) SQL의 본질과 동작 방식 이해

  • SQL을 잘 쓰려면, 백엔드에서 어떤 일이 벌어지는지 이해해야 함
  • 어떤 조건이 선 필터링되고, 어떤 조건이 조인 후 필터링되는지 안 보이면 성능 튜닝 못 함

2) 쿼리 최적화와 실행 순서 파악

이 쿼리

SELECT name FROM Employee WHERE department = '영업부';

SELECT name FROM (SELECT * FROM Employee WHERE department = '영업부');

결과는 같지만, 내부 처리 순서가 달라질 수 있음.

→ 관계대수 관점에서 보면, 필터 후 projection이 빠름
→ 반대로 하면 불필요한 데이터가 메모리에 오래 남음 → 느려짐

 

3) DB 설계와 질의 최적화

  • 실제 실무에서도 성능 이슈 날 때 EXPLAIN 실행계획 보고 튜닝하는데
  • 관계대수 개념이 있어야 인덱스 언제 쓰이고 안 쓰이는지, 조인이 어떻게 최적화되는지 이해 가능함

스키마(Schema)

1. 스키마는 '설계도'다.

건물을 짓기 전에 그려놓는 도면처럼, 어떤 데이터가 어떤 식으로 저장될지 정해놓는 설계 문서임

예를 들어, 우리가 '고객 정보'를 저장하려고 한다면, 이렇게 생긴 표가 필요할 수 있음

|       고객번호       |          이름           |          전화번호           |          주소         |

이런 표를 테이블(table)이라고 하고, 이 테이블이 어떤 칸(컬럼, 즉 "필드")으로 구성되는지 정의한 게 바로 스키마임

2. 스키마는 무엇을 정의할까?

테이블 이름 | 컬럼의 이름과 타입 | 기본키,외래키 | 제약 조건

 

1) 테이블 이름

  • 예: Customer, Product, Order

2) 컬럼(열)의 이름과 타입

  • 예: 이름(name)은 글자(String), 가격(price)은 숫자(Number), 날짜(created_at)는 날짜(Date)

3) 키(Primary Key, Foreign Key)

  • Primary Key (기본키): 데이터의 고유한 식별자 (예: 고객번호)
  • Foreign Key (외래키): 다른 테이블과 연결된 키 (예: 주문 테이블의 고객번호 → 고객 테이블과 연결)

4) 제약 조건(Constraints)

  • 예: 이름은 꼭 있어야 한다(NOT NULL), 나이는 0보다 커야 한다(CHECK)

3. 예시

CREATE TABLE Customer (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    phone VARCHAR(20),
    address TEXT
);

 

이건 "Customer"라는 테이블을 만드는 SQL 문장으로 스키마의 한 부분
여기서 설계한 내용은 다음과 같다:

  • customer_id: 숫자고, 중복되면 안 되는 고유 ID
  • name: 글자 100자까지 가능, 반드시 입력해야 함
  • phone, address: 전화번호, 주소

4. 왜 중요한가?

  • 데이터를 일관성 있게 저장하기 위해
  • 데이터 구조를 팀원들이 공통으로 이해하기 위해
  • 프로그램이 데이터를 신뢰하고 처리할 수 있게 하기 위해

5. 스키마 3계층(외부-개념-내부)

  • 외부 스키마: 사용자(또는 앱)가 보는 데이터 모습
  • 개념 스키마: 전체 데이터베이스의 논리적 설계
  • 내부 스키마: 데이터가 실제로 저장되는 방식

1) 외부 스키마 (External Schema)

사용자가 도서관에서 책을 빌릴 때, "제목, 저자, 대출 가능 여부"만 보는 것

- "회원"은 책 제목, 저자만 볼 수 있음

- "관리자"는 가격, 입고일 등 더 많은 정보도 볼 수 있음

  • 사용자마다 필요한 정보만 보여줌
  • 여러 외부 스키마가 있을 수 있음 (예: 직원용, 일반 사용자용)

2) 개념 스키마 (Conceptual Schema)

도서관 전체에 어떤 정보(책, 대출 기록, 회원 정보 등)를 저장하는지 정의하는 것

- 책(Book), 회원(Member), 대출(Loan) 테이블이 어떻게 연결되는지

- 어떤 속성들이 있는지 정의

  • 데이터 전체의 논리적인 구조
  • 테이블 관계, 제약 조건 등을 포함

3) 내부 스키마 (Internal Schema)

책이 실제로 도서관 어디 선반에, 어떤 방식으로 저장돼 있는지를 설계하는 것

- 어떤 책이 어느 선반에, 어떤 분류로 저장되는지

- 데이터를 빠르게 검색하기 위해 인덱스를 걸어놓는다든가

  • 데이터가 물리적으로 저장되는 방식
  • 인덱스, 파일 포맷, 저장 경로 등

정리

구분 설명 예시
외부 스키마 사용자/앱이 보는 데이터 구조 고객용 뷰, 관리자용 뷰
개념 스키마 전체 데이터의 논리적 설계 전체 ERD 구조
내부 스키마 데이터 저장의 실제 구현 (물리적 구조) 인덱스, 저장 파일 구조

왜 나누는 걸까?

  • 시스템을 유지보수하기 쉽게 만들기 위해
  • 내부 구조를 바꿔도 사용자 화면은 그대로 유지되게 하기 위해
  • 보안과 최적화를 각각 다르게 적용하기 위해

📍3계층 스키마 vs 데이터베이스 설계 3단계

구분 3계층 스키마 구조 데이터베이스 설계 3단계
초점 "시스템이 데이터에 접근하는 방식" "데이터를 어떻게 만들고 구조화할지"
관점 사용자 ↔ 시스템 내부 구조 설계자 입장에서 데이터 생성 단계
단계 외부 / 개념 / 내부 스키마 개념 / 논리 / 물리 설계

1) 3계층 스키마 구조

시스템이 어떻게 데이터를 표현하고 저장할지 구분하는 구조
- 데이터 표현을 계층화해서 독립성 보장 (화면은 그대로, 내부 구조만 변경 가능)
  • 외부 스키마: 사용자 입장에서 보이는 데이터 (뷰)
  • 개념 스키마: 전체 데이터베이스 구조 (ERD, 관계 등)
  • 내부 스키마: 실제 저장 구조 (파일, 인덱스, 저장소)

2) 데이터베이스 설계 3단계

설계자가 처음부터 DB를 어떻게 만들지 순서대로 구성하는 과정
- 현실 세계의 정보를 어떻게 정확하고 성능 좋게 데이터베이스로 구현할지 설계
  • 개념 설계: ERD 그리기, 엔터티와 관계 정의
  • 논리 설계: 테이블/컬럼/키 설계 (RDBMS에 맞게)
  • 물리 설계: 인덱스, 파티션, 저장소 구조 등 성능 최적화

정리

항목 3계층 스키마 DB 설계 3단계
중심 질문 "어떻게 저장하고 보여줄까?"
( 데이터 표현 방식)
"어떻게 만들어야 할까?"
(데이터 만드는 과정)
건물 비유 건물 도면(설계도), 사용자의 시각, 내부 배선
기획 → 설계도 작성 → 시공 작업
사용 시점 DB가 작동할 때 적용 DB를 만들기 전에 적용
결과물 사용자 뷰, 저장 구조 ERD, DDL 스크립트, 인덱스 설정

참고

더보기

Q1: DB 설계 단계에서 ERD는 어느 단계에 포함될까?

정답: 개념 설계 단계
- ERD(Entity-Relationship Diagram)는 현실 세계의 개체(사람, 상품, 주문 등)와 이들 사이의 관계(소유, 구매 등)를 시각적으로 표현한 거야.
- 개념 설계는 "무엇을 저장할지"에 집중하는 단계라서, ERD를 작성하는 것이 핵심 작업이야.

예시:
고객(Customer), 주문(Order), 상품(Product)이 있다면
→ 각각을 엔터티로,
→ 고객이 주문한다, 주문이 상품을 포함한다는 관계를 관계(Relationship)로 표현

요약:
- ERD는 개념 설계의 핵심 도구
- 아직 RDBMS(SQL, MySQL 등)에 맞게 테이블로 변환하지 않은 상태

Q2: 내부 스키마와 물리 설계는 어떻게 연결되어 있을까?


정답: 내부 스키마 = 물리 설계의 구현 결과

  • 내부 스키마는 데이터가 실제로 어떻게 저장되는지를 시스템 관점에서 표현한 것이고,
  • 물리 설계는 설계자 입장에서 성능과 저장 공간을 고려해서 저장 방식을 결정하는 것이야.

즉,
물리 설계에서 결정한 내용
→ 인덱스를 어떻게 걸고, 어떤 칼럼에 파티션을 나누고, 어떤 형식으로 저장할지
→ 이것이 내부 스키마에 반영되어 구현되는 거야.

예시:
물리 설계자가 “상품 테이블의 상품명 컬럼에 인덱스를 걸자”고 하면
→ 내부 스키마에서는 그 인덱스를 활용한 실제 저장 구조를 정의하고 운영에 반영함

'개발인생 > Certificate' 카테고리의 다른 글

정처기 실기[기출1]  (0) 2025.04.18
정처기 실기[이론3]  (0) 2025.04.16
정처기 실기[이론-정보보안]  (0) 2025.04.16
정처기 실기[이론1]  (8) 2025.04.08
정처기 실기[프로그래밍언어]  (1) 2025.04.08