catsridingCATSRIDING|OCEANWAVES
Data

MySQL 인덱스 파헤치기

jynn@catsriding.com
Mar 10, 2024
Published byJynn
999
MySQL 인덱스 파헤치기

Database Index with MySQL

데이터베이스 인덱스는 데이터 요청의 처리 속도를 크게 향상시킵니다. 인덱스의 작동 방식과 구조를 이해하는 것은 데이터를 효과적으로 관리하고 최적의 성능을 유지하는 데 필수적입니다. MySQL 환경을 기반으로 인덱스의 본질적인 특징, 장단점, 그리고 사용 시 주의할 사항들을 자세히 알아보겠습니다.

Database Index Fundamentals

데이터베이스 인덱스는 데이터베이스 성능 최적화의 핵심 요소입니다. 인덱스의 역할과 필요성을 이해하면 데이터 관리 및 검색 효율성을 크게 향상시킬 수 있습니다. 인덱스는 디스크 I/O 문제를 해결하며, 데이터 접근 속도를 크게 향상시킵니다.

Rationale Behind Indexing

디스크 I/O는 데이터베이스 성능의 주요 병목 현상 중 하나입니다. 관계형 데이터베이스는 데이터의 영속성을 보장하기 위해 데이터를 하드 디스크에 저장합니다. 이로 인해 데이터베이스의 주요 작업은 디스크 I/O를 수반하게 됩니다. 하드 디스크 드라이브(HDD)는 기계식 장치로, 데이터를 읽고 쓰기 위해 디스크의 물리적 회전과 헤더 이동이 필요합니다. 이러한 기계적 동작은 상당한 시간이 소요되며, 특히 랜덤 I/O 작업에서는 더욱 두드러집니다. 랜덤 I/O는 디스크의 여러 위치에서 데이터를 읽거나 쓰는 작업으로, 헤더를 자주 이동시켜야 하기 때문에 순차 I/O에 비해 속도가 느립니다.

HDD의 이러한 기계적 특성 때문에 디스크 I/O는 데이터베이스 시스템에서 항상 병목이 됩니다. 이를 개선하기 위해 SSD(Solid State Drive)가 도입되었지만, SSD 역시 랜덤 I/O와 순차 I/O 간의 속도 차이가 존재합니다. SSD는 플래시 메모리를 사용하여 HDD에 비해 훨씬 빠른 속도를 제공하지만, 비용이 높고 용량이 상대적으로 작습니다. 따라서 효율적인 데이터 접근을 위해 인덱스의 사용은 여전히 중요합니다.

인덱스는 테이블의 특정 열에 대한 검색을 빠르게 하기 위한 데이터 구조입니다. 인덱스는 책의 색인과 같이 데이터의 위치를 미리 알고 있어, 디스크의 물리적 이동을 최소화하고 데이터를 신속하게 찾을 수 있게 합니다. 예를 들어, 수백 페이지의 책에서 특정 단어를 찾기 위해 처음부터 끝까지 읽어야 한다면 시간이 매우 오래 걸리겠지만, 색인을 통해 해당 단어의 위치를 바로 찾을 수 있다면 시간을 크게 단축할 수 있습니다.

인덱스는 다음과 같은 주요 역할을 합니다:

  • 검색 속도 향상: 인덱스를 사용하면 테이블의 특정 열을 기준으로 데이터를 정렬하여 저장할 수 있습니다. 이를 통해 데이터 검색 속도를 크게 향상시킬 수 있습니다.
  • 디스크 I/O 감소: 인덱스는 디스크의 물리적 이동을 최소화하여, 데이터를 읽고 쓰는 작업에서의 디스크 I/O를 줄입니다.
  • 성능 최적화: 인덱스는 대규모 데이터베이스에서의 성능을 최적화하여, 사용자가 빠르게 데이터를 조회하고 처리할 수 있도록 합니다.

결론적으로, 인덱스는 디스크 I/O로 인한 성능 저하 문제를 해결하고, 데이터베이스의 검색 및 접근 속도를 크게 향상시키기 위해 도입되었습니다. 데이터베이스의 데이터가 하드디스크에 저장됨으로써 발생하는 성능 문제를 극복하기 위한 중요한 도구로서, 인덱스는 데이터베이스 성능 최적화의 핵심적인 역할을 수행합니다.

Concepts of Database Indexing

인덱스는 데이터베이스 테이블의 특정 열에 대한 데이터를 신속하게 검색할 수 있도록 하는 데이터 구조입니다. 인덱스는 모든 데이터를 직접 저장하는 것이 아니라, 데이터를 찾을 수 있는 위치 정보를 저장합니다. 이를 통해 디스크의 물리적 이동을 최소화하고 빠른 데이터 접근을 가능하게 합니다. 인덱스의 동작 원리와 구조를 이해하면, 데이터베이스 성능 최적화의 핵심 원리를 파악할 수 있습니다.

Principles of Index Operation

인덱스는 테이블의 특정 열에 대한 값을 정렬된 순서로 유지합니다. 각 인덱스 항목에는 해당 값과 그 값이 저장된 실제 데이터의 주소(포인터)가 포함됩니다. 이를 통해 인덱스를 사용하면 데이터베이스는 테이블 전체를 탐색하지 않고도 필요한 데이터를 신속하게 찾을 수 있습니다.

도서관에서 특정 책을 찾는 과정을 생각해보겠습니다. 도서관은 책을 분류하기 위해 듀이십진분류법(Dewey Decimal Classification, DDC) 또는 미국 의회 도서관 분류법(Library of Congress Classification, LCC) 같은 분류법을 사용하여 책마다 고유의 청구 기호를 부여합니다.

  1. 도서관의 컴퓨터 시스템에서 책의 제목이나 저자를 입력하여 책의 청구 기호를 검색합니다.
  2. PL856.U745 .N6713 2000 같은 형식의 검색된 청구 기호를 사용하여 책이 위치한 섹션을 찾습니다.
  3. 해당 섹션의 책장으로 이동하여 청구 기호를 기반으로 책을 찾습니다.
  4. 책의 정확한 위치에 도달하여 필요한 책을 확인합니다.
  5. 책을 가져옵니다.

