MySQL 기술 인사이더 InnoDB 스토리지 엔진 연구 노트 5 장 인덱스 및 알고리즘

인덱스가 너무 많으면 응용 프로그램의 성능에 영향을줍니다. 삽입 할 때마다 인덱스를 업데이트하고 디스크에 저장해야하므로 디스크 IO가 증가합니다. 인덱스가 너무 적 으면 쿼리 성능에 영향을줍니다. 찾기 균형.

InnoDB는 B + 트리 인덱스와 해시 인덱스를 지원합니다. InnoDB의 해시 인덱스는 가변적이며, InnoDB는 테이블의 용도에 따라 테이블에 대한 해시 인덱스를 생성하며 테이블에 해시 인덱스 생성 여부를 인위적으로 개입 할 수 없습니다. B + 트리 구조는 이진 트리와 유사합니다. 현재 관계형 데이터베이스 시스템에서 키-값 쌍을 기반으로 데이터를 빠르게 찾기 위해 가장 일반적으로 사용되는 가장 효과적인 인덱스입니다. B + 트리의 B는 이진을 나타내지 않지만 균형을 나타냅니다. B + 트리는 가장 오래된 것입니다. 균형 이진 트리는 진화했지만 B + 트리는 이진 트리가 아닙니다.

B + 트리 인덱스는 주어진 키 값을 가진 특정 행을 찾을 수 없지만 데이터 행이있는 페이지를 찾은 다음 MySQL은 페이지를 메모리로 읽어 들인 다음 메모리에서 검색합니다.

평균적으로 이진 검색은 순차 검색보다 효율적입니다. 각 페이지의 페이지 디렉토리에있는 슬롯은 기본 키의 순서로 저장되며 특정 레코드에 대한 쿼리는 페이지 디렉토리에서 이진 검색을 통해 얻습니다.

균형 잡힌 이진 트리 정의 : 첫째, 이진 검색 트리의 정의를 충족하고, 둘째, 모든 노드의 왼쪽 및 오른쪽 하위 트리 높이의 최대 차이가 1임을 충족해야합니다.

균형 잡힌 이진 트리의 검색 성능은 최고에 가깝습니다. 최상의 성능을 얻으려면 최적의 이진 트리를 구축해야합니다. 그러나 최적의 이진 트리를 구축하고 유지하려면 많은 작업이 필요하며 일반적으로 균형 잡힌 이진 트리가 필요합니다.

균형 이진 트리의 쿼리 속도는 매우 빠르지 만 균형 이진 트리를 유지하는 데 드는 비용이 매우 높습니다. 일반적으로 삽입 또는 업데이트 후 트리의 균형을 얻기 위해 한 번 이상의 왼쪽 및 오른쪽 회전이 필요합니다. 균형 바이너리 트리는 다음과 같습니다.
여기에 사진 설명 삽입
새로운 값이 삽입되면 균형을 유지하기 위해 다음 작업을 수행해야합니다.
여기에 사진 설명 삽입
위의 그림은 삽입 된 트리를 한 번 왼쪽으로 돌려 균형을 다시 맞추도록합니다. 때로는 여러 번 회전해야합니다. In the
여기에 사진 설명 삽입
B + 트리에서 모든 레코드 노드는 키 값 순서대로 동일한 레이어에 저장됩니다. 노드에서 리프 노드는 포인터로 연결됩니다. 다음 B + 트리의 높이는 2이며 각 페이지는 4 개의 레코드를 저장할 수 있습니다. 팬 아웃은 5
여기에 사진 설명 삽입
입니다. 이진 트리를 삽입하면 백 리프 노드에 삽입 된 레코드가 여전히 순서대로 유지되는지 확인해야합니다.
여기에 사진 설명 삽입
그림 5의 경우 -6의 B + 트리에서 28 개의 키 값을 삽입하고 Leaf Page와 Index Page가 꽉 차 있지 않고 직접 삽입하면됩니다.
여기에 사진 설명 삽입
키 값이 70 인 행을 삽입하면 Leaf Page는 이미 꽉 찼지만 Index Page는 아직 꽉 찼습니다. Full, Leaf Page에 삽입하면 Full, 상황은 55, 55, 60, 65, 70이고 중간 값 60에 따라
여기에 사진 설명 삽입
리프 노드가 분할됩니다 . 위 그림에서는 리프 노드 간의 포인터가 생략되었습니다. 그런 다음 키 값이 95 인 행을 삽입합니다. 이때 리프 페이지와 인덱스 페이지가 모두 꽉 찼으며 두 개의 분할이 필요합니다.
여기에 사진 설명 삽입
위의 테이블은 리프 노드 간의 포인터도 생략합니다. 어떻게 변경해도 B + 트리는 항상 균형을 유지하지만 균형을 유지하기 위해 새로 삽입 된 키 값에 대해 많은 페이지 분할 작업이 필요할 수 있습니다. B + 트리는 주로 페이지 분할은 디스크 작업을 의미합니다. 가능하면 페이지 분할을 줄여야하므로 B + 트리 회전 작업이 제공됩니다.

