가장 왼쪽 접두사 원리와 MySQL [인덱스] 인덱스 푸시 다운 최적화

디렉토리

첫째,의 도입

둘째, 보험 지수

처음처럼 보인다는 기본 스토리지 아키텍처의 다음 공동 인덱스에 대해 이야기하기 전에 문제에 대해 말하자면? 공동 색인 검색 과정은 무엇입니까?

셋째, 가장 왼쪽 접두사 원칙

가장 왼쪽 접두사 정의 원칙

넷째, 인덱스 푸시 다운

V. 요약


첫째,의 도입

이 글을 시작하기 전에, 먼저 명확한 개념 모두의 클러스터 된 인덱스의 각 노드는 B + 트리입니다 인덱스 페이지 , 인덱스 페이지가 이전의 좋은의 규정을 기준으로합니다 풋의 얼마나 많은 인덱스 페이지 인덱스 값을 결정하는가.

 

단지 비 - 리프 노드 인덱스 영역 (색인 항목 ), 즉, 단지 인덱스 데이터를 저장한다.

리프 노드 인덱스 영역 갖는 데이터 영역 (데이터 항목) , 인덱스가 인덱스 데이터 저장 영역, 기본 키 인덱스 및 2 인덱스 트리 트리 상이한의 데이터 영역이다 :

  • InnoDB의 기본 키 테이블 인덱스 트리 잎 노드는 전체 테이블의 데이터의 데이터 영역에 저장됩니다.
  • 이노 테이블 보조 인덱스 트리의 리프 노드는 노드에 해당하는 기본 키 인덱스에 저장됩니다.

 

노드 B +의 수가 수 있는지 쉽게 중복 저장 인덱스 값이지만 때문에 적은 양의 데이터의 중복이 영향을받지되도록 인덱스가 차지하는.

 

여기에서 우리는이 질문 보면 :

다음 테이블 T, 나는 T에서 선택 *을 실행할 경우 경우 3, 5, 당신은 검색 작업을 여러 번 나무를 수행 할 필요가 사이의 K, 얼마나 많은 스캔 라인이 있습니까?

 

다음은 초기화 문의 테이블입니다.

mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0, 
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;

insert into T values(100,1,'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

 

InnoDB의 인덱스 조직 구조

现在,我们一起来看看这条 SQL 查询语句的执行流程:

  1. ID = 300를 취득 K = 3 인덱스 트리 K의 레코드를 검색하는 단계;
  2. 그런 인덱스 트리의 ID가 ID에 대응 = 300 R3 발견;
  3. ID = 500를 수득한다 K 값 K = 5 인덱스 트리 제거;
  4. 돌아 가기 ID에 해당하는 인덱스 트리 ID로 = R4는 500을 발견;
  5. k 번째 값이 K = 6 인덱스 트리 제거 조건은 루프 단부를 만족하지 않는다.

 

因为B+树的叶子节点之间都按循序用指针连接在一起,所以k的索引树找到3的叶子节点之后直接根据叶子节点的后继指针到5结点就行了,依次同理,什么时候结点的索引值k不符合查询条件中的范围要求了就结束查询。

 

在这个过程中,回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程读了 k 索引树的 3 条记录(步骤 1、3 和 5),回表了两次(步骤 2 和 4)。

 

在这个例子中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表。那么,有没有可能经过索引优化,避免回表过程呢?这里就引入了覆盖索引的概念。

 

둘째, 보험 지수

명령문 T에서 선택 ID를 실행하는 경우 (3) 사이 K 여기서 5는 다음 만 ID의 값을 확인해야하고, 트리 인덱스 k의 ID 값이 노드의 데이터 영역이 (보조 인덱스 트리 저장된 대응 기본 키 값), 당신은 필요가 없습니다, 직접 쿼리 결과를 제공 할 수있는 테이블로 다시 . 즉,이 쿼리 내부, 인덱스 k는 우리의 탐구의 요구에, 우리는 소위 "포함"된 커버링 인덱스를 .

 

커버링 인덱스 트리의 검색의 수를 줄일 수 있기 때문에, 상당히 그래서 커버 인덱스가 공통의 성능 최적화 도구입니다 사용, 쿼리 성능을 향상시킬 수 있습니다.

 

인덱스 K의 인덱스를 사용하여 엔진 커버의 내부에 실제로 세 개의 레코드를 읽을 것을 참고, R3 ~ R5 (해당 인덱스 k에 항목)하지만, MySQL 서버 계층을 위해, 엔진을 찾고 있습니다 두 기록에, 그래서 스캔 라인의 수는 MySQL의 2로 간주됩니다.

 

위의 설명에 따라 인덱스를 취재, 우리는 문제를 논의 : 공용 정보 시트에,이 ID 번호와 이름 여부를 확립 할 필요가 공동 인덱스 (인덱스가 공동 커버링 인덱스 생성을 생성하는 방법입니다) ?

 

다음과 같이 대중 테이블의 정의가 있다고 가정 :

CREATE TABLE `tuser` (
  `id` int(11) NOT NULL,
  `id_card` varchar(32) DEFAULT NULL,
  `name` varchar(32) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `ismale` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`id`), -- 这个表的主键是单独建了一个id,不是用的身份证号,因为身份证号太长了,用它作为主键太占空间
  KEY `id_card` (`id_card`),
  KEY `name_age` (`name`,`age`)
) ENGINE=InnoDB

 

