8.8.2 EXPLAIN 출력 포맷
EXPLAIN 문은 SELECT 문의 실행 계획에 대한 정보를 제공합니다.
EXPLAIN 은 SELECT 문에서 사용되는 각 테이블에 대한 정보 행을 반환합니다. 이것은 MySQL이 문을 처리하는 동안 테이블을 읽는 순서대로 출력에 테이블을 나열합니다. MySQL은 Nested Loop Join 메소드를 사용하여 모든 결합을 해결합니다. 이것은 MySQL이 첫 번째 테이블에서 행을 읽고 다음 두 번째 테이블, 세 번째 테이블과 같이, 일치하는 행을 찾는 것을 의미합니다. 모든 테이블이 처리되면, MySQL은 선택된 컬럼을 출력하고, 일치하는 행이있는 테이블을 찾을 때까지 테이블 목록 퇴보합니다. 다음 행을 테이블에서 읽은 프로세스는 다음 테이블로 이동합니다.
EXTENDED 키워드를 사용하면 EXPLAIN 은 EXPLAIN 문에 계속 SHOW WARNINGS 명령문을 발행하여 표시 할 수있는 추가 정보를 생성합니다. EXPLAIN EXTENDED 는 필터 처리된 칼럼도 표시합니다. 섹션 8.8.3 "EXPLAIN EXTENDED 출력 형식" 을 참조하십시오.
EXTENDED 키워드와 PARTITIONS 키워드를 동일한 EXPLAIN 문을 함께 사용 할 수 없습니다.
EXPLAIN출력 컬럼EXPLAIN결합 형EXPLAIN추가 정보EXPLAIN출력의 해석
EXPLAIN 출력 컬럼
이 섹션에서는 EXPLAIN 에 의해 생성되는 출력 컬럼에 대해 설명합니다. 뒤의 섹션에서 type 과 Extra 컬럼에 대한 추가 정보를 제공합니다.
EXPLAIN 의 각 출력 행은 하나의 테이블에 대한 정보를 제공합니다. 각 행은 표 8.1 "EXPLAIN 출력 열" 로 요약하고 다음 표에 설명되어있는 값이 포함됩니다.
표 8.1 EXPLAIN 출력 컬럼
| 컬럼 | 의미 |
|---|---|
id | SELECT 식별자. |
select_type | SELECT 형 |
table | 출력 행의 테이블 |
partitions | 일치하는 파티션 |
type | 결합 형 |
possible_keys | 선택 가능한 인덱스 |
key | 실제로 선택된 인덱스 |
key_len | 선택된 키의 길이 |
ref | 인덱스와 비교되는 컬럼 |
rows | 조사되는 행의 견적 |
filtered | 테이블 조건에 의해 필터링되는 행의 비율 |
Extra | 추가 정보 |
idSELECT식별자. 이것은 쿼리의SELECT의 연번입니다. 행이 다른 행의 합집합 결과를 참조하는 경우, 값은NULL이 될 수 있습니다. 이 경우table컬럼은<union등의 값이 표시되고 행이M,N>M과N의id값이있는 행의 합집합을 참조하는 것이 표시됩니다.select_typeSELECT유형에서 다음 표에 나와 있지만 중 하나입니다.select_type값의미 SIMPLE간단한 SELECT(UNION이나 서브 쿼리를 사용하지 않습니다)PRIMARY가장 바깥 쪽 SELECTUNIONUNION의 2 번째 이후의SELECT문DEPENDENT UNIONUNION의 2 번째 이후의SELECT문에서 외부 쿼리에 따라 달라집니다UNION RESULTUNION의 결과입니다.SUBQUERY서브 쿼리의 첫번째 SELECTDEPENDENT SUBQUERY서브 쿼리의 첫번째 SELECT에서 외부 쿼리에 따라 달라집니다DERIVED파생 테이블 SELECT(FROM절의 서브 쿼리)MATERIALIZED실체화 된 서브 쿼리 UNCACHEABLE SUBQUERY결과를 캐시하지 못하고 외부 쿼리의 행마다 재평가 될 필요가있는 서브 쿼리 UNCACHEABLE UNION캐시 불가능한 서브 쿼리 ( UNCACHEABLE SUBQUERY를 참조하십시오)에 속하는UNION의 2 번째 이후의 SELECTDEPENDENT는 일반적으로 상관 관계 서브 쿼리의 사용을 보여줍니다. 섹션 13.2.10.7 "상관 서브 쿼리" 를 참조하십시오.DEPENDENT SUBQUERY의 평가는UNCACHEABLE SUBQUERY의 평가와는 다릅니다.DEPENDENT SUBQUERY의 경우 외부 문맥의 변수가 다른 값의 각 세트 당 한 번만 서브 쿼리가 다시 평가됩니다.UNCACHEABLE SUBQUERY의 경우 외부 컨텍스트의 각 행에 서브 쿼리가 다시 평가됩니다.서브 쿼리 캐시 가능성은 쿼리 캐시에 쿼리 결과 캐시 (이에 대해서는 섹션 8.9.3.1 "쿼리 캐시 동작" 에서 설명합니다)와 다릅니다. 서브 쿼리 캐시는 쿼리 실행 중에 이루어 쿼리 캐시는 쿼리의 실행이 종료 한 후에 만 결과를 저장하는 데 사용됩니다.
table출력 행에서 참조하는 테이블의 이름입니다. 이것도 다음 값 중 하나가 될 수 있습니다.
<union: 줄은M,N>M과N의id값이있는 행의 합집합을 참조합니다.<derived: 줄은N>N의id값이있는 행의 파생 테이블 결과를 볼 수 있습니다. 파생 테이블은 예를 들어FROM절의 서브 쿼리의 결과 등입니다.<subquery: 줄은N>N의id값이있는 행의 실체화 된 서브 쿼리의 결과를 볼 수 있습니다. 섹션 8.2.1.18.2 "서브 쿼리 구체화에 의한 서브 쿼리의 최적화" 를 참조하십시오.
partitions쿼리에서 레코드가 일치되는 파티션. 이 컬럼은
PARTITIONS키워드가 사용되는 경우에만 표시됩니다. 분할되지 않은 테이블의 경우이 값은NULL입니다. 섹션 19.3.5 "파티션에 대한 정보를 얻기" 를 참조하십시오.type결합 형. 다양한 형태의 설명은 "
EXPLAIN결합 형 "을 참조하십시오.possible_keyspossible_keys컬럼은 MySQL이 테이블의 행의 검색에 사용하기 위해 선택할 수있는 인덱스를 나타냅니다. 이 컬럼은EXPLAIN의 출력에 표시되는 테이블의 순서에 전혀 의존하지 않습니다. 즉,possible_keys의 키의 일부는 생성 된 테이블의 순서로 실제로 사용하지 못할 수 있습니다.이 컬럼이
NULL의 경우는 관련 인덱스가 없습니다. 이 경우WHERE절을 조사하여 그 인덱스 구성에 적합한 컬럼을 참조하고 있는지 여부를 확인하여 쿼리 성능을 향상시킬 수 있습니다. 그 경우는 적절한 인덱스를 생성하고 다시EXPLAIN으로 쿼리를 확인합니다. 섹션 13.1.7 "ALTER TABLE 구문" 을 참조하십시오.테이블에있는 인덱스를 확인하려면
SHOW INDEX FROM을 사용합니다.tbl_namekeykey컬럼은 MySQL이 실제로 사용하는 것을 결정한 키 (인덱스)를 보여줍니다. MySQL이 행을 조회하는 데 하나의possible_keys인덱스를 사용하기로 결정하면 키 값으로 인덱스가 나열됩니다.key는possible_keys값에 존재하지 않는 인덱스를 지정하고있을 가능성이 있습니다. 이것은possible_keys인덱스 아무도 행의 조회에 적합하지 않은 경우에 발생할 수 있지만 쿼리가 선택한 모든 컬럼이 다른 인덱스 컬럼입니다. 즉, 지정된 인덱스가 선택된 컬럼을 커버하기 위해 반환되는 행을 결정하는 데 사용되지 않지만, 인덱스 스캔 데이터 라인 스캔보다 효율적입니다.InnoDB는 각 보조 인덱스와 함께 기본 키 값을 저장하기 위해InnoDB는 쿼리에서 기본 키 선택하는 경우에도 보조 인덱스에서 선택된 컬럼을 커버 할 수 있습니다.key가NULL의 경우, MySQL은 쿼리를보다 효율적으로 수행하기 위해 사용하는 인덱스를 찾을 수 없습니다.MySQL에서
possible_keys컬럼에 나타난 인덱스를 강제로 사용하게하거나 무시하려면 쿼리FORCE INDEX,USE INDEX또는IGNORE INDEX를 사용합니다. 섹션 13.2.9.3 "인덱스 힌트 구문" 을 참조하십시오.MyISAM테이블과NDB테이블의 경우ANALYZE TABLE을 실행하여 최적화가 더 적절한 인덱스를 선택하는 데 도움이됩니다.NDB테이블의 경우, 이에 따라 분산 된 푸시 다운 조인 성능도 향상됩니다.MyISAM테이블의 경우, myisamchk --analyze는ANALYZE TABLE과 같은 일을 수행합니다. 섹션 7.6 "MyISAM 테이블의 보수와 크래쉬 복구" 를 참조하십시오.key_lenkey_len컬럼은 MySQL이 사용하는 것을 결정한 키의 길이를 나타냅니다.key컬럼에NULL로 표시된 경우,이 길이는NULL입니다.key_len값으로 MySQL이 실제로 사용하는 다중 키 파트 수를 확인할 수 있습니다.refref컬럼은 테이블에서 행을 선택하기 위해key컬럼에 지정된 인덱스에 비교되는 컬럼 또는 상수를 나타냅니다.값이
func의 경우, 사용되는 값은 특정 함수의 결과입니다. 어떤 함수 있는지 확인하려면EXPLAIN EXTENDED다음에SHOW WARNINGS를 붙여 사용합니다. 함수는 실제로는 산술 연산자와 같은 연산자 일 수 있습니다.rowsrows컬럼은 MySQL이 쿼리를 실행하기 위해 조사 할 필요가 있다고 생각 행수를 나타냅니다.InnoDB테이블의 경우, 이것은 추정치이며, 항상 정확하지 않을 수 있습니다.filteredfiltered컬럼은 테이블 조건에 의해 필터링 된 테이블 행의 추정 비율을 나타냅니다. 즉,rows는 조사되는 추정 행 수를 나타내고,rows×filtered/100이 이전 테이블과 조인되는 행 수를 나타냅니다.EXPLAIN EXTENDED를 사용하면이 열이 표시됩니다.Extra이 컬럼은 MySQL이 쿼리를 해결하는 방법에 대한 정보가 포함되어 있습니다. 다양한 값에 대한 설명은 "
EXPLAIN추가 정보 "를 참조하십시오.
EXPLAIN 결합 형
EXPLAIN 출력의 type 컬럼은 테이블의 결합 방법을 설명합니다. 다음 목록에 가장 적절한 형태에서 가장 잘못된 유형의 순서로 정렬 된 결합 형을 나타냅니다.
system테이블에 행이 하나 밖에 없습니다 (= system 테이블). 이것은
const결합 형의 특수한 케이스입니다.const테이블에 일치하는 레코드가 최대 1 가지 쿼리를 시작할 때 읽습니다. 행이 하나 밖에 없기 때문에이 행의 열 값은 최적화의 나머지를 통해 상수로 간주 될 수 있습니다.
const테이블은 한번 밖에 읽을 수 없기 때문에 매우 빠릅니다.const는PRIMARY KEY또는UNIQUE인덱스의 모든 부분을 상수 값과 비교할 때 사용됩니다. 다음 쿼리는tbl_name은const테이블로 사용할 수 있습니다.SELECT * FROM
tbl_nameWHEREprimary_key= 1; SELECT * FROMtbl_nameWHEREprimary_key_part1= 1 ANDprimary_key_part2= 2;eq_ref이전 테이블의 행의 조합에 대해이 테이블에서 한 줄씩 읽습니다.
system및const형 이외에서 이것은 최적의 결합 형입니다. 이것은 결합 인덱스의 모든 파트가 사용되어 인덱스가PRIMARY KEY또는UNIQUE NOT NULL인덱스 인 경우에 사용됩니다.eq_ref는=연산자를 사용하여 비교되는 인덱스 설정된 컬럼에 사용할 수 있습니다. 비교 값은 상수 또는이 테이블 이전에 읽은 테이블의 컬럼을 사용하는 식을 지정할 수 있습니다. 다음의 예에서는 MySQL은eq_ref조인을 사용하여ref_table을 처리 할 수 있습니다.SELECT * FROM
ref_table,other_tableWHEREref_table.key_column=other_table.column; SELECT * FROMref_table,other_tableWHEREref_table.key_column_part1=other_table.columnANDref_table.key_column_part2= 1;ref이전 테이블의 행의 조합에 대해 일치하는 인덱스 값을 가진 모든 행이이 테이블에서 읽습니다.
ref조인 키의 왼쪽 프리픽스 만 사용되는 경우, 또는 키가PRIMARY KEY나UNIQUE인덱스가 아닌 경우 (즉, 결합에서 키 값에 따라 단일 행을 선택할 수없는 경우)에 사용 됩니다. 사용되는 키가 몇 줄 밖에 일치하지 않는 경우, 이것은 적절한 결합 형입니다.ref는=또는<=>연산자를 사용하여 비교되는 인덱스 설정된 컬럼에 사용할 수 있습니다. 다음의 예에서는 MySQL은ref조인을 사용하여ref_table을 처리 할 수 있습니다.SELECT * FROM
ref_tableWHEREkey_column=expr; SELECT * FROMref_table,other_tableWHEREref_table.key_column=other_table.column; SELECT * FROMref_table,other_tableWHEREref_table.key_column_part1=other_table.columnANDref_table.key_column_part2= 1;fulltext결합은
FULLTEXT인덱스를 사용하여 수행됩니다.ref_or_null이 결합 형은
ref와 유사하지만, MySQL이NULL값을 갖는 행의 추가 검색을 수행 할 추가됩니다. 이 결합 형의 최적화는 대부분의 경우에 하위 쿼리의 해결에 사용됩니다. 다음의 예에서는 MySQL은ref_or_null조인을 사용하여ref_table을 처리 할 수 있습니다.SELECT * FROM
ref_tableWHEREkey_column=exprORkey_columnIS NULL;섹션 8.2.1.8 "IS NULL 최적화" 를 참조하십시오.
index_merge이 결합 형은 인덱스 병합 최적화가 사용 된 것을 나타냅니다. 이 경우 출력 행의
key컬럼은 사용 된 인덱스의 목록이 포함되어key_len는 사용 된 인덱스의 최대 키 파트의 목록이 포함됩니다. 자세한 내용은 섹션 8.2.1.4 "인덱스 병합 최적화" 를 참조하십시오.unique_subquery이 형식은 다음과 같은 형식의
IN서브 쿼리의ref를 대체합니다.valueIN (SELECTprimary_keyFROMsingle_tableWHEREsome_expr)unique_subquery는 효율성을 위해 서브 쿼리를 완전히 대체 단순한 인덱스 조회 기능입니다.index_subquery이 결합 형은
unique_subquery와 비슷합니다.IN서브 쿼리를 대체하지만, 다음과 같은 형식의 서브 쿼리의 고유하지 않은 인덱스에 대해 작동합니다.valueIN (SELECTkey_columnFROMsingle_tableWHEREsome_expr)range행을 선택하기위한 인덱스를 사용하여 특정 범위에있는 행 만 검색됩니다. 출력 행의
key컬럼은 사용 된 인덱스를 나타냅니다.key_len는 사용 된 최대 인덱스 부분이 포함됩니다. 이 형식의ref컬럼은NULL입니다.range는=<<>,>, >>=,<,<=,IS NULL,<=>,BETWEEN또는IN()연산자 중 하나를 사용하여 키 컬럼을 상수와 비교하는 경우에 사용 수 있습니다.SELECT * FROM
tbl_nameWHEREkey_column= 10; SELECT * FROMtbl_nameWHEREkey_columnBETWEEN 10 and 20; SELECT * FROMtbl_nameWHEREkey_columnIN (10,20,30); SELECT * FROMtbl_nameWHEREkey_part1= 10 ANDkey_part2IN (10,20,30);indexindex결합 형 타입은 인덱스가 스캔되는 것을 제외하고,ALL과 동일합니다. 이것은 두 가지 방법으로 이루어집니다.인덱스가 쿼리 첨부 인덱스에서 사용하면 테이블에서 필요한 모든 데이터를 만족시킬 수있는 경우 인덱스 트리 만 검색됩니다. 이 경우
Extra컬럼에Using index라고 표시됩니다. 인덱스는 일반 테이블 데이터보다 작기 때문에 인덱스 만 스캔은 일반적으로ALL보다 빠릅니다.풀 테이블 스캔은 인덱스에서 읽기를 사용하여 인덱스 순서로 데이터 행을 조회하여 수행됩니다.
Extra컬럼에Uses index가 표시되지 않습니다.
MySQL은 쿼리에서 단일 인덱스의 일부인 컬럼 만이 사용되는 경우이 결합 형을 사용할 수 있습니다.
ALL풀 테이블 스캔은 이전 테이블의 행의 조합에 대해 실행됩니다. 이것은 일반적으로 테이블이
const로 표시되지 않은 첫 번째 테이블 인 경우에는 적합하지 않고, 보통 다른 모든 경우에 현저 부적절합니다. 일반적으로 상수 값 또는 이전 테이블에서 컬럼 값에 따라 테이블에서 행의 취득을 가능하게하는 인덱스를 추가하면ALL을 피할 수 있습니다.
EXPLAIN 추가 정보
EXPLAIN 출력의 Extra 컬럼은 MySQL이 쿼리를 해결하는 방법에 대한 정보가 포함되어 있습니다. 다음 목록은이 컬럼에 표시 될 수있는 값에 대해 설명합니다. 쿼리를 가능한 한 빠르게하려면, Using filesort 및 Using temporary 의 Extra 값에주의합니다.
Child of 'table'pushed join @ 1이 테이블은 NDB 커널로 푸시 다운 할 수있는 결합의
table의 자식으로 참조됩니다. MySQL Cluster에서 푸시 다운 된 결합이 유효한 경우에만 적용됩니다. 자세한 내용과 예제는ndb_join_pushdown서버 시스템 변수의 설명을 참조하십시오.const row not foundSELECT ... FROM같은 쿼리의 경우, 테이블은 비어있었습니다.tbl_nameDeleting all rowsDELETE대해 일부 스토리지 엔진 (MyISAM등)은 쉽고 빠르게 모든 행 테이블을 삭제하는 핸들러 메소드를 지원하고 있습니다. 이Extra값은 엔진이 최적화가 사용 된 경우에 표시됩니다.DistinctMySQL은 개별 값을 검색하기 위해 첫 번째로 일치하는 행을 찾으면 현재의 행의 조합에 관하여 더 줄 검색을 중지합니다.
FirstMatch (tbl_name)tbl_name은 준 결합 FirstMatch 결합 바로 가기 전략이 사용됩니다.Full scan on NULL key이것은 옵티마이 저가 인덱스 조회 접근 방법을 사용할 수없는 경우 대체 전략으로 서브 쿼리의 최적화로 이루어집니다.
Impossible HAVINGHAVING절은 항상 false로 어떤 행을 선택할 수 없습니다.Impossible WHEREWHERE절은 항상 false로 어떤 행을 선택할 수 없습니다.Impossible WHERE noticed after reading const tablesMySQL은 모든
const(및system) 테이블을 읽고WHERE절이 항상 false임을 알립니다.LooseScan (m..n)준 결합 LooseScan 전략이 사용됩니다.
m및n은 키 파트 번호입니다.Materialize,ScanMySQL 5.6.7 이전에는, 이것은 하나의 실체화 된 임시 테이블의 사용을 보여줍니다.
Scan이 있으면 테이블의 읽기에 임시 테이블 인덱스는 사용되지 않습니다. 그렇지 않은 경우는 인덱스 조회가 사용됩니다. 또한Start materialize항목을 참조하십시오.MySQL 5.6.7 현재 실체화는
MATERIALIZED의select_type값이있는 행과<subquery의N>table값이있는 행으로 표시됩니다.No matching min / max rowSELECT MIN(...) FROM ... WHERE같은 쿼리의 조건을 만족하는 행이 없습니다.conditionno matching row in const table결합 된 쿼리에서 빈 테이블 또는 고유 인덱스 조건을 만족하는 행이없는 테이블이있었습니다.
No matching rows after partition pruningDELETE또는UPDATE에 대해 최적화 파티션 정리 후 삭제 또는 업데이트하는 것이 아무것도 발견하지 않았습니다. 그것은SELECT문Impossible WHERE의미가 비슷합니다.No tables used쿼리에
FROM절이 없거나FROM DUAL절이 있습니다.INSERT또는REPLACE문에서SELECT부분이없는 경우EXPLAIN에이 값이 표시됩니다. 예를 들어,EXPLAIN INSERT INTO t VALUES(10)에 대해 그것은EXPLAIN INSERT INTO t SELECT 10 FROM DUAL와 동일하기 때문에 표시됩니다.Not existsMySQL은 쿼리에 대한
LEFT JOIN최적화를 실행할 수있어LEFT JOIN조건에 일치하는 1 개의 행이 발견되면 이전 행의 조합이 테이블에 더 행을 조사하지 않습니다. 이것은 이렇게 최적화 쿼리 유형의 예입니다.SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;
t2.id가NOT NULL로 정의되어 있다고합니다. 이 경우, MySQL은t1을 스캔하고t1.id값을 사용하여t2의 행을 조회합니다. MySQL이t2에 일치하는 행을 찾으면t2.id는NULL이되지 않는 것을 알고 있기 때문에 같은id값을 가진t2의 나머지 행을 스캔하지 않습니다. 즉,t1의 각 행에 대해, MySQL은t2에서 실제로 일치하는 행 수에 관계없이t2에서 하나의 조회 만 수행해야합니다.Range checked for each record (index map :N)MySQL은 사용에 적합한 인덱스를 찾지 못했지만, 이전 테이블에서 컬럼 값을 발견 한 후 일부 인덱스를 사용할 수 있는지 알 수있었습니다. 이전 테이블의 행의 조합에 대해 MySQL은
range또는index_merge접근 방식을 사용하여 행을 검색 할 수 있는지 여부를 확인합니다. 이것은 매우 빠르지 않지만, 인덱스가 전혀없는 결합의 실행보다 빠릅니다. 이전 테이블의 모든 컬럼 값을 알고 있으며, 상수로 간주되는 것을 제외하고, 적용 기준은 섹션 8.2.1.3 "range 최적화" 과 섹션 8.2.1.4 "인덱스 병합 최적화" 에 설명 된 있다 같습니다.인덱스는 테이블의
SHOW INDEX에 표시된 순서대로 1부터 번호가 매겨집니다. 인덱스 맵 값N은 후보 인덱스를 나타내는 비트 마스크입니다. 예를 들어,0x19(2 진수 11001)의 값은 인덱스 1, 4 및 5가 고려되는 것을 나타냅니다.scannedNdatabases이것은 섹션 8.2.4 "INFORMATION_SCHEMA 쿼리 최적화" 에 설명 된대로 서버가
INFORMATION_SCHEMA테이블의 쿼리를 처리 할 때 사용하는 디렉토리 스캔 수를 나타냅니다.N의 값은 0 또는all입니다.Select tables optimized away쿼리는 모든 인덱스를 사용하여 해결 된 집계 함수 (
MIN(),MAX()) 또는COUNT(*)만 포함되어 있지만GROUP BY절은 포함되지 않았습니다. 최적화는 1 행만 반환한다고 판단했습니다.Skip_open_table,Open_frm_only,Open_trigger_only,Open_full_table이 값은 섹션 8.2.4 "INFORMATION_SCHEMA 쿼리 최적화" 에 설명하도록
INFORMATION_SCHEMA테이블에 대한 쿼리에 적용 할 파일 오픈 최적화를 보여줍니다.Skip_open_table: 테이블 파일을 열 필요가 없습니다. 데이터베이스 디렉토리를 검색하여 쿼리에서 이미 정보를 사용할 수 있도록되어 있습니다.Open_frm_only: 테이블의.frm파일 만 열어야합니다.Open_trigger_only: 테이블의.TRG파일 만 열어야합니다.Open_full_table: 최적화되지 않은 정보의 조회..frm,.MYD, 그리고.MYI파일을 열어야합니다.
Start materialize,End materialize,ScanMySQL 5.6.7 이전에는, 이것은 여러 실체화 된 임시 테이블의 사용을 보여줍니다.
Scan이 있으면 테이블의 읽기에 임시 테이블 인덱스는 사용되지 않습니다. 그렇지 않은 경우는 인덱스 조회가 사용됩니다. 또한Materialize항목을 참조하십시오.MySQL 5.6.7 현재 실체화는
MATERIALIZED의select_type값이있는 행과<subquery의N>table값이있는 행으로 표시됩니다.Start temporary,End temporary이것은 준 결합 중복 제거 전략 임시 테이블의 사용을 보여줍니다.
unique row not foundSELECT ... FROM같은 쿼리의 경우 테이블에tbl_nameUNIQUE인덱스 나PRIMARY KEY한정된 행이 없습니다.Using filesortMySQL은 정렬 된 순서로 행을 검색하는 방법을 찾기 위해 추가 경로를 실행해야합니다. 정렬은 결합 형에 따라 모든 행을 진행 소트 키와
WHERE절에 일치하는 모든 행에 대해 행에 대한 포인터를 저장하고 실행됩니다. 다음 키가 정렬되고 정렬 순서에서 행이 검색됩니다. 섹션 8.2.1.15 "ORDER BY 최적화" 를 참조하십시오.Using index실제 행을 읽기위한 추가 탐색을 수행 할 필요가없고, 인덱스 트리의 정보만을 사용하여 테이블에서 컬럼 정보를 검색합니다. 이 전략은 쿼리에서 단일 인덱스의 일부분 인 컬럼만을 사용하는 경우에 사용할 수 있습니다.
Extra컬럼에Using where라고 표시된 경우 키 값 조회를 실행하기 위해 인덱스가 사용되는 것을 의미합니다.Using where가없는 경우 옵티마이 저가 인덱스를 읽어 데이터 행 읽기를 피할 수 있지만, 그것을 조회로 사용하지 않습니다. 예를 들어, 인덱스가 쿼리 첨부 인덱스 인 경우, 최적화는 그것을 조회에 사용하지 않고 그것을 검사 할 수 있습니다.사용자 정의 클러스터링 된 인덱스를 가지는
InnoDB테이블의 경우 인덱스는Extra컬럼에Using index가없는 경우에도 사용할 수 있습니다. 이는type이index에서key가PRIMARY의 경우입니다.Using index condition인덱스 튜플에 액세스 먼저 그들을 테스트하여 모든 테이블 행을 읽을 여부를 판단하여 테이블을 읽습니다. 이와 같이 요구하지 않는 한 모든 테이블 행 읽기를 지연 ( "푸시 다운")하는 인덱스 정보가 사용됩니다. 섹션 8.2.1.6 "인덱스 조건문 푸시 다운 최적화" 를 참조하십시오.
Using index for group-byUsing index테이블 액세스 방법과 마찬가지로Using index for group-by은 MySQL이 실제 테이블에 추가 디스크 액세스를하지 않고GROUP BY또는DISTINCT쿼리의 모든 컬럼을 얻기 위해 사용할 수있는 인덱스 을 찾아 냈다는 것을 나타냅니다. 또한 각 그룹에 대해 약간 인덱스 엔트리 만이 읽을 수 있도록 색인을 가장 효율적으로 사용됩니다. 자세한 내용은 섹션 8.2.1.16 "GROUP BY 최적화" 를 참조하십시오.Using join buffer (Block Nested Loop),Using join buffer (Batched Key Access)초기의 결합에서의 테이블은 각 부분에 결합 버퍼에 읽힌 해당 행이 버퍼에서 사용되어 현재 테이블의 결합이 실행됩니다.
(Block Nested Loop)는 Block Nested Loop 알고리즘의 사용을 나타내며(Batched Key Access)는 Batched Key Access 알고리즘의 사용을 보여줍니다. 즉,EXPLAIN출력의 이전 행의 테이블에서 키가 버퍼링되어Using join buffer가 표시된 라인에 의해 나타내지는 테이블에서 일치하는 행이 일괄 인출됩니다.Using MRR테이블은 Multi-Range Read 최적화 전략을 사용하여 읽습니다. 섹션 8.2.1.13 "Multi-Range Read 최적화" 를 참조하십시오.
Using sort_union(...),Using union(...),Using intersect(...)이들은
index_merge결합 형 인덱스 스캔이 어떻게 병합하는 방법을 보여줍니다. 섹션 8.2.1.4 "인덱스 병합 최적화" 를 참조하십시오.Using temporary쿼리를 해결하기 위해 MySQL은 결과를 저장할 임시 테이블을 작성해야합니다. 이것은 일반적으로 쿼리에 컬럼을 다르게 표시하는
GROUP BY절과ORDER BY절이 포함 된 경우에 발생합니다.Using whereWHERE절은 다음 테이블에 일치하거나 클라이언트에 전송되는 행을 제한하는 데 사용됩니다. 구체적으로 테이블에서 모든 행을 반입하거나 조사 할 의도가없는 한,Extra값이Using where가 아니고, 테이블 결합 형이ALL또는index인 경우, 쿼리에 어떤 오류가있을 수 있습니다.Using where with pushed condition이 항목은
NDB테이블에만 적용됩니다. 즉, MySQL Cluster가 조건문 푸시 다운 최적화를 사용하여 인덱스 설정되지 않은 컬럼과 상수의 직접 비교의 효율성을 향상시킵니다. 그런 경우 조건이 클러스터의 데이터 노드에 "푸시 다운"된 모든 데이터 노드에서 동시에 평가됩니다. 이렇게하면 일치하지 않는 행을 네트워크를 통해 보낼 필요가 없어지고, 조건문 푸시 다운을 사용할 수 있지만 사용하지 않는 경우보다 그러한 쿼리를 5 - 10 배 속도를 높일 수 있습니다. 자세한 내용은 섹션 8.2.1.5 "엔진 조건문 푸시 다운 최적화" 를 참조하십시오.
EXPLAIN 출력의 해석
EXPLAIN 출력의 rows 컬럼의 값을 곱한 값을 취득함으로써 결합이 어느 정도 적합한지를 나타내는 적절한 기준을 얻을 수 있습니다.이것은 쿼리를 실행하기 위해 MySQL을 조사 할 필요가있는 행수를 대략적으로 보여주는 것입니다. max_join_size 시스템 변수가 쿼리를 제한하려면이 행의 곱은 어떻게 여러 테이블 SELECT 문을 실행하고 어느 것을 중지 할 것인지 결정하는 데에도 사용됩니다. 섹션 8.11.2 "서버 파라미터의 튜닝」 을 참조하십시오.
다음 예제는 EXPLAIN 에 의해 얻어진 정보에 따라 여러 테이블 결합을 단계적으로 최적화하는 방법을 보여줍니다.
여기에 표시된 SELECT 문이 있으며, EXPLAIN 을 사용하여 조사 할 생각이라고합니다.
EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
tt.ProjectReference, tt.EstimatedShipDate,
tt.ActualShipDate, tt.ClientID,
tt.ServiceCodes, tt.RepetitiveID,
tt.CurrentProcess, tt.CurrentDPPerson,
tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
et_1.COUNTRY, do.CUSTNAME
FROM tt, et, et AS et_1, do
WHERE tt.SubmitTime IS NULL
AND tt.ActualPC = et.EMPLOYID
AND tt.AssignedPC = et_1.EMPLOYID
AND tt.ClientID = do.CUSTNMBR;
이 예에서는 다음과 같이 가정하고 있습니다.
비교 대상의 열은 다음과 같이 선언되어 있습니다.
테이블 컬럼 데이터 형 ttActualPCCHAR (10)ttAssignedPCCHAR (10)ttClientIDCHAR (10)etEMPLOYIDCHAR (15)doCUSTNMBRCHAR (15)테이블에는 다음 인덱스가 있습니다.
테이블 인덱스 ttActualPCttAssignedPCttClientIDetEMPLOYID(기본 키)doCUSTNMBR(기본 키)tt.ActualPC값은 균일하게 분포되어 있지 않습니다.
처음에는 최적화가 실행되기 전에는 EXPLAIN 문에서 다음과 같은 정보가 생성되었습니다.
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
do ALL PRIMARY NULL NULL NULL 2135
et_1 ALL PRIMARY NULL NULL NULL 74
tt ALL AssignedPC, NULL NULL NULL 3872
ClientID,
ActualPC
Range checked for each record (index map : 0x23)
각 테이블의 type 이 ALL 이기 때문에이 출력은 MySQL이 모든 테이블, 즉 모든 행의 조합 데카르트를 생성하는 것을 보여줍니다. 이것은 각 테이블의 행 수를 곱한 값을 조사 할 필요가 있기 때문에 상당히 시간이 걸립니다. 이 케이스의 경우이 곱이 74 × 2135 × 74 × 3872 = 45,268,558,720 줄 것입니다. 테이블이 더 크면 얼마나 시간이 걸려 있었는지 쉽게 상상이갑니다.
여기에서 문제의 하나는 열이 동일한 형태와 크기로 선언 된 경우, MySQL은 컬럼에 인덱스를보다 효율적으로 사용할 수있는 것입니다. 이 컨텍스트에서는 VARCHAR 과 CHAR 같은 크기로 선언되어 있다면, 그들은 동일한 것으로 간주됩니다. tt.ActualPC 는 CHAR (10) 으로 선언되어있어 et.EMPLOYID 는 CHAR (15) 이므로 길이의 불일치가 있습니다.
이 컬럼 길이의 불일치를 수정하려면 ALTER TABLE 을 사용하여 ActualPC 을 10 자에서 15 자로 길어합니다.
mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR (15);
이제 tt.ActualPC 와 et.EMPLOYID 은 모두 VARCHAR (15) 입니다. EXPLAIN 문을 다시 실행하면 다음과 같은 결과가 생성됩니다.
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC, NULL NULL NULL 3872 Using
ClientID, where
ActualPC
do ALL PRIMARY NULL NULL NULL 2135
Range checked for each record (index map : 0x1)
et_1 ALL PRIMARY NULL NULL NULL 74
Range checked for each record (index map : 0x1)
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
이것은 완전하지는 않지만 훨씬 개선되고 있습니다. rows 값의 곱은 74의 계수만큼 줄어 듭니다. 이 버전은 몇 초에서 실행합니다.
두 번째 변경을 실행하여 tt.AssignedPC = et_1.EMPLOYID 과 tt.ClientID = do.CUSTNMBR 의 비교에서 컬럼 길이의 불일치를 해소 할 수 있습니다.
mysql>ALTER TABLE tt MODIFY AssignedPC VARCHAR (15)->MODIFY ClientID VARCHAR (15);
변경 후 EXPLAIN 은 다음과 같은 출력을 생성합니다.
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 Using
ClientID, where
ActualPC
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
이 시점에서 쿼리는 거의 가능한 한 충분히 최적화되어 있습니다. 나머지 문제는 MySQL은 기본적으로 tt.ActualPC 컬럼의 값이 균일하게 분포되어 있다고 가정하지만 tt 테이블에 그것이 맞지 않는 것입니다. 다행히 MySQL에 키 분포를 분석하도록 말할 쉽습니다.
mysql> ANALYZE TABLE tt;
추가 인덱스 정보에 의해 결합이 완벽하게되어, EXPLAIN 가 다음의 결과를 생성합니다.
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC NULL NULL NULL 3872 Using
ClientID, where
ActualPC
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
EXPLAIN 출력의 rows 컬럼은 MySQL 결합 최적화의 학습에 의한 추측입니다. rows 의 곱과 쿼리가 반환 실제 행 수를 비교하여 수치가 실제와 가까운 여부를 확인하십시오. 수치가 꽤 다른 경우에는 SELECT 문에서 STRAIGHT_JOIN 을 사용하고 FROM 절에서 다른 순서로 테이블을 나열 해 보면 성능을 개선 할 수 있습니다.
경우에 따라서는 서브 쿼리에서 EXPLAIN SELECT 를 사용하면 데이터 변경 명령문을 실행할 수 있습니다. 자세한 내용은 섹션 13.2.10.8 "FROM 절의 서브 쿼리" 를 참조하십시오.