인덱스는 도서관에서 책을 찾을 때 필요한 청구 기호와 같은 역할을 합니다. 그것은 고유 식별 코드로, 데이터를 빠르게 검색할 수 있도록 도와줍니다. 이 인덱스는 데이터베이스 시스템의 별도 공간에서 생성되고 관리되며, 테이블의 특정 열의 값을 키로 사용하여 정렬됩니다. 이렇게 생성된 인덱스 파일은 키 값 및 해당 키 값에 대한 데이터의 물리적 위치를 참조하는 포인터와, 인덱스 구성 및 유형에 대한 메타데이터가 함께 저장되며, 실제 데이터 파일과는 별도로 관리됩니다. 인덱스의 구조는 대부분 B-트리(B-Tree) 또는 해시 테이블(Hash Table) 등의 자료구조를 사용하고, 이는 인덱스의 성능과 효율성을 확보하는데 중요한 요소입니다.

이제 도서관에서 책을 찾는 과정을 데이터베이스 인덱스 검색 과정과 비교해보겠습니다:

  • 인덱스 검색 시작: 데이터베이스는 검색하려는 값에 해당하는 인덱스를 탐색합니다.
  • 검색 키 비교: 인덱스의 루트 노드에서 시작하여 검색 키를 비교합니다. B-트리 구조를 예로 들면, 검색 키가 현재 노드의 키보다 작으면 왼쪽 서브트리로 이동하고, 크면 오른쪽 서브트리로 이동합니다. 이 과정을 반복하여 리프 노드에 도달합니다.
  • 리프 노드 도달: 리프 노드에 도달하면, 해당 노드에서 검색 키와 일치하는 항목을 찾습니다. 이 항목에는 실제 데이터가 저장된 위치(페이지 번호와 오프셋)가 포함되어 있습니다.
  • 데이터 페이지 접근: 인덱스 항목이 가리키는 주소를 사용하여 데이터가 저장된 페이지로 이동합니다. 이 페이지에서 실제 데이터를 읽어옵니다.
  • 결과 반환: 필요한 데이터를 찾은 후, 검색 결과를 반환합니다. 이 과정은 매우 빠르게 이루어지며, 전체 테이블을 탐색하는 것보다 훨씬 효율적입니다.

Pages in Database
데이터베이스 시스템에서 페이지란 보통 4KB에서 8KB 크기의 고정 길이 연속 블록 저장 공간을 의미하며, 레코드를 저장하는 데 사용됩니다. 쿼리가 실행될 때 데이터베이스는 디스크에서 관련 페이지를 메모리로 불러와 요청을 처리합니다. 이러한 페이지 접근 과정은 인덱스를 사용하여 최적화할 수 있습니다. 인덱스를 사용하면 데이터베이스가 전체 테이블을 스캔하지 않고도 요청된 데이터가 포함된 페이지를 빠르게 찾아낼 수 있습니다. 이는 디스크 I/O 작업의 수를 줄여 데이터베이스 시스템의 전반적인 성능을 향상시킵니다. MySQL 5.7 버전부터는 InnoDB 스토리지 엔진의 페이지 크기를 innodb_page_size 시스템 변수를 이용해 4KB ~ 64KB 사이의 값으로 선택할 수 있으며, 기본값은 16KB입니다.

이와 같은 단계들을 통해 인덱스는 데이터베이스 검색을 효율적으로 처리하며, 디스크 I/O를 최소화하여 빠른 성능을 제공합니다. 인덱스는 특정 열의 값을 정렬된 상태로 유지하기 때문에 이진 검색(Binary Search)과 같은 효율적인 검색 알고리즘을 사용할 수 있습니다. 예를 들어, 사전에서 특정 단어를 찾을 때 이름이 알파벳 순서로 정렬되어 있어 중간 지점을 기준으로 검색 범위를 절반으로 줄이며 빠르게 찾을 수 있습니다.

또한, 인덱스는 데이터의 위치 정보를 포함하고 있어 디스크의 물리적 이동을 최소화할 수 있습니다. 즉, 필요한 데이터가 저장된 페이지의 디스크 주소를 빠르게 파악하여 최소한의 디스크 I/O로 데이터를 접근할 수 있게 합니다. 이는 디스크 헤더의 이동을 줄이고, 랜덤 I/O를 순차 I/O로 변환하여 성능을 극대화합니다.

Index Structures and Algorithms

B-Tree는 데이터베이스 인덱싱 알고리즘 중 가장 일반적으로 사용됩니다. 여러 변형이 있으며, 일반적으로 DBMS에서는 B+-Tree나 B*-Tree가 주로 사용됩니다. 기본 자료 구조인 이진 트리(Binary Tree)와 이름에서 혼동할 수 있지만, B-Tree의 "B"는 Binary가 아닌 Balanced를 의미합니다.

B-Tree는 각 노드가 가변적으로 여러 자식을 가질 수 있는 구조로, 모든 리프 노드는 동일한 깊이를 가집니다. 또한, B-Tree는 노드를 항상 정렬된 상태로 유지하여 이진 검색 알고리즘을 사용할 수 있습니다. 이는 검색 범위를 절반으로 줄이며 데이터를 신속하게 찾을 수 있게 합니다. B-Tree 인덱스는 루트 노드, 브랜치 노드, 리프 노드로 구성됩니다:

  • 루트 노드(Root Node): 트리의 최상위 노드로, 트리 탐색의 시작점입니다. 인덱스 키와 자식 노드에 대한 포인터를 포함합니다.
  • 브랜치 노드(Branch Node): 중간 노드로, 하위 노드로 가는 포인터를 포함합니다. 키 값과 자식 노드 주소를 포함합니다.
  • 리프 노드(Leaf Node): 트리의 최하위 노드로, 실제 데이터의 주소(포인터)를 포함합니다. 키 값과 실제 데이터의 주소를 포함합니다.

database-index-with-mysql_00.png

MySQL에서는 InnoDB 스토리지 엔진이 기본적으로 B-Tree 구조를 사용하여 인덱스를 관리합니다. InnoDB는 B-Tree를 사용하여 데이터 페이지를 구성하고, 클러스터형 인덱스를 통해 데이터의 물리적 순서를 유지합니다. 이는 데이터 검색과 삽입, 삭제 작업에서 높은 성능을 제공합니다.