B + 트리 회전은 Leaf Page가 꽉 찼지만 왼쪽과 오른쪽 형제 노드가 꽉 찼을 때 발생합니다. 이때 B + 트리는 먼저 페이지를 분할하지 않고 레코드를 페이지의 형제 노드로 전송합니다. 일반적으로 왼쪽 형제가 먼저 확인되므로 키 값이 70 인 행이 그림 5-7에 삽입되면 먼저
여기에 사진 설명 삽입
회전합니다. 회전을 사용하면 B + 트리에 대한 페이지 분할 작업 수가 줄어들고 높이가 줄어 듭니다. B + 트리는 여전히 2입니다.

B + 트리는 채우기 비율을 사용하여 트리의 삭제 및 변경을 제어하며, 50 %는 채우기 비율을 설정할 수있는 최소값입니다. B + 트리의 삭제 작업은 또한 리프 노드의 레코드가 삭제 후에도 순서대로 유지되도록해야합니다.

여기에 사진 설명 삽입
삭제 작업의 채우기 비율이 50 %라고 가정합니다.

그림 5-9의 B + 트리에서 키 값이 70 인 레코드를
여기에 사진 설명 삽입
삭제하고 직접 삭제합니다 . 그런 다음 키 값이 25 인 레코드를 삭제합니다. 값을 삭제 한 후에도 값은 여전히 ​​인덱스 페이지의 값입니다. , 25의 오른쪽 형제 노드 인 인덱스 페이지 업데이트 :
여기에 사진 설명 삽입
그런 다음 키 값이 60 인 행을 삭제합니다. 삭제 후 리프 페이지의 채우기 비율이 50 % 미만이므로 병합 작업이 필요합니다. 인덱스 페이지에서 관련 레코드를 삭제하려면 인덱스 페이지를 병합해야합니다. :
여기에 사진 설명 삽입
B + 트리 인덱스 본질은 데이터베이스에서 B + 트리를 구현하는 것입니다. 데이터베이스에서 B + 인덱스의 한 가지 특징은 높은 팬 아웃입니다. 일반적으로 높이 데이터베이스의 B + 트리는 2 ~ 3 개의 레이어에 불과합니다.

데이터베이스의 B + 트리 인덱스는 클러스터형 인덱스와 보조 클러스터형 인덱스로 구분되며 내부 구조는 B + 트리로 균형이 잘 잡혀 있습니다.

InnoDB 엔진 테이블은 인덱스로 구성된 테이블입니다. 클러스터형 인덱스는 각 테이블의 기본 키에 따라 B + 트리를 구성합니다. 전체 테이블의 행 레코드는 리프 노드에 저장됩니다. 따라서 클러스터형 인덱스의 리프 노드는 데이터 페이지가됩니다. 각 데이터 페이지는 이중 연결 목록을 통해 연결됩니다.

실제 데이터 페이지는 B + 트리로만 정렬 할 수 있으므로 각 테이블에는 클러스터형 인덱스가 하나만있을 수 있습니다. 클러스터형 인덱스를 사용하면 인덱스의 리프 노드에서 직접 데이터를 찾을 수 있기 때문에 쿼리 최적화 프로그램은 클러스터형 인덱스를 사용하는 경향이 있습니다. .

