I. 배경
오늘, 교환 그룹의 한 학생이 질문을 제기했다. 보기는 :
: 후, 학생들은 정말 퍼지 예 인덱스 복용 전체 조회 만든
우리는이 두 SQL의 가장 큰 차이가 있음을 볼 수있다 이에을 : 전체 필드 쿼리 (선택 *)를,하지만 단지 기본 키 (선택 ID)를 쿼리합니다.
:이 시점에서, 다른 프로그램에 대해 이야기 다른 학생들이 있습니다
이 색인 전체 텍스트가 간다 말도없이, 전체 메시지 퍼지 인덱스를 이동합니다. 그러나이 프로그램을 포함하는 인덱스, 나는 그 배경과 일치라고 생각합니다 :
배경이 퍼지 쿼리 필드의 문제이기 때문에 1, 일반 인덱스는 일반 인덱스는 기본 키가 커버링 인덱스를 보낼 수 쿼리 동안이다.
이다 2, 배경, 만 기본 키 쿼리 (ID)는 인덱스 지출 표시됩니다.
둘째, 데이터 준비 및 장면을 재현
1 제조 테이블 데이터 :
일반 전화 인덱스에 필드를 추가, 사용자 테이블을 만듭니다
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`phone` varchar(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_phone` (`phone`) USING BTREE COMMENT 'phone索引'
) ENGINE=InnoDB AUTO_INCREMENT=200007 DEFAULT CHARSET=utf8;
100 000 제조 의미 데이터의 의미
delimiter ;
CREATE DEFINER=`root`@`localhost` PROCEDURE `iniData`()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into user(name,age,phone) values('测试', i, 15627230000+i);
set i=i+1;
end while;
end;;
delimiter ;
call iniData();
2, SQL의 구현, 실행 계획을 볼 수 :
explain select * from user where phone like '%156%';
explain select id from user where phone like '%156%';
3. 결과 :
신분증 | SELECT_TYPE | 표 | 파티션 | 유형 | 이 possible_keys | 키 | 있는 key_len | 심판 | 행 | 거르는 | 특별한 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 단순한 | 사용자 | 모두 | 99927 | 11.11 | 여기서 사용 |
신분증 | SELECT_TYPE | 표 | 파티션 | 유형 | 이 possible_keys | 키 | 있는 key_len | 심판 | 행 | 거르는 | 특별한 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 단순한 | 사용자 | 인덱스 | index_phone | (36) | 99927 | 11.11 | 여기서 사용; 인덱스를 사용하여 |
우리는 두 번째 SQL이 실제로 사용하고 보여줄 것을 볼 수 있습니다 index_phone
인덱스를.
그러나 찾을 수있는주의 학생 : possible_keys
실제로 비어 있습니다! 질병의 전송. . .
나는 관계 prossible_keys과 키에 대해 이야기하기 위해 여기입니다 :
1
possible_keys
인덱스가 사용될 수 있으며,key
실제 사용의 인덱스이고;2, 보통이다
key
지수는 필연적에 포함possible_keys
.
약간의 트릭이있다 : 인덱스 및 (행)가 동일한 것으로 밝혀졌다 인덱스 읽기를 사용하지 않고 라인의 번호를 사용!
셋째, 검증 단계 및 추측
상술 한, possible_keys
및 key
관계는, 우리는 그것을 확인하는 통상 촬영을 인덱스를 사용한다.
다음 SQL, 모든 퍼지 쿼리하지만 인덱스를 복용의 특정 보장 권리 퍼지 쿼리, 우리는이 시간에 별도로보고 possible_keys
및 key
값 :
explain select id from user where phone like '156%';
결과 :
신분증 | SELECT_TYPE | 표 | 파티션 | 유형 | 이 possible_keys | 키 | 있는 key_len | 심판 | 행 | 거르는 | 특별한 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 단순한 | 사용자 | 범위 | index_phone | index_phone | (36) | 49963 | (100) | 여기서 사용; 인덱스를 사용하여 |
여기에 너무 명백 :
1, possible_keys
그것은 포함 않는 경우 key
인덱스에.
2, 그리고 rows
전체가 두 배 아래로 즉시 49,963로 떨어졌다 filtered
(100)에 도달했다.
무대 추측 :
1, 우선, select id from user where phone like '%156%';
때문에 커버 지수는 오히려 인덱스를 지출 index_phone
.
2,이 possible_keys가 null, 나무를 찾기 위해 인덱스에 액세스 할 수 입증하지 않습니다. 물론, select id from user where phone like '%156%';
디스플레이가 사라 지수에도 불구하고 있지만, 행의 수 읽기 행 과 select * from user where phone like '%156%';
의 인덱스하지 않은 행이 동일합니다.
3, 우리는, 추측 할 수 select id from user where phone like '%156%';
커버 인덱스를 사용하고, 심지어으로 index_phone
인덱스를하지만, 지출에 나무, 인덱스 트리를 탐색의 단지 정상적인 순서를 찾지 못했습니다. 그래서, 사실, SQL 필드에 두 개의 작은 테이블, 쿼리 성능은 용기를 소환해야합니다.
추적 분석에 의해 확인 넷째,
우리는 선택하는 방법입니다 최적화 모두 SQL에 대한 추적 분석을 사용 하였다.
1, 탐구의 전체 필드 :
-- 开启优化器跟踪
set session optimizer_trace='enabled=on';
select * from user where phone like '%156%';
-- 查看优化器追踪
select * from information_schema.optimizer_trace;
여기에서 우리는 라인에 TRACE를 보면 :
{
"steps": [
{
"join_preparation": {
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `user`.`id` AS `id`,`user`.`name` AS `name`,`user`.`age` AS `age`,`user`.`phone` AS `phone` from `user` where (`user`.`phone` like '%156%')"
}
]
}
},
{
"join_optimization": {
"select#": 1,
"steps": [
{
"condition_processing": {
"condition": "WHERE",
"original_condition": "(`user`.`phone` like '%156%')",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "(`user`.`phone` like '%156%')"
},
{
"transformation": "constant_propagation",
"resulting_condition": "(`user`.`phone` like '%156%')"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "(`user`.`phone` like '%156%')"
}
]
}
},
{
"substitute_generated_columns": {
}
},
{
"table_dependencies": [
{
"table": "`user`",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": [
]
}
]
},
{
"ref_optimizer_key_uses": [
]
},
{
"rows_estimation": [
{
"table": "`user`",
"table_scan": {
"rows": 99927,
"cost": 289
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`user`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 99927,
"access_type": "scan", // 顺序扫描
"resulting_rows": 99927,
"cost": 20274,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 99927,
"cost_for_plan": 20274,
"chosen": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": "(`user`.`phone` like '%156%')",
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`user`",
"attached": "(`user`.`phone` like '%156%')"
}
]
}
},
{
"refine_plan": [
{
"table": "`user`"
}
]
}
]
}
},
{
"join_execution": {
"select#": 1,
"steps": [
]
}
}
]
}
2 만 기본 키 쿼리
set session optimizer_trace='enabled=on';
select id from user where phone like '%156%';
-- 查看优化器追踪
select * from information_schema.optimizer_trace;
여기에서 우리는 줄에 TRACE를보고 계속 :
{
"steps": [
{
"join_preparation": {
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `user`.`id` AS `id` from `user` where (`user`.`phone` like '%156%')"
}
]
}
},
{
"join_optimization": {
"select#": 1,
"steps": [
{
"condition_processing": {
"condition": "WHERE",
"original_condition": "(`user`.`phone` like '%156%')",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "(`user`.`phone` like '%156%')"
},
{
"transformation": "constant_propagation",
"resulting_condition": "(`user`.`phone` like '%156%')"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "(`user`.`phone` like '%156%')"
}
]
}
},
{
"substitute_generated_columns": {
}
},
{
"table_dependencies": [
{
"table": "`user`",
"row_may_be_null": false,
"map_bit": 0,
"depends_on_map_bits": [
]
}
]
},
{
"ref_optimizer_key_uses": [
]
},
{
"rows_estimation": [
{
"table": "`user`",
"table_scan": {
"rows": 99927,
"cost": 289
}
}
]
},
{
"considered_execution_plans": [
{
"plan_prefix": [
],
"table": "`user`",
"best_access_path": {
"considered_access_paths": [
{
"rows_to_scan": 99927,
"access_type": "scan", // 顺序扫描
"resulting_rows": 99927,
"cost": 20274,
"chosen": true
}
]
},
"condition_filtering_pct": 100,
"rows_for_plan": 99927,
"cost_for_plan": 20274,
"chosen": true
}
]
},
{
"attaching_conditions_to_tables": {
"original_condition": "(`user`.`phone` like '%156%')",
"attached_conditions_computation": [
],
"attached_conditions_summary": [
{
"table": "`user`",
"attached": "(`user`.`phone` like '%156%')"
}
]
}
},
{
"refine_plan": [
{
"table": "`user`"
}
]
}
]
}
},
{
"join_execution": {
"select#": 1,
"steps": [
]
}
}
]
}
음, 여기 우리는 모두 SQL에 대한 어떤 최적화 인덱스의 실제 선택을 보여주지 않았다, 추적 내부 분석, 찾을 수 있지만, 그것은 단지 쇼 당신은 사용하는 순차적 스캐닝 데이터를 찾는 방법을.
다른 하나는 전체 테이블 스캔 일반 인덱스를 사용하는 동안 기본 키 인덱스를 사용하여 스캔 전체 테이블은; 아마 유일한 차이는있다 하지만 두 사람은 B + 트리의 특성에 쓸모가있는 찾기 위해 나무를 지출하지 않았다 쿼리 성능을 향상시킬 수 있습니다.
여섯째, 결론
1, 전체 SQL 쿼리 기본 키만을 퍼지 쿼리 결과 세트, 커버 인덱스 때문에, 인덱스가 쿼리 필드를 해당 보낼 때.
2, 인덱스를 사용하지만 특성을 보낼 수있는 나무 만 통과의 정상적인 순서를 찾는데 실패하더라도.
정상 전체 테이블 스캔되도록 순회 순서의 기본 키 인덱스가 3 인 동안, 사실 모두의 성능은 실제로 동일하다.