우리는 ID 번호가 공공의 고유 식별자 인 것을 알고있다. 대중의 정보 요구에 따라 쿼리 ID 번호가있는 경우 즉, 한 우리는 ID 번호 필드에 인덱스를 구축으로 (충분하다 그래서 그냥 먼저 해당 ID 번호가 기본 키 인덱스 트리의 ID 번호에 해당 찾을 수있다 ID , 다음 기본 키 인덱스에서 나무 아래 기본 키 찾기 위해 ID 에만 해당 주민 정보를 찾을 수있는 B + 쿼리 수의 두 배를 할을 ). a의 재 설립 공동 인덱스 (ID 번호, 이름) ( 만 인덱스에서 해당 인덱스 항목을 찾을하는 데 필요한 데이터를 찾을 수있는 쿼리를 작성해야하는이 지수는,이 테이블 기본 키 인덱스 쿼리에 돌아 오지 않는다 나무는 ), (공간의 낭비하지 않습니다) 각 빌드 인덱스, 당신은 B + 트리를 작성해야하고 해당 데이터를 내부에 저장하기 때문에?

 

 지금 고주파 요청이있는 경우, 공공 ID 번호, 차종 감각에 공동 인덱스에서 자신의 이름을 조회 할 수 있습니다. 이것은 고주파 요청에 사용될 수있다 (상기 인덱스 필드 인덱스 엔트리 인덱스에 의해 커버되는, 쿼리 할 필드를 커버) 커버 인덱스 는 보조 인덱스 트리 직접 ID 번호에 따라 자신의 이름을 확인할 수 있기 때문에, 리프 노드의 데이터 영역은 여전히 기본 키 저장 대응의 보조제하지만 스토리지 노드의 인덱스 영역에 좋은 (ID 번호 + 이름) 조인트 인덱스를 생성하는 것이지만, 상기 인덱스 영역이 아닌로부터 직접 필요한 데이터를 얻을 수있다 우리는 전체 라인 녹음을 확인 명령문의 실행 시간을 줄이기 위해 테이블로 복귀해야합니다.

 

물론, 인덱스 필드를 유지하는 것은 가격 (자세한 참조 항상 인덱스 유지 보수 ). 지원하기 위해 중복 인덱스를 만들 때 따라서, 커버링 인덱스는 트레이드 오프를 고려해야합니다. 이 사업 DBA (데이터베이스 관리자), 또는 비즈니스 데이터 건축가의 작품으로.

 

 

 처음처럼 보인다는 기본 스토리지 아키텍처의 다음 공동 인덱스에 대해 이야기하기 전에 문제에 대해 말하자면? 공동 색인 검색 과정은 무엇입니까?

도 위와 같이 복수의 필드는 모든 노드의 인덱스 영역에 인덱스의 순서대로 정의 될의 B + 트리를 구성하도록 조합 인덱스 필드의 복수. 왼쪽에서 오른쪽으로 여러 필드 (지도보기에 위에서 아래로 비교입니다)의 비교가있을 때 비교 인덱스 트리 인덱스를 실시하고 검색 할 수 있습니다.

 