이 B-Tree 인덱스의 각 노드들은 다음과 같은 값들을 지니고 있어, 데이터를 효율적으로 검색하고 관리하는 데 활용할 수 있습니다:

  • 키 값(Key Value): 각 노드는 키 값을 포함하며, 이 키 값은 사용자가 인덱싱하기로 설정한 특정 열의 값입니다. 키 값은 노드 내에서 정렬된 상태로 유지됩니다. 이는 이진 검색을 통해 빠른 탐색을 가능하게 합니다.
  • 포인터(Pointer): 각 노드는 자식 노드로 가는 포인터를 포함합니다. 루트 노드와 브랜치 노드는 자식 노드로 가는 포인터를 가지고 있으며, 리프 노드는 실제 데이터의 주소를 가리키는 포인터를 포함합니다.
  • 메타데이터(Metadata): 각 노드는 추가적인 메타데이터를 포함할 수 있습니다. 예를 들어, 노드의 상태, 자식 노드의 수, 데이터 페이지의 위치 정보 등이 포함됩니다. 이러한 메타데이터는 인덱스의 관리와 최적화에 중요한 역할을 합니다.

B-Tree 구조를 활용하여 데이터베이스 인덱스를 관리하는 방법은 다음과 같습니다:

  • 삽입: 새로운 키 값이 B-Tree에 저장될 때 적절한 위치를 찾아 삽입합니다. 리프 노드가 가득 차면 노드를 분리(Splitting)하여 새로운 브랜치 노드를 생성합니다. 예를 들어, 새로운 레코드가 추가될 때, B-Tree는 키 값을 기준으로 적절한 위치를 찾아 삽입합니다. 만약 리프 노드가 가득 찼다면, 새로운 노드를 생성하고 기존 노드를 분할하여 트리의 균형을 유지합니다.
  • 삭제: 키 값을 삭제할 때는 리프 노드에서 키 값을 찾아 삭제 마킹을 합니다. 삭제된 공간은 재사용될 수 있습니다. 삭제 작업은 주로 해당 키 값을 포함하는 리프 노드를 찾아가서 삭제 마킹을 합니다. 이는 트리의 구조를 크게 변화시키지 않으면서 공간을 효율적으로 사용할 수 있게 합니다.
  • 검색: 루트 노드에서 시작하여 키 값을 비교하며 브랜치 노드를 거쳐 리프 노드까지 탐색합니다. 리프 노드에서 실제 데이터 주소를 찾아 데이터에 접근합니다. 예를 들어, 특정 키 값을 찾기 위해 루트 노드에서 시작하여 각 브랜치 노드를 통해 키 값을 비교하면서 리프 노드에 도달합니다. 이 과정을 통해 빠르고 효율적으로 데이터를 검색할 수 있습니다.

B-Tree는 삽입과 삭제 후에도 트리의 균형을 유지하므로 항상 최적의 검색 성능을 보장합니다. 또한, B-Tree 구조는 범위 검색에 최적화되어 있어 특정 범위 내의 데이터를 빠르게 찾을 수 있습니다. B-Tree는 페이지 단위로 데이터를 저장하고 관리하므로 디스크 I/O를 최소화할 수 있습니다.

그러나 이러한 균형을 유지하기 위해 추가적인 비용이 발생합니다. 일반적으로, 인덱스를 포함한 쓰기 작업은 인덱스를 사용하지 않는 경우보다 약 1.5배 더 많은 비용이 드는 것으로 알려져 있습니다. 이는 삽입 또는 삭제 시, 트리의 균형을 유지하기 위해 노드를 분할하거나 병합하는 작업이 필요하기 때문입니다. 이러한 작업은 디스크 I/O가 많이 발생하게 되며, 특히 대규모 데이터베이스에서는 이로 인해 성능 저하가 발생할 수 있습니다.

읽기 작업에서도 B-Tree의 깊이에 따라 디스크 I/O 비용이 증가할 수 있습니다. 각 레벨마다 블록을 읽어야 하므로, 트리의 깊이가 깊어질수록 더 많은 디스크 읽기 작업이 필요합니다. 따라서 B-Tree 인덱스를 사용하면 읽기 성능이 향상되지만, 추가적인 디스크 I/O 비용도 고려해야 합니다. 인덱스를 거치지 않고 데이터를 바로 조회하는 것이 더 효율적인 경우도 있습니다. 예를 들어, 테이블의 상당 부분을 읽어야 할 때는 전체 테이블 스캔이 인덱스 검색보다 더 효율적일 수 있습니다.

이러한 이유로 인덱스를 설계할 때는 데이터베이스의 사용 패턴을 분석하고, 인덱스를 무작정 추가하기보다는 적절하게 사용하는 것이 중요합니다. B-Tree의 효율성을 유지하기 위해 인덱스 키의 크기와 선택도를 적절히 관리하는 것이 중요합니다. 키 값이 작을수록 한 페이지에 더 많은 키를 저장할 수 있어 검색 속도가 빨라집니다. 트리의 깊이가 얕을수록 검색 시 디스크 읽기 횟수가 줄어들어 성능이 향상됩니다. 또한, 인덱스의 선택도가 높을수록 중복된 키 값이 적어 검색 성능이 향상됩니다. MySQL에서는 이러한 구조를 통해 높은 성능의 데이터베이스 인덱싱을 제공합니다.

Types of Database Indexes

데이터베이스 인덱스는 여러 유형으로 나뉘어 다양한 기준에 따라 분류되며, 각 인덱스는 특정 목적을 가지고 있어 데이터베이스의 성능을 향상시키고 다양한 작업을 최적화하는 데 기여합니다.

TypeDesc.
Primary Key프라이머리 키 또는 기본 키라고 하며, 테이블의 각 레코드를 고유하게 식별하는 역할을 합니다. 일반적으로 테이블에서 가장 중요한 키로, 중복 값을 허용하지 않습니다.
Foreign Key외래 키라고 부르며, 다른 테이블의 프라이머리 키를 참조하여 테이블 간의 관계를 유지하고 참조 무결성을 보장합니다. 이를 통해 데이터베이스의 일관성을 유지할 수 있습니다.
Unique Index유니크 인덱스라고 하며, 특정 열의 값이 고유하도록 보장하여 중복 데이터를 방지합니다. 주로 이메일, 사용자 이름 등 고유해야 하는 값에 사용됩니다.
Non-Unique Index비고유 인덱스 또는 그냥 인덱스라고 하면 보통 이 유형을 의미하며, 데이터 검색 성능을 향상시킵니다. 주로 검색 속도를 높이기 위해 사용됩니다.
Function-Based Index함수 기반 인덱스라고 하며, 특정 함수나 식의 결과를 인덱싱합니다. 이를 통해 복잡한 계산이 필요한 검색을 빠르게 수행할 수 있습니다.

이러한 인덱스는 효율적인 데이터 접근과 성능 최적화를 통해 빠르고 정확한 데이터 검색을 가능하게 하며, 데이터 무결성을 유지하여 안전한 데이터 저장을 보장하는 데이터베이스의 핵심 요소입니다.

