Skip to content
Open
120 changes: 120 additions & 0 deletions Database/인덱스를 사용하는 이유(장단점).md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 인덱스를 사용하는 이유(장단점)
## 요약
> 인덱스는 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조입니다.
> 사용 시 테이블 조회 속도를 높여 DB 성능을 향상시키며, Full Scan하지 않아 시스템 부하를 줄여줍니다.
> 하지만 항상 정렬된 상태로 유지해야하기에 추가적인 쓰기작업이 필요하며 이를 저장하기 위한 저장공간이 필요합니다. 때문에 잘못 사용할 경우 성능 저하의 역효과를 발생시킵니다.


## 인덱스(Index)란?
- 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조.
- 추가적인 쓰기 작업과 저장공간을 활용
-> 이를 관리하기 위해 DB에 ~~약 10%에 해당하는~~ 저장공간 필요
- **PK는 자동으로 Index가 생성됨** -> NHN 기출
![인덱스 구조](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/index_structure.png?raw=true)

> 인덱스 없이 조회하면 모든 튜플(레코드)를 검색하지만 인덱스를 사용한다면 인덱스를 탐색하고 일치할 시에 해당 튜플로 데이터를 검색. -> 속도 **up**


## 인덱스를 사용하는 이유
- 인덱스 테이블은 데이터들이 정렬되어 있음! -> **정렬과 연관지어 기억하자**

### 조건 검색 Where 절의 효율성
- 인덱스 테이블은 데이터들이 정렬되어 저장되어 있기 때문에 해당 조건(where)에 맞는 데이터를 빠르게 찾아낼 수 있음

### 정렬 Order by 절의 효율성
- 이미 정렬되어 있기 떄문에 order by에 의한 Sort과정을 피할 수 있음

### MIN, MAX의 효율적인 처리 가능
- MIN값과 MAX값을 레코드의 시작값과 끝 값 한 건씩만 가져오면 되기에 Full Scan보다 효율적


## 인덱스의 장단점
### 장점
- 테이블을 조회하는 속도와 그에 따른 성능을 향상
- 전반적인 시스템의 부하를 줄임(Full Scan을 안해서)

### 단점
- 인덱스를 관리하기 위해 DB의 ~~약 10%에 해당하는~~ 추가적인 저장공간 필요
- 인덱스를 관리하기 위해 추가 작업 필요
- 잘못 사용할 경우 성능 저하의 역효과 발생


## 인덱스 관리
- Index를 항상 **최신의 데이터를 정렬된 상태로 유지**해야 원하는 값을 탐색 할 수 있음
- INSERT, UPDATE, DELETE(데이터 추가, 수정, 삭제) 수행 시 정렬 필요! -> 부하**UP**
- INSERT, UPDATE, DELETE 시 추가적인 연산 필요
-> 부하를 최소화하기 위해 데이터 삭제라는 개념에서 **인덱스를 사용하지 않는다** 라는 작업으로 대신함
- INSERT : 새로운 데이터에 대한 인덱스 추가
- DELETE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 진행
- UPDATE : 기존의 인덱스를 사용하지 않음 처리, 갱신된 데이터에 대한 인덱스 추가


## 인덱스 생성 전략
- 조건절에 자주 등장하는 컬럼(호출 빈도가 높음)
- 같거나 크고, 작음으로 자주 사용되는 컬럼(where 또는 order by에서 쓰이는 컬럼)
- 중복되는 데이터가 최소한인 컬럼(분포도가 좋다 = 데이터가 서로 다르고 넓게 퍼져 있다)
- 조인 조건으로 자주 사용되는 컬럼


## 인덱스 자료구조
### 해시테이블
- key : 데이터(= 컬럼의 값)
- value : 데이터의 위치
- 장점
- 빠른 데이터 탐색에 유용
- 시간 복잡도 O(1)
- 단점
- 등호 연산에만 특화
- DB는 부등호(>, <) 연산이 많아서 **사용 부적합**
![인덱싱_해쉬](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/indexing_hash.png?raw=true)

## B+ Tree
- 대부분의 DB 인덱싱 자료구조
- 특징
- 리프노드에만 인덱스와 함께 데이터를 갖고있고, 나머지 노드들은 인덱스만을 가짐
- 리프노드들은 연결리스트로 이루어짐 -> 탐색이 0번노드부터 일어나는 연결리스트에 비해 시간 효율이 좋음!(log2(N))
- 데이터 노드의 크기는 인덱스 노드와의 크기와 같지 않아도 됨
- 예시
- 인덱스
![인덱싱_B+Tree1](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/indexing_b%2Btree1.jpeg?raw=true)

