---
# System prepended metadata

title: 6월 16일 스터디

---

# 6월 16일 스터디
## 최지수
### 인덱스 스캔의 종류
- Range Scan
    인덱스 루트 블록에서 리프 블록까지 수직적으로 탐색한 후에 리프 블록을 필요한 범위만 스캔하는 방식
    B+Tree의 가장 일반적이고 정상적인 엑세스 방식
    인덱스를 구성하는 선두 컬럼이 조건절에 사용되어야 가능하다.
    이 스캔 과정을 거쳐 생성된 결과 집합은 인덱스 컬럼 순으로 정렬을 생략하거나 min, max값을 빠르게 추출 가능
- Full Scan
    수직적 탐색 없이 리프 블록을 처음부터 끝가지 수평적으로 탐색하는 방식
    최적의 인덱스가 없을 때 차선으로 선택
- Unique Scan
    수직적 탐색만으로 데이터를 찾는 방식
    작동시점 - unique인덱스를 통해 '=' 조건으로 탐색하는 경우
    중복되지 않는 unique한 값을 '=' 조건으로 검색할 경우 데이터 하나를 찾는 순간 더이상 탐색하지 않음
- Skip Scan
    조건절에 빠진 인덱스 선두 컬럼의 distinct value 개수가 적고 후행 컬럼의 distinct value 개수가 많을 때 사용
    루트 또는 브랜치 블록에서 읽은 컬럼 값 정보를 이용해 조건에 부합하는 레코드를 포함할 가능성이 있는 리프 블록만 골라서 액세스 하는 방식
    첫 번째 리프 블록과 마지막 리프 블록은 항상 방문
    인덱스의 전체 조건을 이용하지 않고 부분적으로 이용할 경우 사용

### B+Tree 인덱스 동작 과정
B+Tree는 Root - Branch - Leaf로 이루어져 있다.
수직적 탐색을 통해 인덱스 스캔 시작 지점을 찾고 수평적 탐색으로 데이터를 찾는다.

**수직적 탐색**
수평적 탐색을 위한 시작 지점을 찾는 과정이다.
찾고자 하는 값이 들어가 있을 범위를 찾아 하위 블록으로 이동한다.
이 과정을 반복하면서 하위 블록에서 조건을 만족하는 첫 번째 레코드를 찾는 과정이다.
루트 블록에서 리프 블록까지 아래 쪽으로 탐색을 진행하기 때문에 수직적 탐색이라고 한다.

**수평적 탐색**
수직적 탐색을 통해 스캔 지점을 찾고 난 후 리프 블록을 수평적으로 스캔하면서 데이터를 찾는 과정이다.
리프 블록끼리는 서로 앞 뒤 블록에 대한 주소 값을 가지고 있기 때문에 수평적인 탐색이 가능하다.
탐색을 하다가 해당 범위를 넘어서는 값을 만나면 멈춘다.


---

## 문예지
### call by value vs call by reference
> **js data type**
> 
- 기본 데이터 타입: null, number, string, boolean, undefinded, symbol(ES6에 추가)
- objects: Array, Object

>**call by value**
>

js의 기본 데이터 타입은 변경 불가능함(immutable) + 이들 값은 런타임(변수 할당 시점)에 메모리의 스택 영역(Stack Segment)에 고정된 메모리 영역을 점유하고 저장

```javascript=
let a = 1;
let b = a; // a, b는 서로 다른 메모리 주소 참조

console.log(a, b);    // 1  1
console.log(a === b); // true

a = 10;
console.log(a, b);    // 10  1
console.log(a === b); // false
```


>**call by reference**
>

값이 아닌 참조(모두 동일한 위치)로 전달
기본 데이터가 아닌 유형(non-primitive data type)의 변수를 함수의 매개 변수로 전달되면, 원래 변수의 참조가 업데이트

```javascript=
let nameObj = { name: '1111' } 

function changeName(nameObj) { 
    return nameObj.name = '2222'
} 

console.log(changeName(nameObj)) // 2222
console.log(nameObj) // 2222

```