각 페이지에 인위적으로 두 행의 레코드 만 저장할 수 있습니다.

CREATE TABLE t (
    a    INT NOT NULL PRIMARY KEY,
    b    VARCHAR(8000)
);

데이터 삽입 :

INSERT INTO t
SELECT 1, REPEAT('a', 7000);

INSERT INTO t
SELECT 2, REPEAT('a', 7000);

INSERT INTO t
SELECT 3, REPEAT('a', 7000);

INSERT INTO t
SELECT 4, REPEAT('a', 7000);

구성된 이진 트리는 다음과 같습니다.
여기에 사진 설명 삽입
많은 데이터베이스 문서에서 클러스터형 인덱스가 물리적 주소 순서로 데이터를 저장한다고하지만 클러스터형 인덱스가 특정 순서로 물리적 레코드를 저장해야하는 경우 유지 관리 비용이 매우 높습니다. 물리적으로 연속적이지 않지만 논리적으로 연속적입니다.

클러스터형 인덱스는 데이터의 논리적 순서를 정의하므로 기본 키 범위 값에 대한 쿼리에 빠르게 액세스 할 수 있습니다.
여기에 사진 설명 삽입
위 범위 쿼리에서 페이지 범위는 리프 노드의 상위 노드를 통해 얻은 다음 데이터를 얻을 수 있습니다. 페이지를 읽을 수 있습니다. 위 그림의 행 열은 정확한 값이 아닌 쿼리 결과의 반환 된 행의 예상 수를 제공합니다.

보조 인덱스 (비 클러스터형 인덱스) 리프 노드에는 행의 모든 ​​데이터가 포함되어 있지 않습니다. 키 값 외에도 리프 노드는 각 리프 수준의 인덱스 행에 책갈피를 포함하여 InnoDB 엔진에 위치를 알려줍니다. 해당 행을 찾습니다. 데이터 즉, 책갈피는 해당 데이터 행의 클러스터 된 인덱스 키입니다.

보조 인덱스는 클러스터형 인덱스의 데이터 구성에 영향을주지 않으며 각 테이블에 여러 보조 인덱스가있을 수 있습니다. 보조 인덱스를 통해 데이터를 찾을 때 보조 인덱스를 사용하여 보조 인덱스의 리프 노드에서 클러스터형 인덱스의 기본 키를 찾은 다음 기본 키 인덱스를 통해 전체 행 레코드를 찾습니다.

SQLserver와 같은 다른 데이터베이스의 경우 데이터 삽입 측면에서 MySQL의 MyISAM 엔진과 유사한 힙 테이블이라는 인덱스 구성되지 않은 테이블이 있습니다. 힙 테이블의 인덱스는 모두 클러스터되지 않고 힙 테이블에는 기본 키가 없습니다. 책갈피는 행 식별자입니다. 디스크의 실제 행은 "파일 번호 : 페이지 번호 : 슬롯"과 같은 형식으로 위치 할 수 있습니다. 번호".

힙 테이블의 비 클러스터형 인덱스는 기본 키를 통해 클러스터형 인덱스를 검색 할 필요가 없습니다. 읽기 전용의 경우 책갈피가 행 식별자 인 비 클러스터형 인덱스가 비 클러스터형 인덱스보다 빠를 수 있습니다. 북마크를 기본 키로 사용하지만 테이블이 증가하는 경우 삭제 및 수정과 같은 DML 작업 중에 행 식별자로 북마크가있는 비 클러스터형 인덱스는에서 가리키는 데이터 페이지의 위치를 ​​지속적으로 업데이트해야 할 수 있습니다. 이때 북마크를 기본 키로하는 클러스터되지 않은 인덱스보다 오버 헤드가 클 수 있습니다. 정렬 및 범위 검색의 경우 인덱스 구성 테이블은 B + 트리의 중간 노드를 통해 검색 할 모든 페이지를 찾을 수 있으며 힙 테이블의 특성으로 인해 불가능합니다. 그러나 일반 데이터베이스는 다중 불연속 읽기 작업을 피하기 위해 미리 읽기 기술을 사용합니다. 힙 테이블이 빠른지 인덱스로 구성된 테이블이 빠른지 여부는 특정 상황에 따라 다릅니다.