세 가지 방법의 예를 들어 쿼리 프로세스로 위의 그림 :

  1. 제 1 필드 데이터 및 상기 검색 인덱스 필드는 동일하지
  2. 데이터 검색 인덱스 필드와 동일한 필드의 처음
  3. 데이터 검색 인덱스 필드의 처음 두 필드로서

 

  • 상황 : 데이터가 검색되어야하는 조건 (10003, XXX, XXX)는 검색이 10002보다 큰 검색 루트에서 시작하고 10004과 데이터 페이지에 오른쪽에 바로 누른 후 권리 그것보다 상대적으로 작은 발견 인덱스 뒤에 두 개의 필드를 비교할 필요가 없습니다
  • 사례 2 : 검색 할 데이터의 조건 (10001, Assiatant), 프로세스의 경우와 마찬가지로,의 데이터 페이지의 왼쪽에 최초의 완전한 인덱스에 비해 현장에 직접 가서 첫 번째 필드 및 쿼리 데이터를 찾을입니다 데이터의 왼쪽 페이지의 첫 번째 필드 세 개의 노드가 그 다음 두 번째 필드를 비교하는 것 같으며, 발견 가장 왼쪽의 노드가 직접이 노드이기 때문에, 인덱스 영역은 세 개의 필드를 가지고 있지만, 하지만이 검색 필드, 다음 세 번째 필드를 제어하고이 직접 필드하지 않습니다. 이것은 이 경우 뒤에 원칙에 대한 가장 왼쪽 접두사 실행 이야기가 가장 왼쪽 접두사 원칙입니다 .
  • 세 가지 경우 : 조건 데이터는 (10003는 직원, XXX),이 경우는 데이터의 페이지에 오른쪽 두 번째 경우에있어서, 두 번째 필드를 비교 완료 이룰하는 제 1 비교 경우에 따라 완성되고 검색 될 동일하지만, 또한 데이터를 검색 필드는 제 3 영역 인덱스 필드를 비교하는 것
  • 추가 상황 : 데이터가 조건 (10003)이 있다면, 그는 오른쪽 페이지에 대한 데이터를 검색하는 절차의 경우를 따를 것이며, 모든 노드의 첫 번째 인덱스 페이지의 오른쪽 데이터 필드를 찾아 검색 할 수 있기 때문에, 10003입니다 하나 개의 검색 필드 (10003), 두 노드 모두에게 올바른 데이터 페이지를 얻을 후 직접에. 이것은 또한 응용 프로그램의 가장 왼쪽 접두사 원칙이다

 

셋째, 가장 왼쪽 접두사 원칙

여기에서 당신은 의심의 여지가 각 쿼리에 대한 인덱스를 디자인 할 경우, 인덱스가 너무 많이하지 않습니다,이 표시됩니다. 나는 그의 집 주소를 확인하기 위해 대중의 식별 번호를 따르십시오? 비즈니스 수요에서이 쿼리의 확률이 높은 것은 아니지만, 그러나 우리는 그것을 바로 전체 테이블 스캔을 가만 두지 않을 수 있습니까? 반대로, 인덱스가 자주 요청 낭비 조금 느낌이 아닌 별도의 (ID 번호, 주소)를 생성 . 내가 어떻게해야합니까?

 

여기, 내가 당신의 결론을 가정 해 봅시다. 이 B + 트리 인덱스 구조 지수는 기록을 찾기 위해, 「가장 좌측 접두사 "로 사용할 수 있습니다.

 

시각적으로이 개념을 설명하기 위해 분석 (이름, 나이)이 공동으로 인덱스를 사용합니다.

(이름, 나이) 인덱스 회로도

그것은 인덱스 항목은 내부에 정의 된 인덱스 필드에 따라 외관의 순서로 정렬됩니다, 볼 수 있습니다.

 

귀하의 요구는 모든 논리 이름을 발견하는 경우 ID4 신속하게 이동 한 다음 반복 처리 거꾸로 당신이 원하는 모든 결과를 얻을 수 있습니다 "조 스미스"입니다.

 

첫 번째 단어의 모든 이름을 확인하려면 "장"사람들, SQL 문의 조건이다 "여기서 '장 %'와 같은 이름입니다." 이 시점에서, 당신은 인덱스를 보내는 첫 번째 일치하는 레코드를 찾을 수 있습니다 다음 조건이 될 때까지 반복 처리 뒤쪽으로는 만족하지 ID3이다.

 

 다음은 검색 속도를 가장 왼쪽 접두사 원칙의 원칙이다. 수가 적은 같은 인덱스 트리의 인덱스 항목이 하나의 좌석 인 경우는 직접 만든 그래서 그냥, "홍길동"에 대한 검색과 같은 항목을 검색 할 인덱스 항목의 수보다 경우 검색의 가장 왼쪽 접두사 원칙은 모두이 같다 조 스미스는 노드. 당신이 노드의 좌석 후 더있는 경우, 노드가 여러 반환을 (이 과정은 인덱스 나무가 다음 다른 노드 조 스미스는 또한 순서대로 저장, 정렬하기 때문에 첫 번째 노드 조 스미스를 찾는 것입니다 직접 라인에 의해 다시 테이블 하나에 다음 조건 지금까지)을 충족하지 않는 액세스 노드 통과 될 때까지 오른쪽으로 다음 노드.

 