Key vs. Index
데이터베이스에서 키(Key)와 인덱스(Index)는 종종 동일한 의미로 사용됩니다. 키는 데이터베이스 내에서 고유성과 참조 무결성을 보장하는 특정 유형의 인덱스를 의미합니다. 예를 들어, 프라이머리 키는 테이블의 각 행을 고유하게 식별하며, 외래 키는 두 테이블 간의 참조 무결성을 보장합니다. 인덱스는 데이터베이스 테이블에서 데이터 검색 속도를 향상시키기 위해 사용되는 데이터 구조를 의미하는 더 넓은 범위의 용어입니다. 모든 키는 인덱스이지만, 모든 인덱스가 키는 아닙니다. 인덱스는 고유성이나 참조 무결성을 강제하지 않더라도 쿼리 성능을 최적화하기 위해 어떤 컬럼이나 컬럼 집합에 대해서도 생성될 수 있습니다. 따라서 많은 문맥에서 이 두 용어는 상호 교환적으로 사용될 수 있지만, 데이터베이스 관리 시스템 내에서 그들의 특정 역할과 특성을 이해하는 것이 중요합니다.

Primary Key

프라이머리 키(Primary Key)는 데이터베이스 테이블의 각 레코드를 고유하게 식별하는 데 사용되는 컬럼(또는 컬럼의 조합)입니다. 프라이머리 키는 데이터 무결성을 유지하고 각 레코드에 빠르게 접근할 수 있게 해줍니다. 다음은 프라이머리 키의 주요 특징과 역할에 대한 상세한 설명입니다:

  • Unique: 프라이머리 키는 각 레코드를 고유하게 식별합니다. 즉, 프라이머리 키 값은 테이블 내에서 중복될 수 없습니다. 예를 들어, 직원 테이블에서 직원 ID를 프라이머리 키로 설정하면, 각 직원의 ID는 유일해야 합니다.
  • Non-Nullable: 프라이머리 키는 null 값을 가질 수 없습니다. 이는 각 레코드가 항상 식별 가능한 키 값을 가져야 함을 의미합니다.
  • Singularity: 각 테이블에는 하나의 프라이머리 키만 존재할 수 있습니다. 프라이머리 키는 단일 컬럼으로 구성될 수도 있고, 여러 컬럼의 조합인 복합 키로 구성될 수도 있습니다.

다음은 MySQL에서 프라이머리 키를 정의하는 예시입니다. 직원 테이블에서 직원 ID를 프라이머리 키로 설정합니다.

MySQL
create table EMPLOYEES (
    employee_id bigint auto_increment,
    first_name varchar(50),
    last_name varchar(50),
    primary key (employee_id)
);

이렇게 employee_idprimary key 키워드로 지정하면 데이터베이스 내부 엔진에서 이 컬럼을 고유한 식별자로 사용하여 각 레코드를 효율적으로 관리합니다.

프라이머리 키가 제대로 설정되었는지 확인하려면 다음과 같은 쿼리를 사용할 수 있습니다:

MySQL
show keys from EMPLOYEES where Key_name = 'PRIMARY';

이 쿼리는 EMPLOYEES 테이블에서 프라이머리 키로 설정된 컬럼을 보여줍니다.

MySQL
+---------+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|Table    |Non_unique|Key_name|Seq_in_index|Column_name|Collation|Cardinality|Sub_part|Packed|Null|Index_type|Comment|Index_comment|Visible|Expression|
+---------+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|EMPLOYEES|0         |PRIMARY |1           |employee_id|A        |0          |null    |null  |    |BTREE     |       |             |YES    |null      |
+---------+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+

이 쿼리는 다음 정보를 보여줍니다:

  • Table: 인덱스가 속한 테이블의 이름
  • Non_unique: 인덱스의 유일성 여부
    • 0: 유일함을 의미, 즉 유니크 인덱스
    • 1: 중복을 허용함을 의미, 즉 일반 인덱스
  • Key_name: 인덱스의 이름
  • Seq_in_index: 인덱스에서 컬럼의 순서
  • Column_name: 인덱스에 포함된 컬럼의 이름
  • Collation: 인덱스가 정렬되는 방식
    • A: 오름차순을 의미
    • D: 내림차순을 의미
    • NULL: 정렬되지 않음을 의미
  • Cardinality: 인덱스의 고유한 값의 개수 (대략적인 값)
  • Sub_part: 인덱스의 부분 길이 (전체 길이가 아닐 경우)
  • Packed: 인덱스가 압축되었는지 여부
    • NULL: 압축되지 않음
    • YES: 압축됨
  • Null: 컬럼이 NULL 값을 허용하는지 여부
    • YES: NULL 값을 허용함
    • NO: NULL 값을 허용하지 않음
  • Index_type: 인덱스의 자료 구조
    • BTREE: B-Tree 구조
    • HASH: 해시 구조
    • FULLTEXT: 풀텍스트 인덱스
  • Comment: 인덱스에 대한 설명
  • Index_comment: 인덱스에 대한 사용자 정의 추가 코멘트

프라이머리 키는 여러 컬럼의 조합으로도 구성될 수 있습니다. 이를 복합 키(Composite Key)라고 합니다. 예를 들어, 주문 테이블에서 주문 ID와 제품 ID를 함께 사용하여 프라이머리 키를 정의할 수 있습니다.

MySQL
create table ORDER_ITEMS (
    order_id int,
    product_id int,
    quantity int,
    primary key (order_id, product_id)
);

이렇게 여러 컬럼을 프라이머리 키로 설정하게 되면, 레코드 조회 시 두 컬럼을 함께 조합된 값이 특정 레코드의 고유 값이 됩니다. 그러나 이들 중 하나의 컬럼만 조건에 추가하거나 순서가 바뀌는 경우 인덱스를 타지 못할 수 있어 주의해야 합니다. 예를 들어, 복합 키가 order_idproduct_id로 구성된 경우, order_id만으로 조회하거나, product_id를 첫 번째 조건으로 사용하는 경우 인덱스를 제대로 활용하지 못할 수 있습니다. 인덱스를 효과적으로 사용하려면, 복합 키의 모든 컬럼을 조건에 포함하고, 정의된 순서대로 사용해야 합니다.

복합 키가 잘 설정되었는지 확인하려면 다음과 같은 쿼리를 사용할 수 있습니다:

MySQL
show keys from ORDER_ITEMS where Key_name = 'PRIMARY';