테이블에서 색인보기 :

SHOW INDEX FROM tableName;

테이블 t에 c 열을 추가하고이 열에 비 클러스터형 인덱스를 만듭니다.

ALTER TABLE t
ADD c INT NOT NULL;

이미 데이터가있는 테이블에 비어 있지 않은 열을 추가하면 열의 데이터는 자동으로 0 또는 빈 문자열이됩니다.

ALTER TABLE을 사용하여 인덱스 구문을 만들고 삭제합니다.

ALTER TABLE tbl_name
| ADD {
   
   INDEX|KEY} [index_name]
[index_type] (index_col_name, ...) [index_option] ...

ALTER TABLE tbl_name
DROP PRIMARY KEY
| DROP {
   
   INDEX|KEY} index_name

CREATE / DROP INDEX로 인덱스 생성 및 삭제 :

CREATE [UNIQUE] INDEX index_name
[index_type]
ON tbl_name (index_col_name, ...)

DROP INDEX index_name ON tbl_name

인덱스는 열에있는 데이터의 처음 100 바이트 만 인덱싱 할 수 있습니다. 예를 들어 이전에 생성 된 테이블 t 및 b 열은 varchar (8000)입니다.

ALTER TABLE t
ADD KEY idx_b(b(100));

MySQL의 일반적인 문제는 인덱스 추가 또는 삭제를 위해 MySQL이 먼저 새 임시 테이블을 생성 한 다음 데이터를 임시 테이블로 가져오고 원래 테이블을 삭제 한 다음 임시 테이블의 이름을 원래 테이블 이름으로 변경한다는 것입니다. 테이블이 추가되고 인덱스 삭제가 매우 느립니다. InnoDB Plugin부터는 빠른 인덱스 생성이라는 방법을 지원합니다. 보조 인덱스로만 제한됩니다. 기본 키의 생성과 삭제는 여전히 테이블을 재 구축해야합니다. 보조 인덱스의 경우 InnoDB는 먼저 테이블에 S를 추가합니다. 잠금, 생성 과정에서 테이블을 재 구축 할 필요는 없지만 생성 과정에서만 테이블을 읽을 수 있습니다. 보조 인덱스를 삭제하는이 방법은 보조 인덱스의 공간을 내부 뷰에서 사용 가능한 것으로 표시하기 만하면됩니다. InnoDB 엔진 업데이트 및 삭제 MySQL 내부 뷰의 테이블에 대한 인덱스 정의로 충분합니다.

공동 인덱스는 여러 열이있는 인덱스를 나타냅니다. 테이블 t에 조인트 인덱스를 생성합니다.

ALTER TABLE t
ADD KEY idx_a_b(a, c);

