14.13.16.1 영속적 옵티마이저 통계 파라미터 구성
계획 안정성 은 가장 크고 가장 중요한 쿼리의 바람직한 목표입니다.
InnoDB
는 최적화가 가장 효율적인 쿼리 실행 계획 을 쉽게 찾을 수 있도록 항상 InnoDB
테이블 당 통계를 계산하여 왔습니다. 이러한 통계를 영구적으로 할 수있게 되었기 때문에 특정 쿼리의 인덱스 사용 상황과 결합 순서가 변경 될 가능성은 낮습니다. 이 기능은 기본적으로 활성화되어 있으며, 구성 옵션 innodb_stats_persistent
에서 사용할 수 있습니다.
innodb_stats_persistent_sample_pages
구성 옵션을 설정함으로써 통계를 수집하기 위해 수행되는 샘플링의 양을 제어합니다.
구성 옵션 innodb_stats_auto_recalc
테이블에 (행 10 % 이상) 대폭적인 변경이 가해 졌을 때마다 통계를 자동으로 계산할지 여부를 결정합니다.
통계의 자동 재 계산 (이것은 백그라운드에서 실행됩니다)는 비동기 특성으로 인해, innodb_stats_auto_recalc
가 활성화되어 있었다고해도, 테이블의 10 %를 초과하는 부분에 영향을 미칠 DML 작업을 수행 한 직후에 통계가 다시 계산되는 것은 아닙니다. 경우에 따라서는 통계의 재 계산이 몇 초 지연 될 수 있습니다. 테이블의 큰 부분을 변경 한 직후에 최신 통계가 필요한 경우 통계의 동기적인 (전경) 재 계산을 시작하기 위해 ANALYZE TABLE
을 실행하십시오.
innodb_stats_auto_recalc
이 비활성화되어있는 경우에는 인덱스 컬럼에 대폭적인 변경을 수행 한 후 각 해당 테이블에 대해 ANALYZE TABLE
문을 발행하여 옵티 마이저 통계의 정확성을 보장합니다. 이 문은 대표적인 데이터가 테이블에로드 된 후 설치 스크립트 실행하거나 인덱스 컬럼의 내용이 DML 작업에 의해 크게 변경된 후에 정기적으로 또는 낮은 활동 시간에 일정에 따라 수행 할 수 있습니다. 기존 테이블에 새로운 인덱스가 추가 된 경우 innodb_stats_auto_recalc
의 값에 관계없이 인덱스 통계가 계산되어 innodb_index_stats
테이블에 추가됩니다.
새로운 인덱싱 된 때 통계가 수집되도록되도록, innodb_stats_auto_recalc
옵션을 활성화하거나 영구 통계 모드가 활성화되어있을 때 새 인덱스를 만들 때마다 ANALYZE TABLE
을 실행 하십시오.
테이블을 작성하기 전에 글로벌 수준에서 innodb_stats_persistent
, innodb_stats_auto_recalc
옵션을 설정하거나 CREATE TABLE
및 ALTER TABLE
문에서 STATS_PERSISTENT
, STATS_AUTO_RECALC
및 STATS_SAMPLE_PAGES
절을 사용하여 시스템 전체의 설정을 무시하고 개별 테이블 영구 통계를 구성 할 수 있습니다.
이전에는 이러한 통계는 각 서버의 재부팅와 일부 작업 후에 지워 테이블이 다음 액세스 할 때 다시 계산되어있었습니다. 이러한 통계는 다음에 다른 추정치가 생성 될 수있는 임의의 샘플링 기법을 사용하여 계산되기 때문에 실행 계획에서 다른 선택이 이루어지고 그 때문에 쿼리 성능이 달라집니다.
주기적으로 삭제되기 이전의 통계 수집 방법에 돌아가려면 명령 ALTER TABLE
을 실행합니다. 자세한 내용은 섹션 14.13.16.2 "비 영구 옵티 마이저 통계 매개 변수 구성" 을 참조하십시오. tbl_name
STATS_PERSISTENT=0
14.13.16.1.1 InnoDB 옵티 마이저 통계로 샘플링되는 페이지의 수 구성
MySQL 쿼리 최적화 프로그램은 인덱스의 상대적인 선택성 에 따라 키 분포에 대한 추정 된 통계 를 사용하여 실행 계획을위한 인덱스를 선택합니다. ANALYZE TABLE
등의 작업을 수행하면 InnoDB
는 인덱스의 중요도 를 추정하기 위해 테이블의 각 인덱스에서 임의의 페이지를 샘플링합니다. (이 기술은 랜덤 다이브 라고합니다.)
통계 추정치의 품질을 제어하는 (그러면 쿼리 최적화에 대한 정보를 개선하기) 위해 런타임에 설정할 수있는 매개 변수 innodb_stats_persistent_sample_pages
를 사용하여 추출 된 페이지 수를 변경할 수 있습니다.
innodb_stats_persistent_sample_pages
의 기본값은 20입니다. 일반적인 지침으로 다음과 같은 문제가 발생했을 경우,이 매개 변수를 변경하는 것을 고려하십시오.
EXPLAIN
의 출력에 표시된대로 통계의 정확도가 충분하지 않기 때문에 최적화가 차선의 계획을 선택한다. 통계의 정확도는 인덱스의 실제 카디 낼 리티 (인덱스 컬럼에 대해SELECT DISTINCT
를 실행하여 반환)을mysql.innodb_index_stats
영구 통계 테이블에 표시된 추정치와 비교하여 확인 수 있습니다.통계의 정확도가 충분하지 않은 것으로 확인 된 경우는 통계 추정치가 충분한 정확도가 될 때까지
innodb_stats_persistent_sample_pages
값을 늘리도록하십시오. 그러나innodb_stats_persistent_sample_pages
을 너무 크게하면,ANALYZE TABLE
의 실행 속도가 느려질 수 있습니다.ANALYZE TABLE
가 너무 느립니다. 이 경우ANALYZE TABLE
의 실행 시간이 허용 될 때까지innodb_stats_persistent_sample_pages
을 줄 이도록하십시오. 그러나이 값을 너무 작게하면 정밀도가 낮은 통계 및 차선의 쿼리 실행 계획이라는 첫 번째 문제로 이어질 수 있습니다.통계의 정확성과
ANALYZE TABLE
의 실행 시간의 균형을 취할 수없는 경우ANALYZE TABLE
의 복잡성을 줄이기 위해 테이블의 인덱스 컬럼의 수를 줄이거 나 파티션의 수를 제한하는 것을 고려 하십시오. 또한 프라이 머리 키 컬럼은 고유하지 않은 모든 인덱스에 추가되기 때문에 테이블의 기본 키의 컬럼 수를 고려하는 것도 중요합니다.자세한 내용은 섹션 14.13.17 "InnoDB 테이블에 ANALYZE TABLE의 복잡성 추정" 을 참조하십시오.
14.13.16.1.2 InnoDB 영구 통계 테이블
영구 통계 기능은 innodb_table_stats
및 innodb_index_stats
라는 이름의 mysql
데이터베이스의 내부적으로 관리되는 테이블에 의존합니다. 이 테이블은 모든 설치, 업그레이드 및 소스로부터 빌드 단계에서 자동으로 설정됩니다.
표 14.8 innodb_table_stats 컬럼
컬럼 이름 | 설명 |
---|---|
database_name | 데이터베이스 이름 |
table_name | 테이블 이름, 파티션 이름 또는 서브 파티션 이름 |
last_update | InnoDB 가 마지막으로이 행을 갱신 한 시간을 나타내는 타임 스탬프 |
n_rows | 테이블 내의 행수 |
clustered_index_size | 기본 인덱스의 크기 (페이지 수) |
sum_of_other_index_sizes | 기타 (비 기본) 인덱스의 총 크기 (페이지 수) |
표 14.9 innodb_index_stats 컬럼
컬럼 이름 | 설명 |
---|---|
database_name | 데이터베이스 이름 |
table_name | 테이블 이름, 파티션 이름 또는 서브 파티션 이름 |
index_name | 인덱스 이름 |
last_update | InnoDB 가 마지막으로이 행을 갱신 한 시간을 나타내는 타임 스탬프 |
stat_name | stat_value 컬럼에 값이보고 된 통계의 이름 |
stat_value | stat_name 컬럼 이름이 지정되는 통계 값 |
sample_size | stat_value 컬럼에 표시된 추정치의 샘플링되는 페이지의 수 |
stat_description | stat_name 컬럼 이름이 지정되는 통계에 대한 설명 |
다음의 예와 같이, innodb_table_stats
테이블과 innodb_index_stats
테이블에는 모두 InnoDB
가 마지막으로 인덱스 통계를 업데이트 한 시간을 나타내는 last_update
열이 포함되어 있습니다.
mysql> select * from innodb_table_stats \ G *************************** 1. row ******************** ******* database_name : sakila table_name : actor last_update : 2014-05-28 16:16:44 n_rows : 200 clustered_index_size : 1 sum_of_other_index_sizes : 1 ...
mysql> select * from innodb_index_stats \ G *************************** 1. row ******************** ******* database_name : sakila table_name : actor index_name : PRIMARY last_update : 2014-05-28 16:16:44 stat_name : n_diff_pfx01 stat_value : 200 sample_size : 1 ...
innodb_table_stats
및 innodb_index_stats
테이블은 일반 테이블이기 때문에 수동으로 업데이트 할 수 있습니다. 통계를 수동으로 업데이트하는 기능은 데이터베이스를 변경하지 않고도 특정 쿼리 최적화 계획과 테스트 대체 계획을 강제로 수행 할 수 있습니다. 통계를 수동으로 업데이트하면 업데이트 된 통계가 MySQL에서 다시로드되도록, FLUSH TABLE
명령을 실행합니다. tbl_name
14.13.16.1.3 InnoDB 영구 통계 테이블의 예
innodb_table_stats
테이블에는 테이블 당 하나의 행이 포함되어 있습니다. 수집 된 데이터를 다음의 예입니다.
테이블 t1
에는 기본 인덱스 (컬럼 a
, b
) 보조 인덱스 (컬럼 c
, d
) 및 고유 인덱스 (컬럼 e
, f
)가 포함되어 있습니다.
CREATE TABLE t1 ( a INT, b INT, c INT, d INT, e INT, f INT, PRIMARY KEY (a, b), KEY i1 (c, d), UNIQUE KEY i2uniq (e, f) ) ENGINE = INNODB;
5 행의 샘플 데이터를 삽입 한 후 테이블은 다음과 같이됩니다.
mysql> SELECT * FROM t1; +---+---+------+------+------+------+ | a | b | c | d | e | f | +---+---+------+------+------+------+ | 1 | 1 | 10 | 11 | 100 | 101 | | 1 | 2 | 10 | 11 | 200 | 102 | | 1 | 3 | 10 | 11 | 100 | 103 | | 1 | 4 | 10 | 12 | 200 | 104 | | 1 | 5 | 10 | 12 | 100 | 105 | +---+---+------+------+------+------+ 5 rows in set (0.00 sec)
통계를 즉시 업데이트하려면 ANALYZE TABLE
을 실행합니다 ( innodb_stats_auto_recalc
이 활성화되어있는 경우 변경 될 테이블 행의 10 % 임계 값에 도달했다고 가정 할 때, 통계는 몇 초 내에 자동 에 업데이트됩니다.)
mysql> ANALYZE TABLE t1; +---------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +---------+---------+----------+----------+ | test.t1 | analyze | status | OK | +---------+---------+----------+----------+ 1 row in set (0.02 sec)
테이블 t1
테이블 통계는 InnoDB
가 마지막으로 테이블 통계를 업데이트 한 시간 ( 2014-03-14 14:36:34
) 테이블의 행 수 ( 5
) 클러스터 된 인덱스의 크기 ( 1
페이지 ) 및 기타 인덱스의 총 크기 ( 2
페이지)이 표시됩니다.
mysql> SELECT * FROM mysql.innodb_table_stats WHERE table_name like 't1'\ G *************************** 1. row ******************** ******* database_name : test table_name : t1 last_update : 2014-03-14 14:36:34 n_rows : 5 clustered_index_size : 1 sum_of_other_index_sizes : 2 1 row in set (0.00 sec)
innodb_index_stats
테이블에는 각 인덱스에 여러 행이 포함되어 있습니다. innodb_index_stats
테이블의 각 행은 stat_name
컬럼 이름이 지정되어 stat_description
컬럼에 설명 된 특정 인덱스 통계에 관련한 데이터를 나타냅니다. 예 :
mysql> SELECT index_name, stat_name, stat_value, stat_description -> FROM mysql.innodb_index_stats WHERE table_name like 't1'; +------------+--------------+------------+-----------------------------------+ | index_name | stat_name | stat_value | stat_description | +------------+--------------+------------+-----------------------------------+ | PRIMARY | n_diff_pfx01 | 1 | a | | PRIMARY | n_diff_pfx02 | 5 | a,b | | PRIMARY | n_leaf_pages | 1 | Number of leaf pages in the index | | PRIMARY | size | 1 | Number of pages in the index | | i1 | n_diff_pfx01 | 1 | c | | i1 | n_diff_pfx02 | 2 | c,d | | i1 | n_diff_pfx03 | 2 | c,d,a | | i1 | n_diff_pfx04 | 5 | c,d,a,b | | i1 | n_leaf_pages | 1 | Number of leaf pages in the index | | i1 | size | 1 | Number of pages in the index | | i2uniq | n_diff_pfx01 | 2 | e | | i2uniq | n_diff_pfx02 | 5 | e,f | | i2uniq | n_leaf_pages | 1 | Number of leaf pages in the index | | i2uniq | size | 1 | Number of pages in the index | +------------+--------------+------------+-----------------------------------+ 14 rows in set (0.00 sec)
stat_name
컬럼에는 다음과 같은 유형의 통계가 표시됩니다.
size
:stat_name
=size
이면stat_value
컬럼에는 인덱스의 페이지 수를 표시합니다.n_leaf_pages
:stat_name
=n_leaf_pages
이면stat_value
컬럼은 인덱스의 리프 페이지 수가 표시됩니다.n_diff_pfx
:NN
stat_name
=n_diff_pfx01
이면stat_value
컬럼에는 인덱스의 첫 번째 컬럼의 고유 값의 개수가 표시됩니다.stat_name
=n_diff_pfx02
이면stat_value
컬럼에는 인덱스의 처음 두 컬럼의 고유 값의 개수가 표시됩니다. 다음도 마찬가지입니다. 또한stat_name
=n_diff_pfx
이면NN
stat_description
열은 계산 된 인덱스 컬럼의 쉼표로 구분 된 목록이 표시됩니다.
중요도 데이터를 제공하는 n_diff_pfx
의 통계를 자세히 설명하기 위해 NN
t1
테이블의 예를 생각해 보겠습니다. 다음과 같이 t1
테이블은 기본 인덱스 (컬럼 a
, b
) 보조 인덱스 (컬럼 c
, d
) 및 고유 인덱스 (컬럼 e
, f
)에서 생성됩니다.
CREATE TABLE t1 ( a INT, b INT, c INT, d INT, e INT, f INT, PRIMARY KEY (a, b), KEY i1 (c, d), UNIQUE KEY i2uniq (e, f) ) ENGINE = INNODB;
5 행의 샘플 데이터를 삽입 한 후 테이블은 다음과 같이됩니다.
mysql> SELECT * FROM t1; +---+---+------+------+------+------+ | a | b | c | d | e | f | +---+---+------+------+------+------+ | 1 | 1 | 10 | 11 | 100 | 101 | | 1 | 2 | 10 | 11 | 200 | 102 | | 1 | 3 | 10 | 11 | 100 | 103 | | 1 | 4 | 10 | 12 | 200 | 104 | | 1 | 5 | 10 | 12 | 100 | 105 | +---+---+------+------+------+------+ 5 rows in set (0.00 sec)
stat_name LIKE 'n_diff%'
인 index_name
, stat_name
, stat_value
및 stat_description
를 쿼리하면 다음 결과 집합이 반환됩니다.
mysql> SELECT index_name, stat_name, stat_value, stat_description -> FROM mysql.innodb_index_stats -> WHERE table_name like 't1' AND stat_name LIKE 'n_diff%'; +------------+--------------+------------+------------------+ | index_name | stat_name | stat_value | stat_description | +------------+--------------+------------+------------------+ | PRIMARY | n_diff_pfx01 | 1 | a | | PRIMARY | n_diff_pfx02 | 5 | a,b | | i1 | n_diff_pfx01 | 1 | c | | i1 | n_diff_pfx02 | 2 | c,d | | i1 | n_diff_pfx03 | 2 | c,d,a | | i1 | n_diff_pfx04 | 5 | c,d,a,b | | i2uniq | n_diff_pfx01 | 2 | e | | i2uniq | n_diff_pfx02 | 5 | e,f | +------------+--------------+------------+------------------+ 8 rows in set (0.00 sec)
PRIMARY
인덱스의 경우 두 n_diff%
줄 수 있습니다. 행은 인덱스의 컬럼 수와 동일합니다.
고유하지 않은 인덱스의 경우, InnoDB
에 의해 기본 키의 컬럼이 추가됩니다.
index_name
=PRIMARY
및stat_name
=n_diff_pfx01
이면stat_value
은1
입니다. 이것은 인덱스의 첫 번째 컬럼 (컬럼a
)에 고유 값이 1 개 존재하는 것을 보여줍니다. 컬럼a
의 고유 값의 개수는 테이블t1
의 컬럼a
의 데이터를 표시하여 확인됩니다. 여기에는 고유 값이 1 개 존재합니다 (1
). 계산 된 열 (a
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.index_name
=PRIMARY
및stat_name
=n_diff_pfx02
이면stat_value
은5
입니다. 이것은 인덱스의 두 개의 열 (a,b
)에 고유 한 값이 5 개 존재하는 것을 보여줍니다. 컬럼a
와b
의 고유 값의 개수는 테이블t1
의 컬럼a
와b
의 데이터를 표시하여 확인됩니다. 여기에는 고유의 값이 5 개 존재합니다 : (1,1
), (1,2
), (1,3
), (1,4
) 및 (1,5
). 계산 된 열 (a,b
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.
보조 인덱스 ( i1
)의 경우 4 개의 n_diff%
줄 수 있습니다. 보조 인덱스로 정의되는 열은 2 가지 ( c,d
) 밖에 없지만 보조 인덱스 n_diff%
행은 4 가지가 있습니다. 이것은 고유하지 않은 인덱스는 모든 InnoDB
접미사에 의해 기본 키가 추가되기 때문입니다. 그 결과, 보조 인덱스 컬럼 ( c,d
)와 프라이 머리 키 컬럼 ( a,b
)를 모두 반영하여 2 개가 아닌 4 개의 n_diff%
줄 수 있습니다.
index_name
=i1
및stat_name
=n_diff_pfx01
이면stat_value
은1
입니다. 이것은 인덱스의 첫 번째 컬럼 (컬럼c
) 내에 고유 값이 1 개 존재하는 것을 보여줍니다. 컬럼c
의 고유 값의 개수는 테이블t1
의 컬럼c
의 데이터를 표시하여 확인됩니다. 여기에는 고유 값이 1 개 존재합니다 : (10
). 계산 된 열 (c
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.index_name
=i1
및stat_name
=n_diff_pfx02
이면stat_value
는2
입니다. 이것은 인덱스의 처음 두 컬럼 (c,d
)에 특정 값이 2 개 존재하는 것을 보여줍니다. 컬럼c
와d
의 고유 값의 개수는 테이블t1
의 컬럼c
와d
의 데이터를 표시하여 확인됩니다. 여기에는 고유의 값이 2 개 존재합니다 : (10,11
) 및 (10,12
). 계산 된 열 (c,d
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.index_name
=i1
및stat_name
=n_diff_pfx03
이면stat_value
는2
입니다. 이것은 인덱스의 처음 세 컬럼 (c,d,a
)에 특정 값이 2 개 존재하는 것을 보여줍니다. 컬럼c
,d
및a
의 고유 값의 개수는 테이블t1
의 컬럼c
,d
및a
의 데이터를 표시하여 확인됩니다. 여기에는 고유의 값이 2 개 존재합니다 : (10,11,1
) 및 (10,12,1
). 계산 된 열 (c,d,a
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.index_name
=i1
및stat_name
=n_diff_pfx04
이면stat_value
은5
입니다. 이것은 인덱스의 4 개의 컬럼 (c,d,a,b
)에 고유 한 값이 5 개 존재하는 것을 보여줍니다. 컬럼c
,d
,a
및b
의 고유 값의 개수는 테이블t1
의 컬럼c
,d
,a
및b
의 데이터를 표시하여 확인됩니다. 여기에는 고유의 값이 5 개 존재합니다 : (10,11,1,1
) (10,11,1,2
) (10,11,1,3
) (10,12,1,4
) 및 (10,12,1,5
). 계산 된 열 (c,d,a,b
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.
고유 인덱스 ( i2uniq
)의 경우는 2 개의 n_diff%
줄 수 있습니다.
index_name
=i2uniq
및stat_name
=n_diff_pfx01
이면stat_value
는2
입니다. 이것은 인덱스의 첫 번째 컬럼 (컬럼e
)에 고유의 값이 2 개 존재하는 것을 보여줍니다. 컬럼e
의 고유 값의 개수는 테이블t1
의 컬럼e
데이터를 표시하여 확인됩니다. 여기에는 고유의 값이 2 개 존재합니다 : (100
) 및 (200
) 계산 된 컬럼 (e
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.index_name
=i2uniq
및stat_name
=n_diff_pfx02
이면stat_value
은5
입니다. 이것은 인덱스의 두 컬럼 (e,f
)에 고유 한 값이 5 개 존재하는 것을 보여줍니다. 컬럼e
와f
의 고유 값의 개수는 테이블t1
의 컬럼e
와f
의 데이터를 표시하여 확인됩니다. 여기에는 고유의 값이 5 개 존재합니다 : (100,101
) (200,102
) (100,103
) (200,104
) 및 (100,105
). 계산 된 컬럼 (e,f
)는 결과 집합의stat_description
컬럼에 표시되어 있습니다.
14.13.16.1.4 innodb_index_stats 테이블을 사용한 인덱스 크기의 취득
테이블, 파티션 또는 서브 파티션 인덱스의 크기는 innodb_index_stats
테이블을 사용하여 얻을 수 있습니다. 다음 예에서는 테이블 t1
의 인덱스 크기를 검색합니다. 테이블 t1
의 정의 및 대응하는 인덱스 통계 내용은 섹션 14.13.16.1.3 "InnoDB 영구 통계 테이블의 예" 를 참조하십시오.
mysql> SELECT SUM(stat_value) pages, index_name, -> SUM(stat_value)*@@innodb_page_size size -> FROM mysql.innodb_index_stats WHERE table_name='t1' -> AND stat_name = 'size' GROUP BY index_name; +-------+------------+-------+ | pages | index_name | size | +-------+------------+-------+ | 1 | PRIMARY | 16384 | | 1 | i1 | 16384 | | 1 | i2uniq | 16384 | +-------+------------+-------+ 3 rows in set (0.00 sec)
파티션 또는 서브 파티션의 경우 변경된 WHERE
절을 포함 같은 쿼리를 사용하여 인덱스 크기를 얻을 수 있습니다. 예를 들어, 다음 쿼리는 테이블 t1
의 파티션 인덱스 크기를 가져옵니다.
mysql> SELECT SUM(stat_value) pages, index_name, -> SUM(stat_value)*@@innodb_page_size size -> FROM mysql.innodb_index_stats WHERE table_name like 't1#P%' -> AND stat_name = 'size' GROUP BY index_name;