일반적으로 '인덱스'라고 하면 이는 테이블에 사용자가 생성해돈 B-Tree 인덱스를 의미한다.
인덱스가 사용하는 알고리즘이 B-Tree는 아니더라도, 사용자가 직접 테이블에 생성해둔 인덱스가 우리가 일반적으로 알고 있는 인덱스일 것이다.
하지만 여기서 언급하는 '어댑티브 해시 인덱스'는 사용자가 수동으로 생성하는 인덱스가 아니라 InnoDB 스토리지 엔진에서 사용자가 자주 요청하는
데이터에 대해 자동으로 생성하는 인덱스이며, 사용자는 innodb_adptive_hash_index 시스템 변수를 이용해서
어댑티브 해시 인덱스 기능을 활성화하거나 비활성화 할 수 있다.
-> innodb_adptive_hash_index 시스템 변수를 통해서 옵티마이져가 어댑티브 해시인덱스를 사용할지 말지
사용자가 on/off를 결정한다.
B-Tree 인덱스에서 특정 값을 찾는 과정은 매우 빠르게 처리된다고 많은 사람이 생각한다. 하지만 결국 빠르냐 느리냐의 기준은 상대적인 것이며,
데이터베이스 서버가 얼마나 많은 일을 하느냐에 따라 B-tree 인덱스에서 값을 찾는 과정이 느려질 수도 있고 빨라질 수도 있다.
B-Tree 인덱스에서 특징값을 찾기 위해서는 B-Tree의 루트 노드를 거쳐서 브랜치 노드, 그리고 최종적으로 리프 노드까지 찾아가야 원하는 레코드를 읽을 수 있다.
적당한 사양의 컴퓨터에서 이런 작업을 동시에 몇 개 실행한다고 해서 성능 저하가 보이지는 않을 것이다.
하지만 이런 작업을 동시에 몇천 개의 스레드로 실행하면 컴퓨터의 CPU는 엄청난 프로세스 스케줄링을 하게 되고 자연히 쿼리의 성능은 떨어진다.
adaptive hash index는 이러한 B-Tree 검색 시간을 줄여주기 위해 도입된 기능이다.
InnoDB 스토리지 엔진은 자주 읽히는 데이터 페이지의 키 값을 이용해 해시 인덱스를 만들고, 필요할 때마다 어댑티브 해시 인덱스를 검색해서 레코드가
저장된 데이터 페이지를 즉시 찾아갈 수 있다.
B-Tree를 루트노드부터 리프 노드까지 찾아가는 비용이 없어지고 그만큼 CPU는 적은 일을 하지만 쿼리의 성능은 빨라진다.
그와 동시에 컴퓨터는 더 많은 쿼리를 동시에 처리할 수 있게 된다.
해시 인덱스는 '인덱스 키값'과 해당 인덱스 키 값이 저장된 '데이터 페이지 주소'의 쌍으로 관리되는데,
인덱스 키 값은 'B-Tree 인덱스의 고유번호(id)와 B-Tree 인덱스의 실제 키 값' 조합으로 생성된다.
어뎁티브 해시 인덱스의 키 값에 B-Tree 인덱스의 고유번호가 포함되는 이유는 InnoDB 스토리지 엔진에서
어댑티브 해시 인덱스는 하나만 존재(물론 파티션되는 기능이 있지만)하기 때문이다.
즉, 모든 B-Tree 인덱스에 대한 어댑티브 해시인덱스가 하나의 해시 인덱스에 저장되며, 특정 키값이 어느 인덱스에
속한 것인지도 구분해야 하기 때문이다.
그리고 '데이터 페이지 주소'는 실제 키 값이 저장된 데이터 페이지의 메모리 주소를 가지는데, 이는 InnoDB 버퍼풀에 로딩된 페이지의 주소를 의미한다.
그래서 어댑티브 해시인덱스는 버퍼 풀에 올려진 데이터 페이지에 대해서만 관리하고, 버퍼 풀에서 해당 데이터 페이지가 없어지면
어댑티브 해시 인덱스에서도 해당 페이지의 정보는 사라진다.
-> 해시인덱스 구조 = B-Tree (고유 id + key value) + 데이터 페이지의 메모리 주소
CPU 사용률 변화
초당 쿼리 처리수 변화
예전 버전까지는 어댑티브 해시 인덱스는 하나의 메모리 객체인 이유로 어댑티브 해시 인덱스의 경합이 상당히 심했다.
그래서 Mysql 8.0부터는 내부 잠금(세마포어) 경함을 줄이기 위해 어댑티브 해시 인덱스의 파티션 기능을 제공한다.
innodb_apaptive_hash_index_parts 시스템 변수를 이용해 파티션 개수를 변경할 수 있는데,
기본값은 8개이며 만약 어댑티브 해시 인덱스가 성능에 많은 도움이 된다면 파티션 개수를 더 많이 설정하는 것도
어댑티브 해시 인덱스의 내부 잠금 경합을 줄이는데 많은 도움이 될 것이다.
여기까지만 보며 InnoDB 스토리지 엔진의 어댑티브 해시 인덱스는 팔방미인처럼 보이지만, 실제 어댑티브 해시 인덱스를 의도적으로 비활성화하는 경우도 많다.
1. 성능향상에 크게 도움이 되지 않는 경우
1) 디스크 읽기가 많은 경우
2) 특정 패턴의 쿼리가 많은 경우(Join이나 Like 패턴 검색)
3) 매우 큰 데이터를 가진 테이블의 레코드를 폭넓게 읽는 경우
2. 성능향상에 도움이 되는 경우
1) 디스크의 데이터가 InnoDB 버퍼 풀 크기와 비슷한 경우(디스크 읽기가 많지 않은 경우)
2) 동등 조건 검색(동등 비교와 In 연산자)이 많은 경우
3) 쿼리가 데이터 중에서 일부 데이터에만 집중되는 경우
하지만 단순히 어댑티브 해시 인덱스가 도움이 될지 아닐지를 판단하기는 쉽지않다.
한가지 확실한 것은 어댑티브 해시 인덱스는 데이터 페이지를 메모리(버퍼 풀) 내에서 접근하는 것을 더 빠르게 만드는 기능이기 때문에
데이터 페이지를 디스크에서 읽어오는 경우가 빈번한 데이터베이스 서버에서는 아무런 도움이 되지 않는다는 점이다.
하나 더 기억해야 할 것은 어댑티브 해시 인덱스는 '공짜 점심'이 아니라는 것이다.
어댑티브 해시인덱스 또한 저장 공간인 메모리를 사용하며, 때로는 상당히 큰 메모리 공간을 사용할 수도 있다.
어댑티브 해시 인덱스 또한 데이터 페이지의 인덱스 키가 해시 인덱스로 만들어져야 하고 불필요한 경우 제거되어야 하며,
어댑티브 해시 인덱스가 활성화되면 InnoDB 스토리지 엔진의 그 키 값이 해시 인덱스에 있든 없든 검색해봐야 한다는 것이다.
즉, 해시인덱스 효율이 없는 경우에도 InnoDB는 계속 해시 인덱스를 사용할 것이다.
어댑티브 해시 인덱스는 테이블의 삭제 작업에도 많은 영향을 미친다.
어떤 테이블의 인덱스가 어댑티브 해시 인덱스에 적재되어 있다고 가정해보자.
이때 이 테이블을 삭제(Drop)하거나 변경(Alter)하려고 하면 InnoDB 스토리지 엔진은 이 테이블이 가진 모든 데이터 페이지의 내용을 어댑티브 해시 인덱스에서 제거해야한다.
이로 인해 테이블이 삭제되거나 스키마가 변경되는 동안 상당히 많은 CPU 자원을 사용하고,
그만큼 데이터베이스 서버의 처러 성능은 느려진다. 이후 버전에서는 개선되겠지만
Mysql 8.0.20 버전에서는 다음과 같은 Instant 알고리즘의 Online DDL도 상당한 시간이 소요되기도 한다.
mysql> alter table employees ADD address varchar(200), ALGORITHM=instant;
어댑티브 해시 인덱스의 도움을 많이 받을수록 테이블 삭제 또는 변경 작업(Online DDL 포함)은
더 치명적인 작업이 되는 것이다.
이는 어댑티브 해시 인덱스의 사용에 있어서 매우 중요한 부분이므로 꼭 기억해두자.
#어댑티브 해시 인덱스 사용유무 확인
#어댑티브 해시인덱스 사용유무 확인
mysql> show global variables like 'innodb_adaptive_hash%';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| innodb_adaptive_hash_index | ON |
| innodb_adaptive_hash_index_parts | 8 |
+----------------------------------+-------+
2 rows in set (0.00 sec)
show engine innodb status\G;
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 11577, seg size 11579, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 4730347, node heap has 2 buffer(s)
Hash table size 4730347, node heap has 0 buffer(s)
Hash table size 4730347, node heap has 653 buffer(s)
Hash table size 4730347, node heap has 4 buffer(s)
Hash table size 4730347, node heap has 4 buffer(s)
Hash table size 4730347, node heap has 2 buffer(s)
Hash table size 4730347, node heap has 2 buffer(s)
Hash table size 4730347, node heap has 2 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
#어댑티브 해시인덱스의 메모리사용량 확인
select EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED
from performance_schema.memory_summary_global_by_event_name
where EVENT_NAME='memory/innodb/apaptive hash index';
#결론
mysql 8.0을 검토하면서 online ddl의 instant 알고리즘에 대한 기대가 많았는데
어댑티브 해시 인덱스를 쓰게 된다면 있으나마한 기능이 되버릴 수도 있겠다.
ONLINE DDL은 mysql 5.7에서도 서비스 DB에 반영시 부하여부를 테스트하고 여러가지 장애포인트를 확인하고
반영하는데 mysql 8.0으로 업그레이드시 어댑티브 해시인덱스를 ON 하게되면
더 많은 장애 포인트를 검토해봐야 한다는 점에서 적용이 망설여진다.
향후 mysql 8.1.x 버전에서 이 기능이 Hint 기능의 하나로 제공되어
특정 쿼리에서만 사용 가능하게 되고
query에 사용한 테이블 목록만 별도 관리하기만 한다면
그때는 adaptive hash index 사용을 긍정적으로 검토해봐도 좋을 거 같다.
그전까진 성능보단 안정성에 우선을..
#그래프 이미지 참조
https://gywn.net/2015/01/innodb-adaptive-hash-index/
'쇠똥굴리기(BOOK) > Real mysql 8.0' 카테고리의 다른 글
mysql 자동 데드락(deadlock) 감지기능 (0) | 2023.04.10 |
---|---|
트랜젝션 지원 메타데이터 (0) | 2023.04.07 |
SET PERSIST 이야기 (0) | 2023.03.27 |
Mysql 8.0 업그레이드 시 고려사항 (0) | 2023.03.24 |
mysql 서버 연결 방식 localhost / 127.0.0.1 차이 (0) | 2023.03.15 |