테이블의 인덱스 분석 :
여기에 사진 설명 삽입
여기에 사진 설명 삽입
여기에 사진 설명 삽입
여기에 사진 설명 삽입
테이블에는 기본 키 인덱스, 열 c의 인덱스, 열 b의 처음 100 바이트로 구성된 인덱스, 조인트 인덱스 (상단 테이블에서 두 행을 차지함)의 네 가지 인덱스가 있습니다. ). 위 쿼리 결과 필드의 의미 :
1. 테이블 : 인덱스가있는 테이블의 이름입니다.
2. Non_unique : 고유하지 않은 인덱스인지 여부에 관계없이 기본 키는 고유해야하므로 기본 키의 열은 0입니다.
3. Key_name : DROP INDEX에 사용할 수있는 인덱스 이름.
4. Seq_in_index : 인덱스에서 컬럼의 위치, 조인트 인덱스 idx_a_b를 예로 들면 1이 아닌 값은 조인트 인덱스에만 나타납니다.
5. Column_name : 인덱싱 된 열.
6. 데이터 정렬 : 인덱스에 열이 저장되는 방식. 'A'또는 NULL 일 수 있으며, B + 트리 인덱스는 항상 A이며 이는 정렬됨을 의미합니다. Heap 엔진을 사용하고 Hash 인덱스를 생성하면 Hash는 데이터를 정렬하지 않고 Hash 버킷에 따라 인덱스 데이터를 저장하므로 NULL이 표시됩니다.
7. 카디널리티 : 인덱스의 고유 값 수에 대한 추정치를 나타냅니다. 테이블의 행 수로 나눈 값은 가능한 한 1에 가까워 야합니다. 너무 작 으면이 인덱스를 삭제할지 여부를 고려하십시오.
8. Sub_part : 인덱스 idx_b와 같은 열의 일부만 인덱싱할지 여부를 100으로 표시합니다. 즉, b 열의 처음 100 바이트 만 인덱싱됩니다. 전체 열을 인덱싱 할 때 필드 값은 NULL입니다.
9. Packed : 키워드 압축 방법, NULL은 압축되지 않음을 의미합니다.
10. Null : 인덱스 열이 NULL 값을 허용하는지 여부, 예인 경우 Yes를 표시하고 그렇지 않으면 표시하지 않습니다.
11. Index_type : 인덱스 타입, InnoDB는 B + 트리 인덱스 만 지원하므로 위 그림은 BTREE입니다.
12. 코멘트 : 코멘트.

최적화 프로그램은 카디널리티 값에 따라이 인덱스를 사용할지 여부를 결정하지만이 값은 비용이 너무 많이 들기 때문에 실시간으로 업데이트되지 않습니다.이 값을 업데이트하려면 다음 명령을 사용하십시오.

ANALYZE TABLE t;

그러나이 명령에는 몇 가지 문제가 있으며 결과는 시스템마다 다를 수 있습니다.

일정 시간 실행 후 Cardinality는 NULL이 될 수 있습니다. 이때 색인이 성립 된 것처럼 보이지만 두 개의 동일한 문을 사용하거나 설명하지 않지만 최종 결과가 다릅니다. 하나는 색인을 사용하고 다른 하나는 색인을 사용합니다. 전체 테이블 스캔입니다. ANALYZE TABLE 작업을 수행하는 것이 가장 좋습니다.

값이 광범위하고 중복이 거의없는 (즉, 높은 선택도) 필드는 B + 트리 인덱스에 적합합니다. 그러나 액세스 필드가 매우 선택적이지만 가져온 행 데이터가 테이블의 데이터 대부분을 차지하는 경우 MySQL은 B + 트리 인덱스를 사용하지 않습니다.

. 다음은 표 부재 데이터 500W 대한 부분을 갖는 예이며, usernick 필드 고유 인덱스가 그 usernick is'David '실행 계획은 그대로 다음 사용자를 검색 할 때 :.
여기에 사진 설명 삽입
usernick 필드 때문에 매우 선택적이며 위의 쿼리는 Fewer lines 테이블에서 많은 것을 선택하므로 인덱스가 사용됩니다. 그러나 다음 문 :
여기에 사진 설명 삽입
사용 된 열은 여전히 ​​usernick이지만 최적화 프로그램에서 실제로 사용하는 인덱스 키는 NULL을 표시합니다. 이는 가져 오는 행이 테이블의 많은 부분을 차지하기 때문입니다.
여기에 사진 설명 삽입
다음 SQL 문 실행 계획에서 시간을 확인하십시오. 기반 검색 :
여기에 사진 설명 삽입
여기에 사진 설명 삽입
1 일 차이가 있지만 두 문장의 실행 계획이 다릅니다. 두 번째 문장이 실행될 때 idx_regdate를 사용할 수 있지만 Optimizer는 인덱스를 사용하지 않고 전체 테이블 스캔을 사용합니다. 옵티마이 저는 EXPLAIN 행을 전달합니다. 필드 추정 쿼리가 특정 값보다 크면 (작성자가 테이블에있는 데이터의 20 %로 추측) B + 트리가 전체 테이블 스캔을 선택합니다. 그러나 반환 된 행의 예상 개수가 정확하지 않아 옵티마이 저의 선택에 문제가 발생할 수 있습니다. 예를 들어 인덱스 사용을 강제합니다.

