이 포스트는 innodb_ruby
0.8.8 버전 (2014/02/03)을 기준으로 작성되었습니다.
InnoDB 핵심을 이해하기 위한 여행 에서 innodb_ruby 프로젝트의 라이브러리와 커맨드 라인 툴을 소개했습니다. 그리고 innodb_ruby 빠르게 훑어보기 에서 innodb_ruby
의 커맨드 라인 도구에 대한 간단한 데모를 살펴보았습니다.
그리고 지난 포스트인 InnoDB Space 파일의 페이지 관리 방법에선 InnoDB의 extent, 파일 segment 및 free space 관리 구조에 대해 알아보았습니다. 이제 innodb_space
를 사용하여 실제 테이블에서 이 구조들을 확인해보겠습니다.
InnoDB 페이지 관리 구조체의 “최소” 상태를 보여주기 위해, 빈 테이블 (스키마는 중요하지 않음)을 만들었습니다. space-page-type-regions
모드는 동일한 페이지 타입을 갖는 연속된 영역을 요약해 보여줍니다:
$ innodb_space -f test/e.ibd space-page-type-regions
start end count type
0 0 1 FSP_HDR
1 1 1 IBUF_BITMAP
2 2 1 INODE
3 3 1 INDEX
4 5 2 FREE (ALLOCATED)
테이블은 IBD space 파일의 표준 페이지인 FSP_HDR, IBUF_BITMAP, INODE 및 (빈) index의 root에 대한 INDEX 페이지를 가집니다. 미사용 중인 두 개의 FREE (ALLOCATED) 페이지도 있습니다.
space-lists
모드는 space의 extent descriptor 및 inode 리스트를 확인하는 데 사용할 수 있습니다:
$ innodb_space -f test/e.ibd space-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
free_frag 1 0 158 0 158
full_frag 0 0 0 0 0
full_inodes 0 0 0 0 0
free_inodes 1 2 38 2
free_frag extent descriptor 리스트에만 항목이 있으며, 거기엔 하나의 extent만 존재합니다. free_inodes 리스트에는 위에서 확인한 것처럼 하나의 INODE 페이지가 있습니다.
free_frag 리스트의 내용은 space-list-iterate
모드로 확인할 수 있으며, 하나의 extent 리스트 안의 모든 extent를 통틀어 페이지 사용률을 그래피컬하게 출력합니다. (”#” 은 페이지가 사용 중이라는 걸, ”.”은 페이지가 미사용 중이라는 걸 의미합니다):
$ innodb_space -f test/e.ibd -L free_frag space-list-iterate
start_page page_used_bitmap
0 ####............................................................
Space 내 모든 index에 대한 파일 segment는 space-indexes
모드로 확인할 수 있습니다:
$ innodb_space -f test/e.ibd space-indexes
id root fseg used allocated fill_factor
16 3 internal 1 1 100.00%
16 3 leaf 0 0 0.00%
internal 파일 segment만 allocated 페이지를 가지며, 현재 하나의 페이지만 할당된 상태입니다. index-fseg-internal-lists
모드는 internal 파일 segment의 extent 리스트를 요약해 보여줍니다:
$ innodb_space -f test/e.ibd -p 3 index-fseg-internal-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
not_full 0 0 0 0 0
full 0 0 0 0
이 빈 테이블에 full extents가 할당되지 않았으므로 세 개의 리스트가 모두 비어 있습니다. 사용된 페이지 하나는 어디로 갔을까요? 그 페이지는 “fragment” 페이지이며 index-fseg-internal-frag-pages
모드로 확인할 수 있습니다:
$ innodb_space -f test/e.ibd -p 3 index-fseg-internal-frag-pages
page index level data free records
3 16 0 0 16252 0
여기까지가 빈 bookkeeping 구조와 하나의 INDEX 페이지를 갖는 최소한의 상태입니다. 이제 실제 데이터가 포함된 테이블을 살펴보겠습니다.
innodb_ruby 빠르게 훑어보기 에서 백만 개의 행이 있는 테이블을 만들었습니다. 여기서도 같은 테이블을 사용하겠습니다.
총 2,165 개의 페이지가 있으며, 일반적인 테이블은 주로 INDEX 타입의 페이지를 갖습니다:
$ innodb_space -f test/t.ibd space-page-type-regions
start end count type
3 37 35 INDEX
38 63 26 FREE (ALLOCATED)
64 2188 2125 INDEX
2189 2239 51 FREE (ALLOCATED)
2240 2240 1 INDEX
2241 2303 63 FREE (ALLOCATED)
2304 2304 1 INDEX
2305 2367 63 FREE (ALLOCATED)
2368 2368 1 INDEX
2369 2431 63 FREE (ALLOCATED)
2432 2432 1 INDEX
2433 2495 63 FREE (ALLOCATED)
2496 2496 1 INDEX
2497 2687 191 FREE (ALLOCATED)
INDEX 페이지 블록 사이에 있는 FREE (ALLOCATED) 페이지들은 서로 약간 다릅니다. InnoDB는 빈 페이지를 순차적으로 사용하는 것을 보장하지 않으며, 대량 데이터 로드에 대한 많은 최적화 기법들로 인해 페이지가 순서대로 사용되지 않습니다. (페이지 splitting 및 최적화 기법에 대한 자세한 내용은 추후 다른 포스트에서 확인하실 수 있습니다.)
Space의 리스트를 보면, free_frag 상태인 일반적인 extent 뿐만 아니라 free 상태인 extent도 몇 개 있습니다:
$ innodb_space -f test/t.ibd space-lists
name length f_page f_offset l_page l_offset
free 2 0 1758 0 1798
free_frag 1 0 158 0 158
full_frag 0 0 0 0 0
full_inodes 0 0 0 0 0
free_inodes 1 2 38 2
free extent descriptor 리스트의 페이지는 예상대로 모두 비어있습니다:
$ innodb_space -f test/t.ibd -L free space-list-iterate
2560 ................................................................
2624 ................................................................
free_frag extent descriptor 리스트에는 다음과 같이 여러 “fragment” 페이지들도 사용됩니다:
$ innodb_space -f test/t.ibd -L free_frag space-list-iterate
start_page page_used_bitmap
0 ######################################..........................
예상대로, index 파일 segment는 사용된 페이지의 대부분이 leaf 파일 segment에 할당되었음을 보여줍니다 (B+tree에서 2,137개의 leaf 페이지를 관리하기 위한 leaf가 아닌 internal 페이지가 3개뿐 임):
$ innodb_space -f test/t.ibd space-indexes
id root fseg used allocated fill_factor
15 3 internal 3 3 100.00%
15 3 leaf 2162 2528 85.52%
Leaf index 파일 segment에는 실제 사용하는 것보다 많은 페이지가 할당되어 85.52%의 fill factor를 보여주는 것도 확인할 수 있습니다. InnoDB의 “segment fill factor”는 MySQL에서 87.5%로 고정되어 있지만, Facebook에서 MySQL Bug 64673을 제출한 덕분에 Twitter MySQL에서 설정할 수 있습니다.
internal index 파일 segment에는 3개의 페이지만 있으므로, 파일 segment 리스트가 모두 비어 있습니다:
$ innodb_space -f test/t.ibd -p 3 index-fseg-internal-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
not_full 0 0 0 0 0
full 0 0 0 0 0
사용된 세 개의 페이지는 fragment 페이지로 할당됩니다:
$ innodb_space -f test/t.ibd -p 3 index-fseg-internal-frag-pages
page index level data free records
3 15 2 26 16226 2
36 15 1 14521 1401 1117
37 15 1 13585 2341 1045
Leaf index 파일 segment 리스트는 32개의 full extent 및 6개의 not full extent를 갖습니다:
$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
not_full 6 0 1518 0 1718
full 33 0 198 0 1478
또한 leaf index 파일 segment는 가능한 모든 32개의 fragment 페이지를 할당했습니다:
$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-frag-pages
page index level data free records
4 15 0 9812 6286 446
5 15 0 15158 860 689
6 15 0 10912 5170 496
7 15 0 10670 5412 485
8 15 0 12980 3066 590
9 15 0 11264 4808 512
10 15 0 4488 11690 204
11 15 0 9680 6418 440
12 15 0 9306 6800 423
13 15 0 9658 6434 439
14 15 0 10032 6062 456
15 15 0 9988 6108 454
16 15 0 9570 6530 435
17 15 0 9130 6978 415
18 15 0 8844 7266 402
19 15 0 11770 4300 535
20 15 0 9020 7092 410
21 15 0 8646 7462 393
22 15 0 9746 6354 443
23 15 0 11066 5014 503
24 15 0 8910 7204 405
25 15 0 11748 4322 534
26 15 0 10978 5094 499
27 15 0 11132 4940 506
28 15 0 9350 6750 425
29 15 0 13508 2526 614
30 15 0 14938 1082 679
31 15 0 14520 1506 660
32 15 0 9086 7016 413
33 15 0 9724 6368 442
34 15 0 10978 5102 499
35 15 0 9504 6592 432
예상했던 대로, full extent는 full 상태입니다:
$ innodb_space -f test/t.ibd -p 3 -L full index-fseg-leaf-list-iterate
start_page page_used_bitmap
64 ################################################################
128 ################################################################
192 ################################################################
256 ################################################################
320 ################################################################
384 ################################################################
448 ################################################################
512 ################################################################
576 ################################################################
640 ################################################################
704 ################################################################
768 ################################################################
832 ################################################################
896 ################################################################
960 ################################################################
1024 ################################################################
1088 ################################################################
1152 ################################################################
1216 ################################################################
1280 ################################################################
1344 ################################################################
1408 ################################################################
1472 ################################################################
1536 ################################################################
1600 ################################################################
1664 ################################################################
1728 ################################################################
1792 ################################################################
1856 ################################################################
1920 ################################################################
1984 ################################################################
2048 ################################################################
2112 #####################################################
not_full extent는 예상대로 부분적으로 채워진 상태입니다:
$ innodb_space -f test/t.ibd -p 3 -L not_full index-fseg-leaf-list-iterate
start_page page_used_bitmap
2176 #############...................................................
2240 #...............................................................
2304 #...............................................................
2368 #...............................................................
2432 #...............................................................
2496 #...............................................................
InnoDB의 페이지 split optimization의 결과를 여기에서 확인할 수 있습니다: 데이터를 디스크에 순차적으로 배치하기 위해 첫 번째 페이지를 여러 번 (페이지 번호 “hinting”?) 꺼냈습니다. 이에 대한 심층적인 내용은 추후에 다룰 예정입니다.