Real MySQL

8. 인덱스

후후후하하하 2024. 9. 29. 13:16

8.0 버전에 들어오면서 기존 MyISAM 스토리지 엔진에서만 제공하던 전문 검색이나 위치 기반 검색 기능도 모두 InnoDB 스토리지 엔진에서 사용할 수 있게 개선되었다.

 

  • 8.1 디스크 읽기 방식: 전기적 특성을 띤 CPU, 메모리는 매우 빠른 속도로 발전했지만 디스크 같은 기계식 장치의 성능은 상당히 제한적으로 발전했다. 데이터베이스의 성능 튜닝은 어떻게 디스크 I/O를 줄이느냐가 관건임. 
    • 8.1.1 하드 디스크 드라이브(HDD)와 솔리드 스테이트 드라이브(SSD) : 기계식 HDD를 대체하기 위해 전자식 저장 매체인 SSD가 출시됨. SSD도 기존 HDD와 같은 인터페이스(SATA, SAS)를 지원하므로 내장 디스크나 DAS 또는 SAN에 그대로 사용할 수 있다.
      • SATA, SAS, DAS, SAN?
      • SSD는 기존 HDD에서 데이터 저장용 플래터(원판)을 제거하고 플래시 메모리 장착함. RAM보다는 느리지만 HDD보다는 훨씬 빠르다. 그래서 DBMS용으로 사용할 서버에는 대부분 SSD를 채택함.
      • 디스크 헤드를 움직이지 않는 순차 I/O에서는 SSD와 HDD가 별 차이가 안남. 하지만 SSD의 장점은 HDD보다 랜덤 I/O가 훨씬 빠르다는 것이다. DB 서버에서 대부분은 랜덤 I/O를 통해 작은 데이터를 읽고 쓰는 작업임. = DBMS에 최적이다.
    • 8.1.2 랜덤 I/O와 순차 I/O : 순차는 3개의 페이지를 디스크에 기록하기 위해 1번 시스템 콜 요청하지만, 랜덤 I/O는 3개의 페이지를 디스크에 기록하기 위해 3번 시스템 콜을 요청함. 순차는 보따리에 모았다가 한꺼번에 요청함. 디스크의 성능은 디스크 헤더의 위치 이동 없이 얼마나 많은 데이터를 한 번에 기록하느냐에 의해 결정됨. DB 대부분의 작업은 작은 데이터를 빈번히 읽고 쓰기 때문에 MYSQL 서버에는 그룹 커밋이나 바이너리 로그 버퍼 또는 INNODB 로그 버퍼 등의 기능이 내장돼있다.
      • *그룹 커밋, 바이너리 로그 버퍼, INNODB 로그 버퍼?
      • SSD에서도 랜덤 I/O는 여전히 순차 I/O보다 전체 스루풋이 떨어진다. 스루풋: 단위 시간당 디지털 데이터 전송으로 처리하는 양을 의미함.
      • 랜덤, 순차 I/O는 모두 파일에 쓰기를 실행하면 반드시 동기화(sync or flush)작업이 필요하다. 그런데 순차일때도 파일 동기화 작업이 빈번하다면 랜덤과 같이 비효율적으로 처리될 때가 많다. 기업용 데베 서버는 캐시 메모리가 장착된 RAID 컨트롤러가 일반적으로 사용된다. RAID 컨트롤러의 캐시 메모리는 빈번한 파일 동기화 작업이 호출되는 순차 I/O를 효율적으로 처리될 수 있게 변환하는 역할을 한다.
      • RAID 컨트롤러?
      • 쿼리를 튜닝한다 = 랜덤 I/O 자체를 줄여주는 것 = 쿼리를 처리하는데 꼭 필요한 데이터만 읽도록 쿼리를 개선하는 것.
      • 인덱스 레인지 스캔은 주로 랜덤 I/O를 사용(왜?), 풀 테이블 스캔은 순차 I/O를 사용함. 그래서 큰 테이블의 레코드 대부분을 읽는 작업에서는 인덱스 사용안하고 풀 테이블 스캔을 사용하도록 유도함. 순차가 랜덤보다 훨씬 빨리 많은 레코드를 읽어올 수 있기 때문임. 이런 형태는 웹서비스보다는 데이터 웨어하우스나 통계작업에서 사용.
  • 8.2 인덱스 = 찾아보기. 칼럼의 값을 주어진 순서로 미리 정렬해서 보관한다.
  • 인덱스는 SortedList와 마찬가지로 저장되는 칼럼의 값을 이용해 항상 정렬된 상태를 유지한다. 데이터 파일은 ArrayList와 같이 저장된 순서대로 별도의 정렬 없이 그대로 저장해둔다.
  • DBMS에서 인덱스는 데이터의 저장(INSERT, UPDATE, DELETE) 성능을 희생하고 그 대신 데이터의 읽기 속도를 높이는 기능이다. 프라이머리 키와 보조 키로 구분할 수 있다.
  • 역할별 인덱스 구분
    • PK는 레코드를 대표하는 컬럼의 값으로 만들어진 인덱스이다. 해당 레코드를 식별할 수 있는 기준값이 되기 때문에 식별자라고도 부른다. NULL을 허용하지 않으며 중복을 허용하지 않는다.
    • PK를 제외한 나머지 모든 인덱스는 세컨더리 인덱스이다. 유니크 인덱스는 대체 키라고도 하는데 별도로 분류하기도 하고 세컨더리 인덱스로 분류하기도 한다.
  • 데이터 저장 방식(알고리즘) 별 구분
    • B-Tree 인덱스는 칼럼의 값을 변형하지 않고 원래의 값을 이용해 인덱싱하는 알고리즘이다. (초반 몇 바이트만 가지고 생성하는게 아님??)
    • Hash 인덱스 알고리즘은 칼럼의 값으로 해시값을 계산해서 인덱싱하는 알고리즘이다. 매우 빠른 검색을 지원한다. 하지만 값을 변형해서 인덱싱하므로 전방 일치와 같이 값의 일부만 검색하거나 범위를 검색할 때는 해시 인덱스를 사용할 수 없다. 해시 인덱스는 주로 메모리 기반의 데이터베이스에서 많이 사용한다.
  • 데이터의 중복 허용 여부로 분류
    • 유니크 인덱스 - 동등 조건으로 검색한다는 것은 항상 1건의 레코드만 찾으면 더 찾지 않아도 된다는 것을 옵티마이저에게 알려주는 효과를 낸다.
    • 유니크하지 않은 인덱스
  • 기능별 분류
    • 전문 검색용 인덱스
    • 공간 검색용 인덱스
  • 8.3 B-Tree 인덱스 : 칼럼의 원래 값을 변형시키지 않고 (값의 앞부분만 잘라서 관리) 인덱스 구조체 내에서는 항상 정렬된 상태로 유지한다.
  • 왜 해시 인덱스는 값의 앞부분만 잘라서 관리하지 않지??
    • 8.3.1 구조 및 특성: 루트 + 브랜치 + 리프 (리프 노드는 항상 실제 데이터 레코드를 찾아가기 위한 주솟값을 가지고 있다.) - pk의 리프페이지는 실제 데이터 베이스의 물리적 주소를 갖고 있고, 세컨더리 인덱스의 리프는 pk의 주소값을 갖고 있음. 세컨더리 -> PK 인덱스 거쳐서 실제 레코드 반환함.
      • 데이터 파일은 무조건 INSERT된 순서대로 저장되는 것이 아님. 레코드가 삭제되어 빈 공간이 생기면 그 다음 INSERT는 가능한 한 삭제된 공간을 재활용하도록 DBMS가 설계되어 있다.
      • 대부분의 RDMBS의 데이터 파일에서 레코드는 특정 기준으로 정렬되지 않고 임의의 순서로 저장된다. INNODB 테이블에서 레코드는 클러스터되어 디스크에 저장되므로 기본적으로 PK 순서로 정렬되어 저장된다. 이는 오라클의 IOT(Index Organized Table)나 MSSQL의 클러스터 테이블과 같은 구조를 말한다. 다른 DBMS에서는 클러스터링 기능이 선택사항이지만 INNODB에서는 디폴트로 클러스터링 테이블이 생성된다. 클러스터링이란 비슷한 값을 최대한 모아서 저장하는 방식이다.
      • MYISAM 테이블은 세컨더리 인덱스가 물리적인 주소를 가지는 반면, INNODB 테이블은 PK를 주소처럼 사용하기 때문에 논리적인 주소를 가진다. 즉, INNODB 스토리지 엔진에서는 모든 세컨더리 인덱스 검색에서 데이터 레코드를 읽기 위해서는 반드시 PK를 저장하고 있는 B-Tree를 다시 한번 검색해야 한다. 이는 장단점이 존재한다.
    • 8.3.2 B-Tree 인덱스 키 추가 및 삭제
      • 8.3.2.1 인덱스 키 추가: B-Tree 상의 적절한 위치를 검색. 위치가 결정되면 레코드의 키 값(인덱스 키 값)과 대상 레코드의 주소 정보(PK 또는 실제 데이터)를 B-Tree의 리프 노드에 저장한다. 리프 노드가 꽉 차면 리프 노드가 분리되어야 하는데, 이는 상위 브랜치 노드까지 범위가 넓어짐. = 쓰기 작업(새로운 키를 추가하는 작업)에 비용이 많이 듬.
        • 보통 테이블에 레코드를 추가하는 작업 비용이 1이라면 인덱스에 키를 추가하는 작업 비용은 1.5 정도로 예측. 이 비용의 대부분은 디스크로부터 인덱스 페이지를 읽고 쓰기를 해야 해서 걸리는 시간이라는 점. = 느림.
        • 다른 스토리지 엔진은 INSERT 문장이 실행되면 즉시 새로운 키 값을 B-Tree 인덱스에 변경한다. 하지만 INNODB는 필요하다면 인덱스 키 추가 작업을 지연시켜 나중에 처리할 수 있다. 하지만 PK나 유니크 인덱스의 경우 중복 체크가 필요하기 때문에 즉시 B-Tree에 추가하거나 삭제한다.
      • 8.3.2.2 인덱스 키 삭제:  해당 키 값이 저장된 B-Tree의 리프 노드를 찾아서 삭제 마크만 하면 작업이 완료된다. 이 작업 역시 디스크 I/O가 필요한 작업이다.
      • 8.3.2.3 인덱스 키 변경 : 먼저 키 값을 삭제 후 다시 새로운 키 값을 추가하는 형태로 처리된다. INNODB는 모두 체인지 버퍼를 활용해 지연처리 될 수 있다.
        • 체인지 버퍼?
      • 8.3.2.4 인덱스 키 검색 : 루트 - 브랜치 - 리프 작업 과정을 트리 탐색이라고 함. 인덱스 트리 탐색은 SELECT 뿐만 아니라 UPDATE, DELETE를 처리하기 위해 항상 해당 레코드를 먼저 검색해야 할 경우에도 사용된다.
        • 인덱스를 구성하는 키 값의 뒷부분만 검색하는 용도로는 사용할 수 없다. 또한 인덱스의 키 값에 변형이 가해진 후 비교되는 경우에는 B-TREE의 빠른 검색 기능을 사용할 수 없다. 이미 변형된 값은 B-TREE 인덱스에 존재하는 값이 아니다. 함수나 연산을 수행한 결과로 정렬한다거나 검색하는 작업은 B-TREE의 장점을 이용할 수 없다.
    • 8.3.3 B-TREE 인덱스 사용에 영향을 미치는 요소
      • 8.3.3.1 인덱스 키 값의 크기 : 인덱스도 결국은 페이지 단위로 관리된다.
        • B-TREE의 자식노드는 인덱스의 페이지 크기와 키 값의 크기에 따라 결정된다. 페이지 크기 기본값은 16KB이다. 인덱스를 구성하는 키 값의 크기가 커지면 한 페이지에 인덱스 키를 저장할 수 있는 개수가 적어지고, 이로 인해 디스크로부터 읽어야 하는 횟수가 늘어나고 그만큼 느려진다. 또한 인덱스 키 값의 길이가 길어진다는 것은 전체적인 인덱스의 크기가 커진다는 것을 의미한다. 인덱스를 캐시해두는 INNODB 버퍼 풀이나 MYISAM의 키 캐시 영역은 크기가 제한적이라, 메모리에 캐시해 둘 수 있는 레코드 수는 줄어들고 메모리 효율 도한 떨어진다.
      • 8.3.3.2 B-TREE 깊이 : 중요하지만 직접 제어할 방법은 없다. 인덱스 키 값의 크기가 커질수록 인덱스 페이지가 담을 수 있는 인덱스 키 값의 개수가 적어지고 B-TREE의 깊이가 깊어져서 디스크 읽기가 더 많이 필요해진다. 즉, 인덱스 키 값의 크기는 가능하면 작게 만드는 것이 좋다.
        • 의문: B-TREE의 키 값은 앞부분을 BYTE로 끊어서 키를 생성하는 것으로 본거같은데, 그러면 결국 키 값을 크게 넣어도 최적화된다는 것 아님??
      • 8.3.3.3 선택도(기수성) : 모든 인덱스 키 값 가운데 유니크한 값의 수. 
      • 8.3.3.4 읽어야 하는 레코드의 건수
        • 인덱스를 통해 레코드를 읽는 것은 인덱스를 거치지 않고 바로 레코드를 읽는 것 보다 높은 비용이 드는 작업이다.
        • 일반적으로 옵티마이저에서는 인덱스를 통해 레코드 1건을 읽는 것이 테이블에서 직접 레코드 1건을 읽는 것 보다 4~5배 정도 비용이 더 많이 드는 작업인 것으로 예측한다. 즉, 인덱스를 통해 읽어야 할 레코드의 건수가 전체 테이블 레코드의 20 ~ 25%를 넘어서면 인덱스를 이용하지 않고 테이블을 모두 직접 읽어서 필요한 레코드만 가려내는(필터링) 방식으로 처리하는 것이 효율적이다.
    • 8.3.4 B-Tree 인덱스를 통한 데이터 읽기
      • 8.3.4.1 인덱스 레인지 스캔 : 검색해야 할 인덱스의 범위가 결정됐을 때 사용하는 방식. 
        • 실제 리프 노드에서 데이터 파일로 레코드를 읽어오는 과정이 필요하기에 한 건 단위로 랜덤 I/O가 발생한다. 그래서 인덱스를 통해 데이터 레코드를 읽는 작업은 비용이 많이 드는 작업으로 분류된다.
        • 커버링 인덱스 : 디스크 레코드를 읽지 않고 인덱스 내에서 모두 처리하는 것.
      • 8.3.4.2 인덱스 풀 스캔 : 인덱스의 처음부터 끝까지 모두 읽는 방식. 쿼리가 인덱스에 명시된 칼럼만으로 조건을 처리할 수 있는 경우 이 방식이 사용된다. 인덱스 뿐만 아니라 데이터 레코드까지 모두 읽어야 한다면 절대 이 방식으로 처리되지 않는다. 대표적으로 쿼리의 조건절에 사용된 컬럼이 인덱스의 첫 번째 컬럼이 아닌 경우 사용된다.
        • 인덱스 레인지 스캔보다는 빠르지 않지만 테이블 풀 스캔보다는 효율적이다.
      • 8.3.4.3 루스 인덱스 스캔 : 오라클의 '인덱스 스킵 스캔' 기능과 비슷하다. 말 그대로 느슨하게 또는 듬성듬성하게 인덱스를 읽는 것을 의미한다.
        • 중간에 필요치 않은 인덱스 키 값은 무시하고 다음으로 넘어가는 형태로 처리된다.
        • 일반적으로 GROUP BY 또는 집합 함수 가운데 MAX(), MIN() 함수에 대해 최적화를 하는 경우에 사용된다.
      • 8.3.4.4 인덱스 스킵 스캔
        • 인덱스의 핵심은 값이 정렬돼 있다는 것이며, 이로 인해 인덱스를 구성하는 칼람의 순서가 매우 중요하다.
        • 8.0 버전부터는 옵티마이저가 인덱스에 없는 컬럼을 건너뛰고 인덱스 검색이 가능하게 해주는 기능이다. 루스 인덱스 스캔은 GROUP BY 작업을 처리하기 위해 인덱스를 사용하는 경우에만 적용할 수 있었다.
        • 인덱스에 없는 컬럼에서 유니크한 값을 모두 조회해서 주어진 쿼리에 컬럼의 조건을 추가해서 쿼리를 다시 실행하는 형태이다.
        • 단점 또한 존재한다.
          • WHERE 조건절에 조건이 없는 인덱스의 선행 칼럼의 유니크한 값의 개수가 적어야 함.
          • 쿼리가 인덱스에 존재하는 컬럼만으로 처리 가능해야 함.(커버링 인덱스) : 만약 전체(*)를 SELECT 해야 한다면, 풀 테이블 스캔이 발생한다. 
          • 의문 : 커버링 인덱스가 아니라면, SELECT * WHERE BIRTHDAY>19991919. 라면, 인덱스를 원래 못타는 구나. 커버링 인덱스인 경우에만 인덱스 스킵 스캔으로 적용되게끔 해준다. 이 쿼리 인덱스 못타는 부분은 옵티마이저가 개선되면 해결될 수 있다.? 즉, 인덱스 스킵 스캔을 커버링 인덱스 뿐 아니라 모든 쿼리에 적용되게 한다는 것인가.
    • 8.3.5 다중 칼럼(Multi-column) 인덱스
    • 8.3.6 B-Tree 인덱스의 정렬 및 스캔 방향
      • 8.3.6.1 인덱스의 정렬 : 8.0 버전부터 정렬 순서를 혼합한 인덱스도 생성할 수 있게 됨.
        • 8.3.6.1.1 인덱스 스캔 방향
        • 8.3.6.1.2 내림차순 인덱스 : 2개 이상의 칼럼으로 구성된 복합 인덱스에서 각각의 칼럼이 내림차순과 오름차순이 혼합된 경우에는 8.0의 내림차순 인덱스로만 해결될 수 있다. 왜?
          • 역순 정렬 쿼리가 정순 정렬 쿼리보다 28.9% 느리다.
            • 이유는 페이지 잠금이 인덱스 정순 스캔에 적합한 구조, 페이지 내에서 인덱스 레코드가 단방향으로만 연결된 구조이기 때문이다.
          • 소량의 레코드 조회는 굳이 상관없지만, DESC로 많은양의 데이터를 조회하는 쿼리는 내림차순 인덱스를 적용하자.
    • 8.3.7 B-Tree 인덱스의 가용성과 효율성
      • 8.3.7.1 비교 조건의 종류와 효율성 
        • 인덱스를 통해 읽은 레코드가 나머지 조건에 맞는지 비교하면서 취사선택하는 작업을 필터링이라고 한다.
        • 작업의 범위를 결정하는 조건을 '작업 범위 결정 조건'
        • 비교 작업의 범위를 줄이지 못하고 단순히 거름종이 역할을 하는 조건을 '필터링 조건' 또는 '체크 조건'
      • 8.3.7.2 인덱스의 가용성
      • 8.3.7.3 가용성과 효율성 판단
        • 인덱스 사용 불가능 조건(작업 범위 결정 조건으로 사용할 수 없음)
          • NOT-EQUAL로 비교된 경우("<>", "NOT IN", "NOT BETWEEN", "IS NOT NULL")
          • LIKE '%??' 형태로 비교된 경우
          • 스토어드 함수나 다른 연산자로 인덱스 칼럼이 변형된 후 비교된 경우
          • NOT-DETERMINISTIC 속성의 스토어드 함수가 비교 조건에 사용된 경우
          • 데이터 타입이 서로 다른 비교(인덱스 칼럼의 타입을 변환해야 비교가 가능한 경우)
          • 문자열 데이터 타입의 콜레이션이 다른 경우
        • 다중 칼럼 인덱스 조건
          • 작업 범위 결정 조건으로 인덱스 사용 불가능 조건
            • column_1 칼럼에 대한 조건이 없는 경우
            • column_1 칼럼의 비교 조건이 위의 인덱스 사용 불가 조건 중 하나인 경우
          • 사용 가능 조건
          • column_1 ~ column(i-1) 칼럼까지 동등 비교 형태(= or IN)
          • column_i 칼럼에 대해 다음 연산자 중 하나로 비교
            • 동등 비교, 크다 작다 형태, LIKE로 좌측 일치 패턴
  • 8.4 R-Tree 인덱스
    • B-Tree는 인덱스를 구성하는 칼럼의 값이 1차원의 스칼라 값인 반면, R-Tree 인덱스는 2차원의 공간 개념 값이다.
    • MYSQL의 공간 확장 기능
      • 공간 데이터를 저장할 수 있는 데이터 타입
      • 공간 데이터의 검색을 위한 공간 인덱스(R-Tree 알고리즘)
      • 공간 데이터의 연산 함수(거리 또는 포함 관계의 처리)
    • 8.4.1 구조 및 특성
      • 데이터 타입 : POINT, LINE, POLYGON, GEOMETRY
      • MBR: Minimum Bounding Rectangle. 해당 도형을 감싸는 최소 크기의 사각형. 이 사각형들의 포함 관계를 B-Tree 형태로 구현한 인덱스가 R-Tree 인덱스이다.
    • 8.4.2 R-Tree 인덱스의 용도
      • 일반적으로 WGS84(GPS) 기준의 위도, 경도 좌표 저장에 주로 사용된다. 또한 좌표 시스템에 기반을 둔 정보에 대해서는 모두 적용할 수 있다. 
      • R-Tree는 각 도형(도형의 MBR)의 포함 관계를 이용해 만들어진 인덱스다. 따라서 ST_Contains() 또는 ST_Within() 등과 같은 포함 관계를 비교하는 함수로 검색을 수행하는 경우에만 인덱스를 이용할 수 있다.
  • 8.5 전문 검색 인덱스
    • MYSQL의 B-Tree 인덱스는 실제 칼럼의 값이 1MB이더라도 1MB 전체의 값을 인덱스 키로 사용하는 것이 아니라 1000 바이트(MyISAM) 또는 3072 바이트(INNODB) 까지만 잘라서 인덱스 키로 사용한다. 
    • 하지만 문서의 내용 전체를 인덱스화해서 특정 키워드가 포함된 문서를 검색하는 전문 검색에서는 일반적인 용도의 B-Tree 인덱스를 사용할 수 없다.
    • 8.5.1 인덱스 알고리즘
      • 문서의 키워드를 인덱싱하는 기법에 따라 크게 단어의 어근 분석과 n-gram 분석 알고리즘으로 구분한다.
      • 8.5.1.1 어근 분석 알고리즘
        • 불용어 처리(Stop Word) : 검색에서 별 가치가 없는 단어를 모두 필터링해서 제거하는 작업을 의미함.
        • 어근 분석(Stemming) : 검색어로 선정된 단어의 뿌리인 원형을 찾는 작업이다. 한글이나 일본어의 경우 어근 분석보다는 문장의 형태소를 분석해서 명사와 조사를 구분하는 기능이 더 중요한 편이다. 각 국가의 언어가 서로 문법이 다르고 다른 방식으로 발전해왔기에 형태소 분석이나 어근 분석 또한 언어별로 방식이 모두 다르다. 한국어는 MeCab을 이용해 한글 분석이 가능하다.
        • 하지만 단어 사전이 필요하며 문장의 구조 인식이 필요한데 상당한 시간과 노력이 필요하다.
      • 8.5.1.2 n-gram 알고리즘
        • MeCab을 위한 형태소 분석의 시간, 노력 필요의 단점을 보완하기 위해 나온 알고리즘이다. 형태소 분석이 문장을 이해하는 알고리즘이라면, n-gram은 단순히 키워드를 검색하기 위한 인덱싱 알고리즘이다.
        • 본문을 무조건 몇 글자씩 잘라서 인덱싱하는 방법이다. 만들어진 인덱스의 크기는 상당히 큰 편이다. n은 인덱싱할 키워드의 최소 글자 수를 의미한다. 
        • 토큰 단위로 추출하고, 불용어를 제외한 토큰을 단순한 B-Tree 인덱스에 저장한다.
      • 8.5.1.3 불용어 변경 및 삭제
        • 자동 불용어 등록된 것은 오히려 사용자를 더 혼란스럽게 할 수 있어서 불용어 처리 자체를 완전히 무시하거나 MYSQL 서버에 내장된 불용어 대신 사용자가 직접 등록하는 방법을 권장한다.
        • 전문 검색 인덱스의 불용어 처리 무시
          • 모든 스토리지 엔진에 MYSQL 서버의 모든 전문 검색 인덱스에 대해 불용어를 완전히 제거하는 것
          • INNODB 엔진을 사용하는 테이블의 전문 검색 인덱스에만 불용어 처리를 무시
        • 사용자 정의 불용어 사용
          • 불용어 목록을 파일로 저장하고 경로를 등록하는 법
          • 불용어의 목록을 테이블로 저장하는 방식
    • 8.5.2 전문 검색 인덱스의 가용성
      • 전문 검색 인덱스를 사용하려면 반드시 다음 두 가지 조건을 갖춰야 한다.
        • 쿼리 문장이 전문 검색을 위한 문법(MATCH ... AGAINST ...)을 사용
        • 테이블이 전문 검색 대상 칼럼에 대해서 전문 인덱스 보유

 

B+ Tree란?