SELECT id, userid, sex, registdate
INTO OUTFILE 'a'
FROM member
FORCE INDEX(idx_regdate) 
WHERE registdate < '2006-04-24';

수행 :
여기에 사진 설명 삽입
인덱스가 필수가 아닌 경우 :
여기에 사진 설명 삽입
옵티마이 저의 선택이 완전히 올바르지 않음을 알 수 있습니다.

순차 읽기는 디스크의 블록을 순차적으로 읽는 것을 의미합니다. 무작위 읽기는 액세스 된 블록이 연속적이지 않고 디스크 헤드가 지속적으로 이동해야 함을 의미합니다. 기존 기계식 디스크의 병목 현상 중 하나는 낮은 임의 읽기 속도입니다.

다음은 RAID의 쓰기 (cpu가 메모리에 쓸 때 메모리와 디스크 내용이 동시에 수정 됨), 쓰기 (메모리 만 cpu 쓰기 작업 중에 수정되고 디스크 수정이 수행됨)입니다. 메모리 데이터가 새로 입력 된 데이터로 대체 될 때입니다. 쓰기를 위해 RAID 어레이는 일반적으로 자체 전원 공급 장치가 있으므로 정전 및 기타 이유로 인한 데이터 손실에 대해 걱정할 필요가 없습니다.) 읽기의 차이 두 가지 방법으로 sysbench에서 테스트 한 성능 :
여기에 사진 설명 삽입
순차 읽기 성능이 더 높은 것을 알 수 있습니다.

B + 트리 순차 읽기는 인덱스의 리프 노드 연결 목록에 따라 필요한 행 데이터를 순차적으로 읽는 것을 말합니다. 이것은 논리적 순차 읽기 일뿐입니다. 물리 디스크는 여전히 무작위로 읽을 수 있지만 물리 디스크의 데이터는 상대적으로 순차적입니다. ., 면적이 연속 64 페이지이기 때문입니다.

임의 읽기는 일반적으로 보조 인덱스 리프 노드에 액세스하여 기본 키를 가져온 다음 기본 키 인덱스를 통해 데이터를 찾는 것입니다. 디스크에 대한 액세스는 임의입니다.

한 번에 읽는 테이블의 내용이 너무 많으면 비 클러스터형 인덱스의 경우 임의 읽기가 크게 증가합니다. 클러스터형 인덱스의 경우 디스크의 데이터를 반드시 순차적으로 읽을 필요는 없으며 임의 읽기 성능이 다음보다 훨씬 낮습니다. 따라서 대량의 데이터를 선택할 때 인덱스 대신 전체 테이블 스캔을 사용하는 상황이 발생합니다.

읽기 성능을 향상시키기 위해 InnoDB 엔진은 프리 페치 기술을 사용하여 하나의 IO 요청을 통해 여러 페이지를 버퍼 풀로 프리 페치합니다 .InnoDB는 프리 페치 된 페이지가 즉시 액세스 될 것으로 예측합니다. 기존 IO 요청은 한 번에 한 페이지 만 읽습니다. 기존 기계식 하드 디스크의 낮은 IOPS에서 미리 읽기는 읽기 성능을 크게 향상시킬 수 있습니다.

InnoDB 엔진의 두 가지 사전 읽기 방법 :
1. 무작위 사전 읽기 : 영역의 13 페이지 (64 페이지)가 버퍼에 있고 LRU 목록의 프런트 엔드 (페이지가 자주 액세스 됨)에있을 때이 영역은 중간에있는 모든 페이지가 미리 메모리에 읽혀집니다.
2. 선형 미리 읽기 : 한 영역의 모든 24 페이지를 순차적으로 액세스하면 다음 영역의 모든 페이지를 미리 읽습니다.