위 쿼리의 결과는 다음과 같이 나올 수 있습니다:

MySQL
+-----------+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|Table      |Non_unique|Key_name|Seq_in_index|Column_name|Collation|Cardinality|Sub_part|Packed|Null|Index_type|Comment|Index_comment|Visible|Expression|
+-----------+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|ORDER_ITEMS|0         |PRIMARY |1           |order_id   |A        |0          |null    |null  |    |BTREE     |       |             |YES    |null      |
|ORDER_ITEMS|0         |PRIMARY |2           |product_id |A        |0          |null    |null  |    |BTREE     |       |             |YES    |null      |
+-----------+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+

Challenges with Composite Keys 과거 데이터베이스 주도 설계가 만연하던 시절, 복합 키는 매우 유용한 방식으로 여겨졌으나, 여러 문제점이 발견되어 현재는 사용을 지양하는 것이 권장되고 있습니다. 복합 키는 다른 테이블의 외래 키와 함께 사용되어 탐색을 용이하게 했지만, 특정 데이터베이스에 종속되는 설계는 유지보수 및 확장성 문제를 야기할 수 있습니다. 복합 키는 여러 컬럼을 포함하므로 스키마 변경 시 더 많은 수정이 필요하게 되며, 이는 개발 및 유지보수 비용을 증가시킵니다. 또한, 복합 키를 사용하면 쿼리의 복잡성이 증가하여 가독성과 유지보수성이 떨어질 수 있습니다. 인덱스의 크기를 증가시켜 검색 성능에 악영향을 미칠 수도 있고, 여러 데이터베이스 또는 시스템 간에 데이터를 통합하거나 동기화할 때 일관성을 유지하기 어렵게 만듭니다. 반면, 단일 컬럼으로 구성된 프라이머리 키(예: 자동 증가되는 정수형 키)는 이러한 문제를 해결하는 데 더 적합합니다.

프라이머리 키는 데이터베이스 관리에서 여러 중요한 역할을 합니다. 프라이머리 키는 각 레코드를 고유하게 식별하여 데이터 무결성을 유지하고, 인덱스를 통해 레코드를 빠르게 검색할 수 있으며, 외래 키와 함께 사용되어 테이블 간의 관계를 설정합니다. 이를 위해 프라이머리 키는 고유하고 불변해야 하며, 가능한 짧고 간결해야 합니다. 이는 인덱스 크기와 검색 성능에 영향을 미치기 때문입니다. 따라서 프라이머리 키에 대한 이해와 적절한 사용은 데이터베이스의 효율적인 운영과 관리에 필수적입니다.

Foreign Key

외래 키(Foreign Key)는 한 테이블의 컬럼이 다른 테이블의 프라이머리 키(Primary Key)와 연결되어 있을 때 사용됩니다. 외래 키는 두 테이블 간의 관계를 설정하고, 데이터의 무결성을 유지하는 데 중요한 역할을 합니다. 다음은 외래 키의 주요 특징과 역할에 대한 상세한 설명입니다:

  • Data Integrity(데이터 무결성): 외래 키는 한 테이블의 값이 다른 테이블의 프라이머리 키 값과 일치해야 한다는 제약 조건을 가집니다. 이를 통해 데이터의 일관성을 유지할 수 있습니다. 예를 들어, 주문 테이블에서 고객 ID가 고객 테이블의 고객 ID와 일치해야 합니다.
  • Referential Integrity(참조 무결성): 외래 키는 참조 무결성을 보장하여, 부모 테이블(참조되는 테이블)의 데이터가 변경될 때 자식 테이블(참조하는 테이블)의 데이터도 자동으로 업데이트되거나 삭제됩니다. 이는 ON UPDATE CASCADEON DELETE CASCADE 옵션을 사용하여 설정할 수 있습니다.
  • Relationship Definition: 외래 키는 두 테이블 간의 관계를 명확하게 정의합니다. 이를 통해 조인 연산을 수행할 때 데이터 간의 연결 고리를 쉽게 찾을 수 있습니다.

외래 키는 데이터베이스 정규화(Normalization) 이론과 밀접한 관련이 있습니다. 정규화는 데이터베이스 설계의 중요한 원칙 중 하나로, 데이터 중복을 최소화하고 데이터 무결성을 유지하는 것을 목표로 합니다. 외래 키는 이러한 정규화 과정을 통해 테이블 간의 관계를 설정하고 데이터의 일관성을 유지하는 데 중요한 역할을 합니다.

다음은 MySQL에서 외래 키를 정의하는 예시입니다. 주문 테이블에서 고객 ID를 외래 키로 설정하여 고객 테이블의 고객 ID와 참조 관계를 만듭니다.

MySQL
create table CUSTOMERS
(
    customer_id bigint auto_increment,
    name        varchar(50),
    primary key (customer_id)
);

create table ORDERS
(
    order_id    bigint auto_increment,
    customer_id bigint not null,
    order_date  date,
    primary key (order_id),
    foreign key (customer_id) references CUSTOMERS (customer_id) on update cascade on delete cascade
);

이렇게 customer_idforeign key 키워드로 지정하면, 데이터베이스는 ORDERS 테이블의 customer_id가 항상 CUSTOMERS 테이블의 customer_id와 일치하도록 강제합니다.

외래 키의 설정을 확인하려면 다음과 같은 쿼리를 사용할 수 있습니다:

MySQL
show create table ORDERS;

이 쿼리는 ORDERS 테이블의 생성 문을 보여주며, 외래 키 제약 조건을 확인할 수 있습니다.

MySQL
create table `ORDERS`
(
    `order_id`    bigint not null auto_increment,
    `customer_id` bigint not null,
    `order_date`  date default null,
    primary key (`order_id`),
    key `customer_id` (`customer_id`),
    constraint `orders_ibfk_1` foreign key (`customer_id`) references `CUSTOMERS` (`customer_id`) on delete cascade on update cascade
) engine = InnoDB
  default charset = utf8mb4
  collate = utf8mb4_0900_ai_ci

외래 키를 활용하면 데이터 무결성과 참조 무결성을 유지하면서 연관된 테이블들을 조인하여 필요한 데이터를 탐색할 수 있습니다:

MySQL
select
    customers.customer_id as customer_id,
    customers.name        as customer_name,
    orders.order_id       as order_id,
    orders.order_date     as order_date
from
    CUSTOMERS customers
    join ORDERS orders on customers.customer_id = orders.customer_id;