- B+ Tree
![인덱싱_B+Tree2](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/indexing_b%2Btree2.jpeg?raw=true)

> BTree : 모든 노드에 데이터를 담음
> 리프노드 : 자식이 없는 노드. 잎이라고도 함
> B+ Tree 알고리즘에 대해서는 추후 정리할 예정입니다.



## TMI : 결합 인덱스
- 두 개 이상의 컬럼을 합쳐서 인덱스를 만드는 것
- 단일 컬럼으로는 분포도가 나쁘지만, 여러 개의 컬럼을 합친다면 좋은 분포도를 가지며, where절에서 and 조건에 많이 사용되는 컬럼을 결합 인덱스로 생성함

### 결합 인덱스 컬럼 생성 전략
- where절에서 and 조건으로 자주 결합되고, 결합할 시 분포도가 좋아지는 컬럼
- 다른 테이블과 조인의 연결고리로 자주 사용되는 컬럼
- order by에서 자주 사용되는 컬럼
- 하나 이상의 키 컬럼 조건으로 같은 테이블의 컬럼들이 자주 조회될 때

### 예시
- 결합 인덱스 생성 예시
`create index emp_pay_idx on emp_pay(급여년월, 급여코드, 사원번호);`
- 결합 인덱스 사용 예시
```
select * from emp_pay where 급여년월 = '202107';
select * from emp_pay where 급여년월 = '202107' and 급여코드 = '정기급여';
select * from emp_pay where 급여년월 = '202107' and 급여코드 = '정기급여' and 사원번호 = '20210401';
```

> 단 급여코드만을 검색할 때는 결합 인덱스의 첫 번째 컬럼인 급여년월의 조건식이 없기 때문에 결합 인덱스로 조회하지 않음! -> 급여년월, 급여코드, 사원번호의 순서대로 조회
- 결합 인덱스 효율성 감소
1. LIKE 검색 : 2021%같이 검색할 경우 2021에 해당하는 모든 급여코드, 정기급여로 생성된 결합 인덱스를 조회해서 B*Tree에서 조회하기 어려움
2. 결합 인덱스 칼럼 순서(이하 급여년월(1), 급여코드(2), 사원번호(3) 컬럼을 숫자로 말하겠습니다)
- 1, 3 / 2 / 2, 3 / 3 으로 조회할 경우 결합 인덱스 순서대로 조회하지 않아서 Full Scan이 발생합니다