그러나 MySQL의 사전 읽기로 인해 성능 저하가 발생했습니다 .InnoDB 엔진은 Plugin 1.0.4에서 무작위 액세스 사전 읽기를 공식적으로 취소했습니다. 선형 사전 읽기는 유지되었으며 innodb_read_ahead_threshold 매개 변수 (기본값 56)가 추가되었습니다. 영역의 페이지 수를 순차적으로 액세스 할 때 InnoDB 엔진은 프리 페치를 활성화하여 다음 영역의 모든 페이지를 읽을 수 있음을 의미합니다.

솔리드 스테이트 하드 디스크의 내부 구조는 기존의 기계식 하드 디스크와 달리 랜덤 읽기 성능이 질적으로 비약하고 있습니다. 현재 최적화 기의 20 % 원리는 부정확 할 수 있습니다. 솔리드 스테이트 드라이브의 인기로 인해 다양한 데이터베이스가이 영역의 최적화 속도를 높일 것입니다.

보조 인덱스의 리프 노드에는 기본 키가 포함되어 있지만 전체 행 정보는 포함되어 있지 않습니다. InnoDB 엔진은 다음 예제와 같이 보조 인덱스의 리프 노드에서 필요한 데이터를 얻을 수 있는지 항상 판단합니다.

CREATE TABLE t (
    a   INT          NOT NULL,
    b   VARCHAR(20),
    PRIMARY KEY(a), 
    key(b)
);

INSERT INTO t
SELECT 1, 'kangaroo';

INSERT INTO t
SELECT 2, 'dolphin';

INSERT INTO t
SELECT 3, 'dragon';

INSERT INTO t
SELECT 4, 'antelope';

이 때 실행하면 SELECT * FROM t;많은 사람들은 출력이 다음과 같다고 생각합니다.
여기에 사진 설명 삽입
그러나 실제 결과는 다음과 같습니다.
여기에 사진 설명 삽입
위의 예에서 보조 인덱스에는 기본 키 a의 값이 포함되고 b 열의 보조 인덱스가 사용되므로 기본 키 데이터없이 모든 열을 가져올 수 있으며 일반적으로 기본 키 페이지보다 보조 인덱스 페이지에 더 많은 데이터가 저장되므로 보조 인덱스가 사용됩니다. 이 SQL 문을 설명하십시오.

여기에 사진 설명 삽입
열 a 정렬의 결과를 얻으려면 옵티마이 저가 열 a : 정렬을 피하기 위해 기본 키로 직접 이동하거나 기본 키를
여기에 사진 설명 삽입
강제로 사용할 수 있습니다.

SELECT *
FROM t
FORCE KEY(PRIMARY);

실행 :
여기에 사진 설명 삽입
조인트 인덱스는 본질적으로 B + 트리이지만 둘 이상의 키 값을 가지고 있습니다. 두 개의 정수 열 (a, b)로 구성된 조인트 인덱스가있는 경우 데이터는 (a, b) 순서로 B + 트리에 저장됩니다. 이때 위의 인덱스
여기에 사진 설명 삽입
WHERE a = xxx AND b = xxx다음 같은 쿼리에 사용할 수 있습니다. 조건 . WHERE a = xxx위의 색인은 조건이있는 쿼리에도 사용할 수 있습니다. 그러나 조건이 WHERE b = xxx있는 쿼리는 리프 노드의 b 값이 정렬되지 않기 때문에 위의 인덱스를 사용할 수 없습니다.

공동 인덱스를 사용하면 두 번째 키 값을 정렬 할 수 있습니다. 예를 들어 사용자의 쇼핑 상황을 쿼리하여 시간순으로 정렬합니다. 이때 하나 이상의 정렬 작업을 피하기 위해 공동 검색을 사용하는 이유는 인덱스가 자체는 이미 리프 노드에 있습니다. Sorted :

CREATE TABLE buy_log (
    userid       INT UNSIGNED    NOT NULL,
    buy_date     DATE
);

INSERT INTO buy_log
VALUES(1, '2009-01-01');

INSERT INTO buy_log
VALUES(2, '2009-01-01');

INSERT INTO buy_log
VALUES(3, '2009-01-01');

INSERT INTO buy_log
VALUES(1, '2009-02-01');

INSERT INTO buy_log
VALUES(3, '2009-02-01');

