MySQL 인덱스는 어떻게 작동합니까?


402

MySQL 인덱스의 작동 방식, 특히 전체 테이블을 스캔하지 않고 요청 된 데이터를 어떻게 반환 할 수 있습니까?

주제가 맞지 않습니다. 그러나 이것을 자세히 설명 할 수있는 사람이 있다면 매우 감사 할 것입니다.



이것은 매우 광범위한 질문입니다. 인덱스를 사용하지 않는 특정 쿼리 예제가 있고 그 이유를 모르는 경우 쿼리를 게시하면 사람들이 도움을 줄 수 있습니다.
Hammerite

SELECT * FROM members WHERE id = '1'왜 인덱스를 사용하면 더 빨리 작동합니까? 그 인덱스는 무엇입니까?
good_evening

2
이는 인덱스 된 특정 레코드 (기본 키로 식별)를 조회하는 쿼리처럼 보입니다. 인덱스는 메모리에 저장되어 해당 인덱스 행을 볼 수 있으며 실제 데이터가 저장된 위치에 대한 포인터를 포함하기 때문에이 작업을 더 빠르게 수행 할 수 있습니다. 따라서 MySQL은 테이블을 스캔하지 않고도 테이블의 정확한 위치로 이동할 수 있습니다.
Hammerite

정말 고마워요!
궤도에서 가벼움 레이스

답변:


513

기본적으로 테이블의 인덱스는 책의 인덱스와 같이 작동합니다 (이름이 나온 곳).

데이터베이스에 관한 책이 있고 스토리지에 대한 정보를 찾고 싶다고 가정 해 봅시다. 색인이 없으면 (목차와 같은 다른 보조 도구가 없다고 가정 할 때) 주제를 찾을 때까지 (즉, full table scan) 페이지를 하나씩 살펴 봐야합니다 . 반면에 색인에는 키워드 목록이 있으므로 색인을 참조하여storage 113-120,231 및 354 페이지에 나와있는 그런 다음 검색하지 않고 해당 페이지로 직접 넘길 수 있습니다 (즉, 색인, 다소 빠름).

물론 인덱스가 얼마나 유용한지는 위의 비유를 사용하여 몇 가지 예에 따라 다릅니다.

  • 데이터베이스에 관한 책이 있고 "데이터베이스"라는 단어를 색인화 한 경우, 1-59,61-290 및 292-400 페이지에 언급되어있는 것을 알 수 있습니다. 이러한 경우 색인이 큰 도움이되지 않아서 한 페이지 씩 하나씩 더 빨리 가야합니다 (데이터베이스에서 "잘못된 선택"입니다).
  • 10 페이지짜리 책의 경우 5 페이지 색인으로 시작하는 10 페이지짜리 책으로 끝날 수 있으므로 색인을 만드는 것은 의미가 없습니다. 10 페이지를 스캔하여 완료하면됩니다. .
  • 색인도 유용해야합니다. 일반적으로 색인 할 점이 없습니다 (예 : 페이지 당 문자 "L"의 빈도).

3
내부적으로 기술적으로 어떻게 작동하는지가 아니라 무엇인지 설명하고 있습니다.
Tutu Kumari

@ Tutu Kumari : 질문의 수정본을보십시오; 현재 질문에 맞게 답변을 자유롭게 수정하십시오 (다양한 엔진 및 색인 유형에 유의하십시오 (예 : 여기 문서 참조 : dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html ))
Piskvor 건물 왼쪽

259

가장 먼저 알아야 할 것은 인덱스가 원하는 결과를 얻기 위해 전체 테이블을 스캔하지 않는 방법이라는 것입니다.

다양한 종류의 인덱스가 있으며 스토리지 계층에서 구현되므로 인덱스간에 표준이 없으며 사용중인 스토리지 엔진에 따라 다릅니다.

InnoDB 및 B + Tree 인덱스

InnoDB의 경우 가장 일반적인 인덱스 유형은 요소를 정렬 된 순서대로 저장하는 B + Tree 기반 인덱스입니다. 또한 인덱스 된 값을 얻기 위해 실제 테이블에 액세스 할 필요가 없으므로 쿼리 반환 속도가 빨라집니다.

이 인덱스 유형에 대한 "문제"는 인덱스를 사용하기 위해 가장 왼쪽의 값을 쿼리해야한다는 것입니다. 따라서 인덱스에 last_name 및 first_name과 같은 두 개의 열이있는 경우 이러한 필드를 쿼리하는 순서가 중요합니다 .

따라서 다음 표를 참고하십시오.

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

이 쿼리는 인덱스를 활용합니다.

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

그러나 다음 중 하나는

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

당신이 쿼리하기 때문에 first_name먼저 열을 하고 인덱스에서 가장 왼쪽 열이 아니기 때문입니다.

이 마지막 예는 훨씬 더 나쁩니다.

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

이제 인덱스에서 가장 오른쪽 필드의 가장 오른쪽 부분을 비교하고 있습니다.

해시 인덱스