이 쿼리는 CUSTOMERS 테이블과 ORDERS 테이블을 조인하여 각 고객의 ID, 이름, 주문 ID 및 주문 날짜를 출력합니다. 외래 키를 통해 두 테이블 간의 관계가 명확하게 정의되어 있으므로, 조인 연산을 통해 쉽게 데이터를 연결할 수 있습니다.

MySQL
+-------------+---------------+----------+------------+
| customer_id | customer_name | order_id | order_date |
+-------------+---------------+----------+------------+
|           1 | Ongs          |        1 | 2024-01-01 |
|           2 | Mongs         |        2 | 2024-01-02 |
|           1 | Mongs         |        3 | 2024-01-03 |
+-------------+---------------+----------+------------+

이 예시에서 볼 수 있듯이, 외래 키를 사용하여 테이블 간의 관계를 설정하고 이를 활용한 조인 쿼리를 통해 원하는 데이터를 쉽게 조회할 수 있습니다.

그러나 외래 키는 다음과 같은 몇 가지 주의사항을 필요로 합니다:

  • 성능(Performance): 외래 키 제약 조건은 삽입, 업데이트, 삭제 작업 시 추가적인 검사 과정을 요구하기 때문에 성능에 영향을 미칠 수 있습니다.
  • 복잡성(Complexity): 외래 키가 많아지면 테이블 간의 관계가 복잡해져 데이터베이스 설계와 유지보수가 어려워질 수 있습니다.
  • 제약 조건 순서(Constraint Order): 외래 키는 데이터의 삽입 순서에 영향을 미칩니다. 부모 테이블의 레코드가 먼저 삽입되어야 자식 테이블에 레코드를 삽입할 수 있습니다.

적절한 외래 키의 설정과 관리는 데이터베이스의 일관성과 안정성을 유지하는 데 중요한 역할을 합니다.

Unique Index

유니크 인덱스(Unique Index)는 데이터베이스 테이블의 특정 컬럼(또는 컬럼의 조합)에 중복된 값을 허용하지 않도록 하는 제약 조건을 적용하는 인덱스입니다. 유니크 인덱스는 데이터 무결성을 유지하고, 데이터베이스 성능을 향상시키는 데 중요한 역할을 합니다. 프라이머리 키와 유사하게 고유성을 보장하지만, 프라이머리 키와는 달리 null 값을 허용할 수 있으며 한 테이블에 여러 개 설정할 수 있습니다. 다음은 유니크 인덱스의 주요 특징과 역할에 대한 상세한 설명입니다:

  • Data Integrity: 유니크 인덱스는 특정 컬럼의 값이 테이블 내에서 중복되지 않도록 보장합니다. 이를 통해 데이터의 정확성과 무결성을 유지할 수 있습니다. 예를 들어, 이메일 주소와 같은 고유한 정보를 저장하는 컬럼에 유니크 인덱스를 적용하여 중복된 이메일 주소가 저장되지 않도록 할 수 있습니다.
  • Performance Improvement: 유니크 인덱스는 특정 컬럼에 대한 검색 성능을 향상시킵니다. 인덱스는 B-Tree와 같은 자료 구조로 구현되어 있어, 검색, 삽입, 삭제 작업이 빠르게 수행될 수 있습니다. 유니크 인덱스는 특히 고유한 값을 기반으로 하는 검색 작업에서 높은 성능을 발휘합니다.
  • Constraint Enforcement: 유니크 인덱스는 데이터베이스의 제약 조건을 통해 데이터 무결성을 강제합니다. 데이터베이스는 새로운 값이 삽입되거나 기존 값이 업데이트될 때 유니크 인덱스를 검사하여 중복된 값이 없는지 확인합니다. 중복된 값이 있으면 삽입이나 업데이트 작업이 실패하게 됩니다.

다음은 MySQL에서 유니크 인덱스를 정의하는 예시입니다. 사용자 테이블에서 이메일 컬럼에 유니크 인덱스를 설정합니다.

MySQL
create table USERS
(
    user_id  bigint auto_increment,
    username varchar(50),
    email    varchar(100),
    primary key (user_id),
    unique (email)
);

사용자 테이블의 email 컬럼에 유니크 인덱스가 설정되어 있어, 다음과 같이 중복된 이메일 주소를 삽입하려고 하면 오류가 발생합니다. 유니크 인덱스가 중복 데이터를 허용하지 않기 때문입니다.

MySQL
playgrounds> insert into
                 USERS (username, email)
             values
                 ('ongs', 'ongs@catsriding.com')
[2024-05-26 23:36:07] 1 row affected in 7 ms
playgrounds> insert into
                 USERS (username, email)
             values
                 ('mongs', 'mongs@catsriding.com')
[2024-05-26 23:36:09] 1 row affected in 3 ms
playgrounds> insert into
                 USERS (username, email)
             values
                 ('cats', 'mongs@catsriding.com')
[2024-05-26 23:36:10] [23000][1062] Duplicate entry 'mongs@catsriding.com' for key 'users.email'

다음과 같이 쿼리를 통해 유니크 인덱스의 설정을 확인할 수 있습니다:

MySQL
show index from USERS where Key_name = 'email';

이 쿼리는 USERS 테이블에서 인덱스로 설정된 email 컬럼에 대한 정보를 보여줍니다.

MySQL
+-----+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|Table|Non_unique|Key_name|Seq_in_index|Column_name|Collation|Cardinality|Sub_part|Packed|Null|Index_type|Comment|Index_comment|Visible|Expression|
+-----+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|USERS|0         |email   |1           |email      |A        |2          |null    |null  |YES |BTREE     |       |             |YES    |null      |
+-----+----------+--------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+

이 결과를 통해 인덱스가 유니크 인덱스임을 확인할 수 있는 방법은 Non_unique 컬럼의 값을 확인하는 것입니다. Non_unique 값이 0인 경우 해당 인덱스가 유니크 인덱스임을 나타냅니다.

여러 컬럼을 유니크 인덱스로 설정할 수도 있습니다. 예를 들어, 사용자 테이블에서 usernameemail 컬럼의 조합에 유니크 인덱스를 설정할 수 있습니다.

MySQL
create table USERS
(
    user_id  bigint auto_increment,
    username varchar(50),
    email    varchar(100),
    primary key (user_id),
    unique (username, email)
);

이렇게 두 개의 컬럼을 조합하여 유니크 인덱스로 설정하면, 두 컬럼의 조합 값이 테이블 내에서 중복되지 않도록 보장할 수 있습니다. 예를 들어, 다음과 같이 중복된 값이 삽입되려고 하면 오류가 발생합니다.