가장 왼쪽 접두사 정의의 원칙 :

그것은 한 가장 왼쪽 접두사로, 당신은 검색 속도를 높이기 위해 인덱스를 사용하여 인덱스의뿐만 아니라 모든 정의를 볼 수 있습니다. 가장 왼쪽 접두사가 될 수있는 공동 인덱스 N 필드 왼쪽, 그것도 할 수 있습니다 문자열 색인 M 문자 왼쪽. N (이 N 필드,하지만 너무 많은 일이 아니다 당신이 N 필드의 공동 인덱스를 포함하여 왼쪽에서 조회 할 필드 그건 그들이 같은이 순서 ), 당신이 필요로하지 않는 범죄자 N을 체코 필드는 별도의 인덱스, 동일한 효과를 재생할 수 있습니다 기존의 공동 인덱스의 직접 사용을 만들 수 있습니다.

 

하나는 우리의 통과하기 위해 가장 왼쪽 접두사의 원칙과 일치하지 않습니다 경기의 가장 왼쪽 문자, '% 23', 등이 사용, 그것은 인덱스를 사용할 수 없습니다,이 지수는 때문에, 아무것도하지됩니다 인덱스 비교는에서 시작 왼쪽에서 오른쪽으로하는 경우 1 %는 인덱스를 사용할 수 있도록, 그것을 아래로 비교 할 수있는 방법이 시작.

 

그러나 어떤 경우에는 위의 경우처럼 매우 편리합니다

예를 들어 테이블의 URL의 URL에 저장

www.baidu.com

www.360.com

www.null.xyz

지금 XYZ 도메인 이름 접미사를 찾고 있어요, 당신은 '% 닷컴'쿼리처럼해야하지만 불가능 매우 느리게으로 이어질 수있는 인덱스 쿼리를 사용 할 수 있습니다

 

이러한 솔루션 도메인 데이터 삽입 거꾸로

moc.udiab.www

이 쿼리는 'COM %'인 경우, 데이터베이스를 사용하는 경우 약간의 트릭 인덱스를 사용할 수 있습니다.

 

인덱스의 가장 왼쪽 접두사의 얼굴에 지침을 바탕으로, 우리는 문제를 논의 : 공동 인덱스의 설립, 어떻게 인덱스에있는 필드의 순서를 정렬 할 때 .

 

우리의 평가 기준, 여기에 인덱스 다중화 기능을 . 그것이 가장 왼쪽 접두사, 그래서있어 when've (A, B) 공동 인덱스를 지원할 수 있기 때문에, 일반적으로에 별도의 인덱스가 필요하지 않습니다. 따라서 첫 번째 원칙은 순서를 조정하여, 당신이 낮은 인덱스를 유지할 수 있다면, 우선 순위의 순서가 자주 사용된다는 점이다 .

 

 그래서 지금 당신이 알고,이 섹션의 시작 부분에 문제는, 우리는 수요의 요구 "ID 번호 조회 주소에 따라", 고주파 요청 (ID 번호, 이름) 공동 인덱스를 만들 고주파하지, 우리는하지 않았다 조인트의 인덱스 (ID 번호, 주소)를 유지하기 위해 필요한. 당신이 주소를 기반으로 사용자의 검색 쿼리 속도 ID 번호를 향상시키고 자하는 경우, 당신은 내용을 조회하기 위해 전체 B + 트리를 탐색 할 필요 (ID 번호) 인덱스, 또는 다른 MySQL이 있습니다. 그리고 우리는 인덱스, 당신이 (ID 번호, 이름) 고주파 전원 학교 (ID 번호) 역할을하는 요청과 공동 인덱스 색인 바로 그 원칙에 따라 할 수있는 가장 왼쪽 접두사 원칙을 편리하게 할 수 있습니다 공동 인덱스에 의해 수요 ( "ID 번호 조회 주소에 따라"지원은 신속하게에만 신속하게 기본 키 인덱스 트리에서 기본 키의 ID에 해당하는 리프 노드를 찾으려면 기본 키의 ID에 해당하는 ID 번호를 찾으 발견, 그는 모두의 ID를 찾을 수 있습니다 ) 어드레스 데이터를 포함.

 