- 출처
- [Database 인덱스(index)란? - MangKyu’s Diary](https://mangkyu.tistory.com/96)
- [DB 데이터베이스 인덱스(Index) 란 무엇인가?](https://coding-factory.tistory.com/746)
- [자료구조 그림으로 알아보는 B+Tree](https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Plus-Tree)
Binary file added Spring/.DS_Store
Binary file not shown.
157 changes: 157 additions & 0 deletions Spring/Spring MVC 동작 방식.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Spring MVC 동작 방식
## 요약
- Spring MVC는 DespatcherServlet, HandlerMapping, HandlerAdapter, ViewResolver로 동작한다
- Spring MVC Annotation을 알아보자

## Spring MVC 핵심 구성 요소
### DispatcherServlet
- 스프링 부트 구동 시 DispatcherServlet을 서블릿으로 자동등록(urlPatterns=“/“)
- 클라이언트로부터 어떠한 요청이 들어오면 Tomcat과 같은 서블릿 컨테이너가 요청을 받음 -> 이 모든 요청을 DispatcherServlet이 받게 됨
- 즉, HTTP 프로토콜로 들어오는 모든 요청을 처리 -> 장점
> 모든 요청을 가장 먼저 받기 때문에 Front Controller이라고도 함

### HandlerMapping
- 클라이언트의 요청을 처리할 컨트롤러 탐색
- URL에 매핑된 핸들러(컨트롤러) 조회

### HandlerAdapter
- 실제 핸들러를 실행시키며, 핸들러의 처리 결과를 ModelAndView로 변환

### ViewResolver
- 컨트롤러 처리 결과를 JSP를 이용해서 생성하기 위해 사용
- View의 논리 이름을 물리 이름으로 바꾸고 렌더링 역할을 담당하는 뷰 객체 반환

> Handler(핸들러)? : 웹 요청을 실제로 처리하는 객체, Spring MVC입장에서 @Controller 객체나 Controller 인터페이스를 구현한 객체 모두를 말함.

### 스프링 MVC 동작 순서
![스프링 MVC 동작](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Spring/%E1%84%89%E1%85%B3%E1%84%91%E1%85%B3%E1%84%85%E1%85%B5%E1%86%BCMVC%E1%84%83%E1%85%A9%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%A8.jpg?raw=true)

### RestController
![RestController 동작](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Spring/restcontroller%E1%84%83%E1%85%A9%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%A8.jpg?raw=true)

- 1 ~ 5는 Spring MVC와 동일
- 6. 컨트롤러가 ResponseEntity를 반환
- 7. HandlerAdapter가 반환받은 ResponseEntity를 통해 Response 처리 진행
- 8. 서버의 응답을 클라이언트로 반환

## 요청의 흐름
### Servlet
- 서블릿 호출 시 HttpServlet이 제공하는 service() 메서드 호출
- service()를 시작으로 여러 메소드가 실행, DispatcherServlet.doDispatch()가 호출

### DispatcherServlet
```
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

try {
ModelAndView mv = null;
Exception dispatchException = null;

try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// 1. 핸들러 조회
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// 2. 핸들러 어뎁터 조회
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 3. 헨들러 어댑터 실행 -> 4. 핸들러 어댑터를 통해 핸들러 실행 -> 5. ModelAndView 반환
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
catch (Exception ex) {
dispatchException = ex;
}

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
// ........이하 생략
}
}

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {

boolean errorView = false;
// 7. 뷰 렌더링 호출
render(mv, request, response);
}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);

View view;
String viewName = mv.getViewName();
// 8. 뷰 렌더링
view.render(mv.getModelInternal(), request, response);
}


```

## Spring MVC Annotation
### @RequestMapping
- HandlerMapping과 HandlerAdapter의 역할
- 요청 정보를 매핑, 해당 URL 호출되면 이 메소드가 호출

### @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
- Rest API 형식의 CRUD(c = p, r = g, u = p, d = d)
- @RequestMapping의 세부 url 매핑

### @RequestBody
- **Json(application/json)형태**의 HTTP Body 내용을 Java Object로 변환
- 데이터는 MessageConvert를 통해 Java객체로 변환
- 객체의 기본 생성자를 통해 객체를 생성하고, 내부적으로 Reflection을 사용해 값을 할당하므로 값을 주입하기 위한 **생성자나 Settr가 필요 없음**
> 데이터를 Java 객체로 변환하기 때문에 값 주입 생성자나, Setter가 필요 없음

### @RequestParam
- 1개의 HTTP 요청 파라미터를 받기 위해 사용, 파라미터 이름으로 바인딩
- @RequestParam(“userid”) String userID -> request.getparameter(“userid”)
- 선언 시 필수적으로 보내야하며, 필수 변수가 아니라면 required = false로 설정 가능

### @ModelAttribute
- **multipart/form-data 형태**의 HTTP Body 내용과 HTTP 파라미터의 값들을 **생성자나 Setter를 통해** 주입해줌
- HTTP Body 데이터와 HTTP 파라미터들을 Setter를 통해 1대1로 객체에 바인딩
- Reflection으로 검증하기 때문에 모든 값을 받는 생성자가 없다면, 이외의 값은 Setter로 주입됨
> 데이터를 1대1로 객체에 바인딩하기 때문에 값 주입 생성자나, Setter가 필요

### @RequestPart
- multipart/form-data 형태의 요청이 올 때 사용
- File과 DTO를 같이 받을 수 있음
```
@PostMapping("")
public String insertUser(
@RequestPart(value = "file") MultipartFile multipartFile,
@RequestPart(value = "userInfo") UserInfo userInfo) {
}
```

### @PathVariable
- URL의 파라미터를 매핑

### @ResponseBody
- 해당 메소드의 결과를 ModelAndView가 아닌 JSON으로 반환

### @RestController
- 컨트롤러의 모든 메소드를 View가 아닌 Json으로 반환





## 출처
- [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard)
- [SpringDispatcher-Servlet(디스패처 서블릿)이란? 디스패처 서블릿의 개념과 동작 과정 - MangKyu’s Diary](https://mangkyu.tistory.com/18)
- [Spring MVC 기본 어노테이션과 Lombok 정리하기 :: Gyun’s 개발일지](https://devlog-wjdrbs96.tistory.com/401)
- [Spring Annotation 정리](https://velog.io/@gillog/Spring-Annotation-%EC%A0%95%EB%A6%AC)
Loading