MySQL
playgrounds> insert into
                 USERS (username, email)
             values
                 ('ongs', 'ongs@catsriding.com')
[2024-05-27 00:07:42] 1 row affected in 6 ms
playgrounds> insert into
                 USERS (username, email)
             values
                 ('mongs', 'mongs@catsriding.com')
[2024-05-27 00:07:42] 1 row affected in 3 ms
playgrounds> insert into
                 USERS (username, email)
             values
                 ('mongs', 'ongs@catsriding.com')
[2024-05-27 00:07:42] 1 row affected in 2 ms
playgrounds> insert into
                 USERS (username, email)
             values
                 ('mongs', 'mongs@catsriding.com')
[2024-05-27 00:07:42] [23000][1062] Duplicate entry 'mongs-mongs@catsriding.com' for key 'users.username'

유니크 인덱스는 데이터 무결성을 보장하지만, 이를 유지하기 위한 비용도 발생합니다. 다음과 같은 요소를 고려해야 합니다:

  • 성능 오버헤드: 데이터 삽입, 업데이트 시 유니크 인덱스를 유지하기 위한 추가적인 성능 오버헤드가 발생할 수 있습니다. 이는 중복된 값을 방지하기 위해 매번 데이터베이스가 기존 값을 확인하는 작업이 필요하기 때문입니다.
  • 추가 저장 공간 필요: 인덱스를 저장하기 위해 추가적인 저장 공간이 필요합니다.
  • 복잡성 증가: 여러 유니크 인덱스를 관리하는 것은 데이터베이스 스키마의 복잡성을 증가시킬 수 있습니다.

유니크 인덱스는 데이터베이스 관리와 데이터 무결성 유지에 중요한 도구입니다. 이를 적절하게 사용하면 데이터의 중복을 방지하고, 성능을 최적화하며, 데이터의 정확성을 보장할 수 있습니다.

Non-Unique Index

비고유 인덱스(Non-Unique Index)는 데이터베이스 테이블의 특정 컬럼(또는 컬럼의 조합)에 대해 중복된 값을 허용하는 인덱스입니다. 비고유 인덱스는 주로 조회 성능을 향상시키기 위해 사용됩니다. 일반적으로 개발자들이 인덱스를 언급할 때, 대부분 이 비고유 인덱스를 의미합니다. 다음은 비고유 인덱스의 주요 특징과 역할에 대한 상세한 설명입니다:

  • Performance Improvement: 비고유 인덱스는 특정 컬럼에 대한 검색 성능을 향상시킵니다. 인덱스는 B-Tree와 같은 자료 구조로 구현되어 있어, 검색, 삽입, 삭제 작업이 빠르게 수행될 수 있습니다. 비고유 인덱스는 특히 다중 레코드 검색 작업에서 높은 성능을 발휘합니다.
  • Multiple Values: 비고유 인덱스는 중복된 값을 허용하므로, 동일한 값이 여러 레코드에 존재할 수 있습니다. 예를 들어, 주문 테이블에서 주문 날짜에 비고유 인덱스를 적용하면, 여러 주문이 동일한 날짜를 가질 수 있습니다.
  • Flexible Querying: 비고유 인덱스는 다양한 검색 조건을 지원하며, 조인 연산에서도 유용하게 사용될 수 있습니다. 이는 대규모 데이터셋에서의 성능을 크게 향상시킵니다.

비고유 인덱스는 조회 성능을 최적화하기 위해 주로 사용됩니다. 예를 들어, 대규모 테이블에서 특정 컬럼에 대한 빈번한 조회가 발생하는 경우, 해당 컬럼에 비고유 인덱스를 설정하면 조회 속도가 크게 향상될 수 있습니다. 비고유 인덱스는 다음과 같은 상황에서 특히 유용합니다:

  • 자주 조회되는 컬럼: 예를 들어, 주문 테이블에서 특정 주문 날짜의 주문을 자주 조회하는 경우, order_date 컬럼에 비고유 인덱스를 설정하면 성능이 향상됩니다.
  • 조인 연산이 빈번한 경우: 여러 테이블 간의 조인 연산에서 특정 컬럼을 자주 사용한다면, 해당 컬럼에 비고유 인덱스를 설정하여 조인 성능을 최적화할 수 있습니다.
  • 정렬 및 그룹화 작업: 특정 컬럼을 기준으로 정렬하거나 그룹화하는 작업이 빈번한 경우, 해당 컬럼에 비고유 인덱스를 설정하면 이러한 연산의 성능이 향상됩니다.

다음은 MySQL에서 비고유 인덱스를 정의하는 예시입니다. 주문 테이블에서 order_date에 비고유 인덱스를 설정합니다.

MySQL
create table ORDERS
(
    order_id    bigint auto_increment,
    customer_id bigint,
    order_date  date,
    status      varchar(20),
    primary key (order_id),
    key (order_date)
);

위의 예시에서 order_date 컬럼에 비고유 인덱스를 설정함으로써, 특정 날짜에 주문된 모든 주문을 빠르게 조회할 수 있습니다.

비고유 인덱스의 설정을 확인하려면 다음과 같은 쿼리를 사용할 수 있습니다:

MySQL
show index from ORDERS where Key_name = 'order_date';

이 쿼리는 ORDERS 테이블에서 인덱스로 설정된 order_date 컬럼에 대한 정보를 보여줍니다.

MySQL
+------+----------+----------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|Table |Non_unique|Key_name  |Seq_in_index|Column_name|Collation|Cardinality|Sub_part|Packed|Null|Index_type|Comment|Index_comment|Visible|Expression|
+------+----------+----------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+
|ORDERS|1         |order_date|1           |order_date |A        |0          |null    |null  |YES |BTREE     |       |             |YES    |null      |
+------+----------+----------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------+

이 결과를 통해 인덱스가 비고유 인덱스임을 확인할 수 있는 방법은 Non_unique 컬럼의 값을 확인하는 것입니다. Non_unique 값이 1인 경우 해당 인덱스가 비고유 인덱스임을 나타냅니다.

비고유 인덱스를 설정하면 특정 날짜뿐만 아니라 특정 날짜 이후나 이전과 같은 범위 검색에도 인덱스가 영향을 미칩니다. 다음과 같은 쿼리를 통해 범위 검색을 수행할 수 있습니다:

MySQL
select
    *
from
    ORDERS orders
where
    orders.order_date between '2024-01-01' and '2024-01-31';