INSERT INTO buy_log
VALUES(1, '2009-03-01');

INSERT INTO buy_log
VALUES(1, '2009-04-01');

ALTER TABLE buy_log
ADD KEY(userid);

ALTER TABLE buy_log
ADD KEY(userid, buy_date);

위와 같이 userid 만 쿼리하는 것과 같이 userid 필드를 포함하는 두 개의 인덱스가 생성됩니다.
여기에 사진 설명 삽입
possible_keys에 사용할 수있는 두 개의 인덱스가 있음을 알 수 있지만, 리프 노드에는 단일 키 값이 포함되어 있으므로 최적화 프로그램이 userid를 선택합니다. 페이지에 포함 된 더 많은 기록. 사용자 ID 1을 사용하여 마지막 세 개의 구매 레코드를 검색하려는 경우
여기에 사진 설명 삽입
위의 명령문은 두 개의 인덱스에도 사용할 수 있습니다. 최적화 프로그램은이 공동 인덱스의 buy_date가 이미 정렬 되었기 때문에 공동 인덱스를 선택합니다. 사용 :
여기에 사진 설명 삽입
파일 정렬 (정렬, 파일에서 수행되지 않음)을 볼 수 있습니다. 위 그림의 명령문을 실행하는 경우 먼저 현재 정렬 작업 수를 확인한 다음
여기에 사진 설명 삽입
명령문을 실행 한
여기에 사진 설명 삽입
다음 정렬 작업 수를 확인하고 정렬 작업 수가 증가
여기에 사진 설명 삽입
했는지 확인합니다. 조인트 인덱스를 사용하는 경우 , 정렬 작업 수가 증가하지 않았 음을 알 수 있습니다.

InnoDB 엔진의 적응 형 해시 인덱스는 해시 테이블 (해시 테이블) 데이터 구조를 사용합니다. 키는 해시 함수를 통해 해시 테이블에 매핑되며, 일반적으로 충돌이 발생하면 연결 방식을 사용하며 반복되는 키 값의 데이터는 연결 목록에 배치됩니다.

해시 함수는 충돌을 피하는 데 가장 적합합니다. 데이터베이스는 일반적으로 키워드를 자연수로 변환 한 다음 나누기 해싱 방법을 사용합니다. h(k) = k mod m즉, k의 나머지를 m으로 나누면 키워드 k가 일부에 매핑됩니다. m 슬롯 1 인치

InnoDB 엔진 해시 인덱스 충돌 처리는 링크드리스트 방식을 채택하고 해시 함수는 분할 해시 방식을 채택합니다. 페이지를 자연수로 변환 할 때는 먼저 테이블 스페이스 번호를 왼쪽으로 20 비트 이동하고 테이블 스페이스에 페이지 오프셋을 추가합니다.이 값은 분할하여 해시 테이블의 슬롯에 해시 할 수 있습니다.

적응 형 해시 인덱스는 데이터베이스 자체에서 생성 및 사용되며 DBA는 개입 할 수 없습니다. 구성 파일에서 innodb_adaptive_hash_index 매개 변수를 활성화하면 데이터베이스 시작시 innodb_buffer_pool_size / 256 슬롯의 해시 테이블이 자동으로 생성됩니다. 매개 변수 값이 10M이면 InnoDB는 10M / 256 = 40960 슬롯의 해시 테이블을 생성합니다. 시작할 때 적응 형 해시 테이블.

적응 형 해시 인덱스는 사전 유형 조회에는 매우 빠르지 만 범위 조회에는 무력합니다.

현재 적응 형 해시 인덱스 사용량을 확인합니다.

SHOW ENGINE innodb STATUS;

실행 :
여기에 사진 설명 삽입
적응 형 해시 인덱스의 크기 및 사용량, 초당 적응 형 해시 인덱스 검색 사용 및 초당 적응 형 해시 인덱스 검색을 사용하지 않는 상황을 볼 수 있습니다.

적응 형 해시 인덱스는 기본적으로 활성화되어 있습니다.

추천

출처blog.csdn.net/tus00000/article/details/113487456