<br>

> 작은 오해와 진실
> 

```javascript=
let obj = { p1: 10 }
let copy = obj
console.log(obj === copy)

copy = { p2: 100 }
console.log(obj === copy)

```

위 코드에 대한 내 예상
true
true

이유
![](https://i.imgur.com/uiQwIWs.png)

아니었다 :arrow_right: 재할당!

```javascript=
let obj = { p1: 10 }
let copy = obj
console.log(obj === copy) // true

copy = { p2: 100 }
console.log(obj === copy) // false

```

![](https://i.imgur.com/wL1RgUs.png)

내가 생각한대로 바뀌는건 요거

![](https://i.imgur.com/wCWkcOC.png)

<br>

### Nodejs의 내부 동작
![](https://i.imgur.com/GNZcKIn.jpg)

<br>

> 이벤트루프가 왜 중요한가?
> 
- 이벤트루프는 메인스레드 겸 싱글스레드로서, 비즈니스 로직을 수행 
- 수행 도중에 블로킹 IO작업을 만나면 커널 비동기 또는 자신의 워커 쓰레드풀에게 넘겨주는 역할
- 동시에 많은 요청이 들어온다해도 1개의 이벤트루프에서 처리
- JS로직(if분기, 반복문 등)이 무겁다면 많은 요청을 처리해내기 힘들 것 
- 이벤트루프가 바쁘면(= cpu인텐시브 작업) 메모리가 부족해서 뻗을 것

<br>

> libuv는 어떻게 동작하는가?
> 

- libuv는 윈도우 커널, 리눅스 커널을 추상화해서 wrapping 
- Nodejs는 기본적으로 libuv 위에서 동작하며, Node 인스턴스가 뜰 때, libuv에는 워커 쓰레드풀(default 4개)이 생성
- 블로킹 작업(api콜, DB Read/Write 등)들이 들어오면 이벤트루프가 uv_io에게 넘김 
- libuv는 커널단에서 어떤 비동기 작업들을 지원해주는지 알고 있기때문에, 그런 종류의 작업들을 받으면, 커널의 비동기 함수들을 호출 
- 작업이 완료되면 시스템콜을 libuv에게 넘김 
- libuv 내에 있는 이벤트루프에게 콜백으로서 등록
- libuv의 워커쓰레드는 커널이 지원안하는 작업들을 수행

<br>

> 이벤트루프의 내부 동작과정
> 
**이벤트루프의 phase**
이벤트루프는 몇 개의 phase 들로 구성 
각 phase 들은 FIFO 큐를 가지고 있으며, 이 큐에는 특정 이벤트의 콜백들을 넣고, CPU가 할당(=이벤트루프가 해당 phase를 호출할때)될 때 실행

- timers
    - setTimeout()과 setInterval() 과 같은 타이머 콜백 처리
    - 타이머 콜백들을 받고 이걸 poll 큐에 등록
    - 타이머 콜백 내부로직들은 poll큐에 먼저 등록된 콜백들이 처리되고 나중에 처리될 수도 있으므로, 파라미터로 지정한 시간에 딱 실행됨을 보장하지 못함

- I/O callbacks
    - 클로즈 콜백, 타이머로 스케줄링된 콜백, setImmediate()를 제외한 거의 모든 콜백들을 집행

- idle, prepare
    - 내부용으로만 사용 (모든 큐가 비어있으면 idle이 되면서 tick frequency가 떨어짐 = 할 일도없으니 이벤트루프가 천천히 돎)
- poll
    - poll 큐가 비어있음 : setImmediate()가 있으면 check로 넘어감. 없으면 이벤트루프가 phase를 돌며 콜백을 무한히 기다림 =>
    - poll 큐에 뭐가있음 : 이벤트루프가 큐를 순회하며 처리함
- check
    setImmediate() 콜백은 여기서 호출되고 집행
- close callbacks
    .on('close', ...) 같은 것들이 여기서 처리됨