질문의 각 분야가 할 b를 따라서, 두 경우 관절의 질문,하지만 또한, 기반으로? 문에만 b를 사용할 수 없습니다 쿼리 (A, B) 가장 왼쪽 접두사의 원칙에 부합하지 않은 공동 인덱스. 이 시간은 당신이 (A, B)를 유지할 필요가 의미 다른 인덱스, (b)는 두 개의 인덱스를 유지해야합니다.

 

이 때, 우리가 원하는 원칙을 고려하여이 공간 의. 예를 들어, 위의 상황 대중 테이블, 이름 필드는 필드의 나이보다 더 큰, 나는 당신이 공동 인덱스와 단일 필드 인덱스 (나이)의 (이름, 나이)을 작성하는 것이 좋습니다. 효과는 동일하지만, 후자의 이름은 두 개의 큰 필드, 더 많은 공간에 저장되어 있지만, (나이, 이름) 공동 인덱스와 (이름) 인덱스를 설정하지 마십시오.

 

 

넷째, 인덱스 푸시 다운

우리가 가장 왼쪽 접두사 원칙을 충족 기간의 말하기, 가장 왼쪽 접두사는 인덱스 레코드의 위치를 ​​찾을 수 있습니다. 이 시점에서, 당신은 그 부분이 가장 왼쪽 접두사에 부합하지 않는, 질문 할 수 있습니다, 어떤 일이 일어날 것인가?

 

우리는 예를 들어, 여전히 공공 공동 인덱스 테이블 (이름, 나이)의 회원이었다. 지금은 수요가있는 경우 :. 테이블을 검색하는 "첫 번째 단어는 장의 이름, 나이 만 10 세 모든 남자입니다." 그래서, SQL 문은 이렇게 기록하고 있습니다 :

mysql> select * from tuser where name like '张%' and age=10 and ismale=1;

 

당신은 이미 규칙의 접두사 인덱스를 알고 전용 "장"기록은 ID3 먼저 조건을 충족 발견 검색 인덱스 트리에서이 문장 때문에. 물론, 이것은 전체 테이블 스캔이 더 나은 것보다 더도 좋다.

 

然后呢?当然是判断其他条件是否满足。

 

在 MySQL 5.6 之前,只能从 ID3 开始一个个回表。到主键索引上找出数据行,再对比字段值。而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

 

图1和图2,是这两个过程的执行流程图。

1 없음 실행 흐름 인덱스지도 푸시 다운

 

도 2 인덱스 구현 프로세스를 밀어

도 1과 각 점선 화살표 내부도 2 두 번 다시 테이블을 나타낸다.

图 1 中,在 (name,age) 索引里面我特意去掉了 age 的值,这个过程 InnoDB 并不会去看 age 的值,只是按顺序把“name 第一个字是’张’”的记录一条条取出来回表。因此,需要回表 4 次。

图 2 跟图 1 的区别是,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 10,对于不等于 10 的记录,直接判断并跳过。在我们的这个例子中,只需要对 ID4、ID5 这两条记录回表取数据判断,就只需要回表 2 次。

 

V. 요약

이 문서의 오늘, 당신과 내가 취재 인덱스 접두사 인덱스를 포함하여, 데이터베이스 인덱스의 개념을 논의하기 위해 계속 지수는 아래로 밀었다. 당신이 볼 수 있듯이, 자원에 거의 접근으로, 문장의 요구를 충족하면서 것은 데이터베이스 설계의 중요한 원칙 중 하나입니다. 우리는 특히 디자인 테이블 구조, 데이터베이스를 사용하는 경우뿐만 아니라 대상으로 자원의 소비를 줄이기 위해


다른 관련 문서 : [MySQL의] MySQL의 스토리지 엔진 인덱스 코멘트 (클러스터 인덱스 및 비 - 클러스터 된 인덱스)
                        [MySQL의] 이노 행 형식, 데이터 페이지의 구조와 원리 분석을 기초 인덱스
                        [MySQL의] 이노 스토리지 엔진의 MyISAM 스토리지 엔진, 클러스터 된 인덱스 클러스터되지 않은 인덱스의 주요 키 인덱스 사이 개섬 관계, 보조 인덱스
                        [MySQL의] 이노 지수 모델 (B + 트리)
                        [의 MySQL] MySQL의 록 트랜잭션 격리 수준 설명
                        [MySQL의] MySQL의 서브 라이브러리 서브 테이블의 설명
                        [MySQL의 ] 자세한 마스터 - 슬레이브 복제 구현 원리


참조 : "MySQL의 전투 (45) 스트레스"린 Xiaobin

게시 54 개 원래 기사 · 원 찬양 47 ·은 10000 +를 볼

추천

출처blog.csdn.net/cy973071263/article/details/104550117