2014-02-26 2 views
4

3 개의 열 (int, mediumint, int)을 가진 거대한 InnoDB 테이블이 있습니다. innodb_file_per_table 설정에 있으며 첫 번째 두 개의 열테이블이 커지면서 InnoDB 행 크기가 기하 급수적으로 변경됩니까?

테이블 스키마가의 PRIMARY KEY이 :

CREATE TABLE `big_table` (
    `user_id` int(10) unsigned NOT NULL, 
    `another_id` mediumint(8) unsigned NOT NULL, 
    `timestamp` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`user_id`,`another_id `) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

MySQL 버젼은

5.6.16는 현재 내가 150 다중 삽입하고있다 초당 행. 삭제 및 업데이트가 없습니다. 중요한 롤백이나 다른 트랜잭션 중단이 없으므로 낭비되는 공간 사용이 발생합니다.

MySQL은 해당 테이블에서 75,7GB의 계산 된 크기를 보여줍니다. 디스크

있는 .ibd 크기 : 136,679,784,448 바이트 (127.29 GIB)

카운트 된 행 : 2901937966 (행당 47.10 바이트)

이후 MySQL은 또한 75.7 GB의 계산 된 크기를 도시 이일 그 테이블에. 디스크

있는 .ibd 크기 : 144,263,086,080 바이트 (135.35 GIB)

카운트 된 행 : 테이블의 SHOW TABLE STATUS 실행 2,921,284,863 (행당 49.38 바이트)

보여준다 :

Engine | Version | Row_format | Rows  | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Collation 
InnoDB |  10 | Compact | 2645215723 |    30 | 81287708672 |    0 |   0 | 6291456 | utf8_unicode_ci 

내 질문은 다음과 같습니다.

  • 왜 디스크 사용량이 행 수에 비해 불균형하게 증가합니까?
  • Avg_row_lengthData_length은 완전히입니까?

누군가 나를 도울 수 있기를 바랍니다. 디스크 사용량이 더 이상 늘어나지 않기를 바랍니다. 나는 테이블이 작을수록 그것을 알지 못했다.

+0

삽입 할 때'user_id' 값은 항상 이전 값보다 크거나 'user_id' 값이 때로 더 높거나 때로 낮습니다. –

+0

하위 및 상위 user_id에 따라 다릅니다. 하지만 나는 한 번에 하나의 user_id 만 다중 삽입하고 있습니다 (예 : user_id 500의 경우 100 행, user_id 123의 경우 20 행, user_id 1000의 경우 500 행 ..) – Stefan

답변

6

테이블이 현재 29 억 개의 행으로 유기적으로 커지지 않았으며 최근에이 데이터를로드했거나 테이블을 다시 구성한 것으로 가정합니다 (예 : ALTER TABLE 또는 OPTIMIZE TABLE 사용). . 그래서 그것은 디스크에 아주 잘 포장되어 있습니다. 로 배치되어있다 (다행히 매우 간단하고 직관적이다) 테이블 스키마, 각 행 (레코드)를 기반으로

은 다음과 같습니다

(Header)    5 bytes 
`user_id`    4 bytes 
`another_id`   3 bytes 
(Transaction ID)  6 bytes 
(Rollback Pointer) 7 bytes 
`timestamp`   4 bytes 
============================= 
Total    29 bytes 
이노 실제로 약보다 더에 페이지를 기입하지 않습니다

~ 15/16 full (보통 1/2 full보다 작지 않음). 다양한 장소에서 여분의 모든 오버 헤드가 있으므로 레코드의 전체로드 비용은 인덱스의 리프 페이지에서 행당 최소 32 바이트와 최대 60 바이트 정도가됩니다.

가져 오기를 통해 또는 ALTER TABLE 또는 OPTIMIZE TABLE 통해 대량로드 데이터를 매우 효율적으로 디스크에 데이터를 포장하는 이노 수 PRIMARY KEY, 순서로 데이터가 정상적으로로드됩니다 (그리고 인덱스 생성)합니다. 그런 다음 무작위 (또는 실질적으로 무작위) 순서로 데이터를 테이블에 계속 쓰는 경우 B + Tree 용어로 페이지를 절반으로 분할한다는 의미로 효율적으로 압축 된 인덱스 구조가 확장되어야합니다. 레코드가 이상적으로 압축 된 16 KiB 페이지를 가지고 있고 레코드가 평균 ~ 32 바이트를 소비하고 단일 행을 삽입하기 위해 절반으로 분할되면 1/2 빈 페이지 (~ 16 KiB 낭비)가 발생하고 새 행에는 "비용"16 KiB.

물론 사실이 아닙니다. 시간이 지남에 따라 인덱스 트리는 1/2 전체와 15/16 전체 페이지 사이에 자리를 잡을 것입니다. 다음 페이지는 동일한 페이지에서 발생해야하므로 충분한 공간을 이미 찾아야하므로 영원히 페이지를 분할하지 않습니다. 인서트를하기 위해 존재합니다.

처음에는 테이블에 데이터를 일괄로드 (따라서 효율적으로 압축) 한 다음 유기적으로 재배치하면 다소 혼란 스러울 수 있습니다. 초기에는 테이블이 미친 페이스로 성장하고있는 것처럼 보이지만 시간 경과에 따라 성장률을 추적하면 속도가 느려집니다.

내 블로그 게시물 , The physical structure of InnoDB index pagesB+Tree index structures in InnoDB에서 InnoDB 색인 및 레코드 레이아웃에 대한 자세한 내용을 볼 수 있습니다.

+0

감사합니다. 그게 정확히 내가 찾고 있던거야. 해시로 분할하는 것이 도움이된다고 생각하십니까? 한 번에 하나의 user_id에서 데이터를 선택하고 한 번에 하나의 user_id 만 삽입하려고합니다. – Stefan

+1

해시로 파티션을 지정하면이 경우에 도움이되지 않을 것입니다. 정확히 같은 증상을 나타내는 작은 테이블이 많이 있습니다. . 작은 테이블에서는 간접비가 더 나빠질 수 있기 때문에 상황이 더욱 악화 될 수 있습니다. – jeremycole

관련 문제