불행히도 메모리 백엔드 만 지원하는 다른 인덱스 유형입니다. 그것은의 번개 빠르지 만 작업이 좋아하는 당신이 그것을 사용할 수 없음을 의미합니다 전체 조회에 대한 유용 >, <또는 LIKE.

메모리 백엔드에서만 작동하므로 자주 사용하지 않을 것입니다. 내가 지금 생각할 수있는 주요 사례는 다른 선택의 결과 집합으로 메모리에 임시 테이블을 만들고 해시 인덱스를 사용 하여이 임시 테이블에서 다른 많은 선택을 수행하는 경우입니다.

VARCHAR필드 가있는 경우 B- 트리를 사용할 때 다른 열을 만들고 큰 값의 해시를 저장하여 해시 인덱스 사용을 "에뮬레이션"할 수 있습니다. 필드에 URL을 저장하고 있으며 값이 상당히 크다고 가정 해 봅시다. 또한 정수 필드를 생성 url_hash하고 해시 함수 CRC32또는 다른 해시 함수를 사용하여 URL을 삽입 할 때 해시 할 수 있습니다. 그런 다음이 값을 쿼리해야 할 때 다음과 같은 작업을 수행 할 수 있습니다.

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

위 예제의 문제점은 CRC32함수가 아주 작은 해시를 생성하므로 해시 된 값에서 많은 충돌이 발생한다는 것입니다. 정확한 값이 필요한 경우 다음을 수행하여이 문제를 해결할 수 있습니다.

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

충돌 횟수가 크더라도 반복되는 해시에 대한 두 번째 비교 (문자열 1) 만 수행 할 경우에도 여전히 해싱 할 가치가 있습니다.

불행히도이 기술을 사용하면 url필드 를 비교하기 위해 여전히 테이블을 쳐야합니다 .

마무리

최적화에 대해 이야기하고 싶을 때마다 고려해야 할 몇 가지 사실 :

  1. 정수 비교는 문자열 비교보다 훨씬 빠릅니다. 의 해시 인덱스 에뮬레이션에 대한 예를 통해 설명 할 수 있습니다 InnoDB.

  2. 프로세스에 단계를 추가하면 속도가 느려지지 않고 빨라질 수 있습니다. a SELECT를 두 단계로 나눠서 최적화 하여 첫 번째 값을 새로 만든 인 메모리 테이블에 저장 한 다음이 두 번째 테이블에서 더 많은 쿼리를 실행할 수 있다는 사실을 알 수 있습니다 .

MySQL에는 다른 인덱스도 있지만 B + Tree는 가장 많이 사용되며 해시는 잘 알고 있지만 MySQL 설명서 에서 다른 것을 찾을 수 있다고 생각합니다. .

"High Performance MySQL"책을 읽는 것이 좋습니다. 위의 답변은 인덱스에 대한 장을 기반으로 한 것입니다.


2
위의 경우 다음 쿼리가 유리합니까? 1. SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
하기 Akshay 타루

1
첫 번째 쿼리는 두 번째 쿼리는 수행하지 않습니다. EXPLAIN 사용 : dev.mysql.com/doc/refman/5.5/en/explain.html MySQL에서 두 번째 쿼리를 인덱싱하려면 전체 텍스트 색인을 사용해야합니다. dev.mysql.com/doc/refman/5.5/en/fulltext- search.html
에밀리오 니콜라스

5
나는 당신이 127에 있었고 # 1 답변이 256에 있었기 때문에 당신을 찬성했습니다. 나는 모든 것을 멋지고 깨끗하고 바이너리로 만드는 것을 피할 수 없었습니다.
pbarney

이것은 저에게 새로운 정보였습니다. "이 필드를 쿼리하는 순서가 중요합니다." 감사.
Khatri

1
3 년 후 @ pbarney는 각각 256과 512에 가깝습니다.
nanocv 2018

43

기본적으로 색인은 순서대로 정렬 된 모든 키의 맵입니다. 순서대로 목록을 작성하면 모든 키를 확인하는 대신 다음과 같은 작업을 수행 할 수 있습니다.

1 : 목록의 중간으로 이동-내가 찾고있는 것보다 높거나 낮습니까?

2 : 높으면 중간과 아래쪽 중간 지점으로 이동하고 낮 으면 중간과 위쪽

3 : 더 높거나 낮습니까? 다시 중간 지점으로 이동

이 논리를 사용하면 모든 항목을 확인하는 대신 약 7 단계로 정렬 된 목록에서 요소를 찾을 수 있습니다.

분명히 복잡성이 있지만 기본 아이디어를 제공합니다.


29
이것을 이진 검색이라고합니다.
ddlshack

감사합니다. 마지막으로 db가 인덱스와 함께 작동하는 방법이 아니라 왜 더 빠른지 설명하는 답변입니다.
Gershon Herczeg

