[분석] 퍼지 인덱스를 이동 원리를 설명 MYSQL 및 전체 질문의 원칙의 추적 심층 분석

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_keyskey관계는, 우리는 그것을 확인하는 통상 촬영을 인덱스를 사용한다.

다음 SQL, 모든 퍼지 쿼리하지만 인덱스를 복용의 특정 보장 권리 퍼지 쿼리, 우리는이 시간에 별도로보고 possible_keyskey값 :

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 인 동안, 사실 모두의 성능은 실제로 동일하다.

추천

출처www.cnblogs.com/Howinfun/p/12449975.html