# B-Tree 인덱스의 가용성과 효율성

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">이 글은 <a target="_blank" rel="noopener noreferrer nofollow" href="https://product.kyobobook.co.kr/detail/S000001766482" style="pointer-events: none">Real MySQL 8.0</a>과 <a target="_blank" rel="noopener noreferrer nofollow" href="https://dev.mysql.com/doc/refman/8.0/en/" style="pointer-events: none">공식 문서</a>를 읽고 개인적으로 정리한 내용입니다.</div>
</div>

쿼리의 WHERE, GROUP BY, ORDER BY 절이 어떤 경우에 인덱스를 사용할 수 있고 어떤 방식으로 사용할 수 있는지 알아야 쿼리의 조건을 최적화하거나, 역으로 쿼리에 맞게 인덱스를 최적으로 생성할 수 있습니다.

이 글에서는 어떤 조건에서 인덱스를 사용할 수 있고, 사용한다면 100% 활용할 수 있는지 일부만 사용할 수 있는지 살펴봅니다.

### **1\. 비교 조건의 종류와 효율성**

```sql
mysql> SELECT * FROM dept_emp
       WHERE dept_no = 'd002' AND emp_no >= 10114;
```

위의 쿼리를 위해 `dept_emp` 테이블에 각각 컬럼의 순서만 다른 2가지 케이스로 인덱스를 생성했다고 가정해봅시다.

**1.1. 케이스 A: INDEX (dept\_no, emp\_no)**

`dept_no = 'd002' AND emp_no >= 10114`인 레코드를 찾고, 그 이후에는 `dept_no`가 `d002`가 아닐 때까지 인덱스를 쭉 읽습니다. 이 경우는 읽은 레코드가 모두 클라이언트가 원하는 결과이므로 상당히 효율적으로 인덱스를 이용한 케이스입니다.

`dept_no` 컬럼과 `emp_no` 컬럼은 모두 작업의 범위를 결정하는 조건(작업 범위 결정 조건)이므로 이 인덱스는 쿼리 처리 성능을 높이게 됩니다.

**1.2. 케이스 B: INDEX (emp\_no, dept\_no)**

`emp_no >= 10114 AND dept_no = 'd002'`인 레코드를 찾고, 그 이후 모든 레코드에 대해 `dept_no`가 `d002`인지 비교하는 과정을 거칩니다.

`emp_no` 컬럼만 작업 범위 결정 조건이고, `dept_no` 컬럼은 비교 작업의 범위를 줄이지 못하는 거름종이 역할의 조건(체크 조건)입니다. 작업 범위 결정 조건은 많으면 많을수록 쿼리 처리 성능을 높이지만 체크 조건은 쿼리 처리 성능을 높이지 못하며 오히려 더 느리게 만들 때가 많습니다.

### **2\. 가용성과 효율성 판단**

B-Tree 인덱스의 특성상 다음 조건에서는 작업 범위 결정 조건으로 사용할 수 없습니다. 경우에 따라서 필터링 조건으로 사용할 수는 있습니다.

* NOT-EQUALS로 비교된 경우("&lt;&gt;", "NOT IN", "NOT BETWEEN", "IS NOT NULL)
    
    * .. WHERE column &lt;&gt; 'N'
        
    * .. WHERE column NOT IN (10, 11, 12)
        
    * .. WHERE column IS NOT NULL;
        
* LIKE '%??'(앞부분이 아닌 뒷부분 일치) 형태로 문자열 패턴이 비교된 경우
    
* 스토어드 함수나 다른 연산자로 인덱스 컬럼이 변형된 후 비교된 경우
    
    * .. WHERE SUBSTRING(column, 1, 1) = 'X'
        
    * .. WHERE DAYOFMONTH(column) = 1
        
* NOT-DETERMINISTIC 속성의 스토어드 함수가 비교조건에 사용된 경우
    
    * .. WHERE column = deterministic\_function()
        
* 데이터 타입이 서로 다른 비교(인덱스 컬럼의 타입을 변환해야 비교가 가능한 경우)
    
    * .. WHERE char\_column = 10
        
* 문자열 데이터 타입의 콜레이션이 다른 경우
    
    * .. WHERE utf8\_bin\_char\_column = euckr\_bin char\_column
        

---

### **🎯정리**

* 작업의 범위를 결정하는 조건(작업 범위 결정 조건)은 쿼리 처리 성능을 높입니다.
    
* 거름종이 역할의 조건(필터링 조건)은 쿼리 처리 성능을 낮춥니다.
    
* 작업 범위 결정 조건으로 사용할 수 없는 경우를 알아두면 쿼리 성능을 높일 수 있습니다.
    

---

### **🔖참고**

* [https://product.kyobobook.co.kr/detail/S000001766482](https://product.kyobobook.co.kr/detail/S000001766482)
    
* [https://dev.mysql.com/doc/refman/8.0/en/](https://dev.mysql.com/doc/refman/8.0/en/)