실제 단계 수는 데이터에 따라 달라집니다. 고유 한 값의 수와 범위 전체의 분포입니다. 7은 100 개의 값에 대한 이론상 최대 값입니다. 여기에서 단계 수를 계산하는 방법에 대한 자세한 설명 stackoverflow.com/questions/10571170/…
Joshua

가장 일반적인 MySQL 인덱스는 이진 검색과 유사하지만 동일하지 않은 B + Tree입니다. 알고리즘 복잡도는 동일하지만 검색 방식이 다릅니다. 참조 en.wikipedia.org/wiki/B-tree
매트

4

이 링크를 살펴보십시오 : http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

그들이 작동하는 방식은 하나의 SO 게시물에서 다루기에는 너무 광범위합니다.

다음 은 내가 본 인덱스에 대한 가장 좋은 설명 중 하나입니다. 불행히도 MySQL이 아닌 SQL Server 용입니다. 두 사람이 얼마나 비슷한 지 잘 모르겠습니다 ...


2
좋은 기사. SQL Server를 모르지만 기본 작업은 매우 유사합니다. (metanote가 : 2 링크 된 문서를 보이게의 콘텐츠를 CSS 스타일을 사용하지 않도록 설정)
Piskvor 건물 왼쪽

3

에서 받아 인덱싱에 대한 자세한 내용은 동영상

단순 인덱싱 테이블에서 고유 인덱스를 만들 수 있습니다. 고유 색인은 두 행이 동일한 색인 값을 가질 수 없음을 의미합니다. 다음은 테이블에서 인덱스를 작성하는 구문입니다.

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

하나 이상의 열을 사용하여 색인을 작성할 수 있습니다. 예를 들어 tutorials_tbltutorial_author 를 사용하여 인덱스를 만들 수 있습니다 .

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

테이블에서 간단한 인덱스를 만들 수 있습니다. 쿼리에서 UNIQUE 키워드를 생략하면 간단한 색인이 생성됩니다. 단순 인덱스는 테이블에서 중복 값을 허용합니다.

열의 값을 내림차순으로 색인화하려는 경우 열 이름 뒤에 예약어 DESC를 추가 할 수 있습니다.

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)

1
스택 오버플로에 오신 것을 환영합니다! 모든 답변이 자신의 동영상에 연결되어 있습니다. 주의하시기 바랍니다 명백한 자기 홍보가 허용되지 않습니다 .
SL Barth-복원 모니카

그는 자신의 동영상을 홍보하려고합니다. LOL
Ilyas karim

1

2 센트를 더하고 싶습니다. 나는 데이터베이스 전문가가 아니었지만 최근이 주제에 대해 조금 읽었습니다. 내가 ELI5를 시도하고 줄 정도로 충분합니다. 그래서 여기 평신도의 설명이 있습니다.


나는 인덱스가 테이블의 미니 미러와 같고 연관 배열과 매우 비슷하다는 것을 이해합니다. 일치하는 키를 제공하면 하나의 "명령"에서 해당 행으로 이동할 수 있습니다.

그러나 해당 인덱스 / 배열이없는 경우 쿼리 인터프리터는 for-loop를 사용하여 모든 행을 통과하고 일치 (전체 테이블 스캔)를 확인해야합니다.

인덱스가 있으면 콘텐츠를 더 빨리 찾는 "업사이드"대신에 추가 스토리지 (그 미니 미러 용)의 "다운 사이드"가 있습니다.

(DB 엔진에 따라) 기본, 외래 또는 고유 키를 생성하면 해당 인덱스도 자동으로 설정됩니다. 같은 원리가 기본적으로 그 키가 작동하는 이유와 방법입니다.


1

답변 목록에 시각적 표현 추가 여기에 이미지 설명을 입력하십시오

MySQL은 추가 간접 계층을 사용합니다. 보조 인덱스 레코드는 기본 인덱스 레코드를 가리키고 기본 인덱스 자체는 디스크상의 행 위치를 보유합니다. 행 오프셋이 변경되면 기본 인덱스 만 업데이트하면됩니다.

주의 사항 : 디스크 데이터 구조는 다이어그램에서 평평 해 보이지만 실제로는 B + 트리입니다.

출처 : 링크


1

MySQL InnoDB에는 두 가지 유형의 인덱스가 있습니다.

  1. 클러스터형 인덱스라고하는 기본 키. 인덱스 키워드는 실제 레코드 데이터와 함께 B + Tree 리프 노드에 저장됩니다.

  2. 비 클러스터형 인덱스 인 보조 키. 이 인덱스는 기본 키 키워드와 B + Tree 리프 노드에 자체 인덱스 키워드 만 저장합니다. 따라서 보조 인덱스에서 검색 할 때는 먼저 기본 키 인덱스 키워드를 찾고 기본 키 B + 트리를 스캔하여 실제 데이터 레코드를 찾습니다. 이로 인해 기본 인덱스 검색에 비해 보조 인덱스가 느려집니다. 그러나 select열이 모두 보조 인덱스에 있으면 기본 인덱스 B + Tree를 다시 찾을 필요가 없습니다. 이것을 커버링 인덱스라고합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.