이 쿼리는 ORDERS 테이블에서 2024년 1월 1일부터 2024년 1월 31일까지의 모든 주문을 조회합니다. order_date 컬럼에 설정된 인덱스 덕분에 이러한 범위 검색이 효율적으로 수행됩니다.

비고유 인덱스는 조회 성능을 최적화하기 위해 주로 사용됩니다. 이를 통해 대규모 데이터셋에서도 효율적으로 데이터를 검색하고 정렬할 수 있습니다. 그러나 비고유 인덱스를 설정할 때도 몇 가지 주의사항이 있습니다:

  • 성능 오버헤드: 데이터 삽입, 업데이트 시 비고유 인덱스를 유지하기 위한 추가적인 성능 오버헤드가 발생할 수 있습니다. 인덱스를 갱신해야 하기 때문입니다.
  • 추가 저장 공간 필요: 인덱스를 저장하기 위해 추가적인 저장 공간이 필요합니다.
  • 복잡성 증가: 여러 비고유 인덱스를 관리하는 것은 데이터베이스 스키마의 복잡성을 증가시킬 수 있습니다.

비고유 인덱스는 애플리케이션 조회 성능 향상에 중요한 도구입니다. 이를 적절하게 사용하면 대규모 데이터셋에서도 효율적으로 데이터를 검색하고 관리할 수 있습니다.

Function-Based Index

함수형 인덱스(Function-Based Index)는 데이터베이스 테이블의 컬럼 값에 특정 함수나 식을 적용한 결과를 인덱싱하는 인덱스입니다. 함수형 인덱스는 복잡한 검색 조건이나 표현식을 포함하는 쿼리의 성능을 향상시키기 위해 사용됩니다. 이를 통해 데이터 검색이 보다 효율적으로 이루어질 수 있습니다.

함수형 인덱스의 주요 특징과 역할에 대한 상세한 설명은 다음과 같습니다:

  • Specific Function or Expression Indexing: 함수형 인덱스는 단순히 컬럼 값을 인덱싱하는 것이 아니라, 특정 함수나 표현식의 결과를 인덱싱합니다. 이를 통해 특정 조건이나 패턴에 대한 검색을 최적화할 수 있습니다.
  • Enhanced Query Performance: 함수형 인덱스는 자주 사용되는 함수나 복잡한 조건이 포함된 쿼리의 성능을 향상시키는 데 유용합니다. 예를 들어, 대소문자를 구분하지 않는 검색이나 특정 형식의 데이터 변환을 포함하는 검색에 효과적입니다.
  • Query Plan Optimization: 함수형 인덱스를 활용하면 데이터베이스 엔진이 보다 효율적인 쿼리 계획을 생성할 수 있어 검색 성능이 크게 개선됩니다.

MySQL 8.0부터는 테이블의 구조를 변경하지 않고, 함수나 표현식을 직접 인덱스 생성 구문에 사용할 수 있게 되었습니다. 이는 데이터베이스 성능 최적화에 중요한 역할을 하며, 특히 복잡한 검색 조건이나 계산된 값의 검색을 빠르게 수행할 수 있게 합니다. 다음은 이러한 함수형 인덱스의 예시와 설명입니다.

다음은 MySQL 8.0에서 함수형 인덱스를 사용하는 예시입니다. 사용자 테이블에서 first_namelast_name 컬럼을 결합하여 인덱싱하는 방법을 보여줍니다:

MySQL
create table USERS
(
    user_id    bigint auto_increment,
    first_name varchar(10),
    last_name  varchar(10),
    primary key (user_id),
    index ix_fullname ((concat(first_name, ' ', last_name)))
);

이렇게 CONCAT(first_name, ' ', last_name) 함수를 직접 사용하여 인덱스를 생성할 수 있습니다. 이 인덱스를 통해 first_namelast_name이 결합된 Full Name 형식을 빠르게 검색할 수 있습니다.

다음은 함수형 인덱스를 활용한 쿼리 예시입니다:

MySQL
select
    *
from
    USERS
where
    concat(first_name, ' ', last_name) = 'Ongs Jynn';

이 쿼리는 CONCAT(first_name, ' ', last_name) 인덱스를 사용하여 first_namelast_nameOngs Jynn인 사용자를 빠르게 검색합니다.

다른 인덱스와 마찬가지로 함수형 인덱스의 설정을 확인하려면 다음과 같은 쿼리를 사용할 수 있습니다:

MySQL
show index from USERS where Key_name = 'ix_fullname';

다음 쿼리 결과를 살펴보면 Expression 컬럼에 함수 표현식이 추가된 것을 확인할 수 있습니다:

MySQL
+-----+----------+-----------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------------------------------------------+
|Table|Non_unique|Key_name   |Seq_in_index|Column_name|Collation|Cardinality|Sub_part|Packed|Null|Index_type|Comment|Index_comment|Visible|Expression                                    |
+-----+----------+-----------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------------------------------------------+
|USERS|1         |ix_fullname|1           |null       |A        |1          |null    |null  |YES |BTREE     |       |             |YES    |concat(`first_name`,_utf8mb4\' \',`last_name`)|
+-----+----------+-----------+------------+-----------+---------+-----------+--------+------+----+----------+-------+-------------+-------+----------------------------------------------+

함수형 인덱스를 사용할 때는 다음과 같은 점을 고려해야 합니다:

  • Index Maintenance Overhead: 함수형 인덱스를 생성하고 유지 관리하는 데 추가적인 오버헤드가 발생할 수 있습니다. 인덱스가 복잡할수록 더 많은 리소스를 필요로 할 수 있습니다.
  • Expression Consistency: 함수형 인덱스를 효과적으로 사용하려면, 인덱싱된 표현식과 쿼리에서 사용되는 표현식이 일치해야 합니다. 예를 들어, 인덱싱된 함수가 CONCAT(first_name, ' ', last_name)이라면, 쿼리에서도 동일한 함수가 사용되어야 합니다.
  • Query Plan Optimization: 데이터베이스 엔진이 함수형 인덱스를 최적화하여 활용할 수 있도록 쿼리 계획을 신중하게 설정해야 합니다.

함수형 인덱스는 프라이머리 키, 외래 키, 유니크 인덱스, 비고유 인덱스와 함께 데이터베이스 성능 최적화의 중요한 도구로 간주됩니다. 이를 통해 복잡한 쿼리 조건을 효율적으로 처리하고, 데이터베이스의 검색 성능을 극대화할 수 있습니다.


  • Database
  • MySQL