14.7.5 InnoDB 테이블에서의 압축 동작
이 섹션에서는 InnoDB 테이블의 압축 에 관한 일부의 내부 구현에 대해 자세히 설명합니다. 여기에 나온 정보는 성능을 조정하는 데 도움이 될 수 있지만, 압축 기본적인 사용을 이해 할 필요가 없습니다.
압축 알고리즘
일부 운영 체제에서는 파일 시스템 레벨에서 압축이 구현되어 있습니다. 일반적으로 파일은 다양한 크기의 블록으로 압축되는 고정 된 크기의 블록으로 분할되기 때문에 쉽게 단편화됩니다. 블록 내부에서 무언가가 변경 될 때마다 블록 전체가 재 압축 된 후 디스크에 기록됩니다. 이러한 특성을 사용하면 압축 방법이 업데이트가 많은 데이터베이스 시스템에서의 사용에는 적합하지 않습니다.
MySQL은 LZ77 압축 알고리즘이 구현되어있는 유명한 zlib 라이브러리 의 지원을 받아 압축이 구현되어 있습니다. 이 압축 알고리즘은 충분히 발달하고 견고한이며, CPU 사용량과 데이터 크기 감소의 두 측면에서 효율적입니다. 이 알고리즘은 '손실없이'이기 때문에 항상 원래의 비 압축 데이터를 압축 형식에서 재구성 할 수 있습니다. LZ77 압축은 압축 된 데이터에서 반복되는 일련의 데이터를 찾을에서 작동합니다. 데이터의 값의 패턴에 따라 압축 효율이 결정되지만, 많은 경우, 일반적인 사용자 데이터는 50 % 이상 압축됩니다.
응용 프로그램에서 실행되는 압축 및 기타 일부 데이터베이스 관리 시스템의 압축 기능과는 달리, InnoDB의 압축 사용자 데이터와 인덱스에 모두 적용됩니다. 종종 인덱스가 데이터베이스 전체 크기의 40-50 % 이상을 차지할 가능성이 있기 때문에이 차이는 중요합니다. 데이터 세트의 압축이 제대로 작동하고있을 때는, InnoDB의 데이터 파일 ( .idb
파일)의 크기가 압축되지 않은 크기의 25 % - 50 %, 때로는 그보다 작습니다. 워크로드 에 따라이 같이 데이터베이스를 줄임으로써 CPU 사용률을 조금 증가시키는 것만으로 I / O를 줄이고 처리량을 늘릴 수 있습니다. innodb_compression_level
구성 옵션을 변경하면 압축 수준과 CPU 오버 헤드 사이의 균형을 조정할 수 있습니다.
InnoDB 데이터 저장 및 압축
InnoDB 테이블의 모든 사용자 데이터는 B 트리 인덱스 ( 클러스터 된 인덱스 )를 구성하고있는 페이지에 저장됩니다. 다른 일부 데이터베이스 시스템에서는이 유형의 인덱스는 "인덱스 구성 테이블"이라고합니다. 인덱스 노드의 각 행에는 (사용자가 지정한 또는 시스템에서 생성 된) 기본 키 값과 테이블의 다른 모든 열이 포함되어 있습니다.
InnoDB 테이블의 보조 인덱스 값 쌍 (인덱스 키와 클러스터 된 인덱스에서 행에 대한 포인터)를 포함한 B 트리이기도합니다. 실제로, 포인터는 테이블의 기본 키 값이며, 인덱스 키와 기본 키가 아닌 컬럼이 필요한 경우 클러스터 된 인덱스에 액세스하는 데 사용됩니다. 항상 보조 인덱스 레코드는 B 트리 페이지에 수용 될 필요가 있습니다.
다음 섹션에서 설명하도록 (클러스터형 인덱스와 보조 인덱스 모두) B 트리 노드의 압축은 긴 VARCHAR
, BLOB
또는 TEXT
컬럼을 저장하는 데 사용되는 오버 플로우 의 압축과 다르게 로 처리됩니다.
B 트리 페이지 압축
B 트리 페이지는 자주 업데이트되므로 특별한 처리가 필요합니다. B 트리 노드가 분할되는 횟수를 최소화하고 그 내용을 압축 해제 및 재 압축 할 필요성도 최소화하는 것이 중요합니다.
MySQL에서 사용되는 기술 중 하나에서는 일부 시스템 정보가 압축되지 않은 형식으로 B 트리 노드에 유지되기 때문에 특정 위치에서 쉽게 업데이트 할 수 있습니다. 예를 들어, 이것은 압축 작업없이 행에 삭제 표시 행을 삭제할 수 있습니다.
또한, MySQL은 인덱스 페이지가 변경된 때 불필요한 압축 해제 및 재 압축을 피하려고 시도합니다. 시스템의 각 B 트리 페이지에는 페이지에 변경 사항을 기록하기위한 비 압축 "변경 로그"가 개최됩니다. 작은 레코드 업데이트 및 삽입은 페이지 전체를 재 구축 할 필요없이이 변경 로그에 기록 될 수 있습니다.
변경 로그의 공간이 부족하면 InnoDB에 의해 페이지가 압축되지 않은 변경 사항이 적용되며 페이지가 다시 압축됩니다. 재 압축에 실패하면 ( 압축 실패 라는 상황), B 트리 노드가 분할되어 업데이트 또는 삽입에 성공하기까지 과정이 반복됩니다.
OLTP 애플리케이션 등으로 쓰기 집약적 워크로드에서의 빈번한 압축 실패를 방지하기 위해 MySQL에서는 페이지에 일부 빈 공간 (패딩)이 예약되어있는 경우가 있습니다. 이렇게하면 변경 로그가 더 빨리 채워지고 분할을 방지 할 수있는 충분한 공간이 아직있는 동안 페이지가 다시 압축됩니다. 각 페이지에 남아있는 패딩 공간의 크기는 시스템에서 페이지 분할의 빈도가 추적되는 것에 따라 변화합니다. 압축 테이블에 기록이 빈번하게 행해지는 고부하의 서버에서는 innodb_compression_failure_threshold_pct
및 innodb_compression_pad_pct_max
구성 옵션을 조정하면이 메커니즘을 미세 조정할 수 있습니다.
일반적으로 MySQL에서 InnoDB 테이블의 각 B 트리 페이지에 2 개 이상의 레코드를 수용 할 수 있습니다. 압축 테이블의 경우이 요건이 완화되었습니다. B 트리 노드의 리프 페이지는 (기본 키와 보조 인덱스이든) 하나의 레코드 만 수용 될 필요가 있지만, 그 레코드는 페이지마다 변경 로그 비 압축 형식으로 들어갈 필요가 있습니다. innodb_strict_mode
가 ON
의 경우 CREATE TABLE
또는 CREATE INDEX
를 실행하는 동안, MySQL에 의해 행의 최대 크기가 확인됩니다. 행이 들어 가지 않는 경우는 「ERROR HY000: Too big row」
라는 오류 메시지가 발행됩니다.
innodb_strict_mode
이 OFF 때 테이블을 작성한 경우 후속 INSERT
또는 UPDATE
문에서 압축 된 페이지 크기에 맞지 않는 인덱스 항목의 작성이 시도되면 해당 작업이 실패하고 「ERROR 42000: Row size too large」
라는 오류 메시지가 표시됩니다. (이 오류 메시지는 기록이 너무 오래 인덱스의 이름을 나타내는 것도 그 특정 인덱스 페이지에 인덱스 레코드 길이와 최대 레코드 크기를 나타내는 것은 아닙니다.)이 문제를 해결하려면 ALTER TABLE
를 사용하여 테이블을 재구성하고 더 큰 압축 된 페이지 크기 ( KEY_BLOCK_SIZE
)을 선택하고 모든 열 프리픽스의 인덱스를 줄이거 나 ROW_FORMAT=DYNAMIC
또는 ROW_FORMAT=COMPACT
를 사용하여 압축을 완전히 비활성화합니다.
BLOB, VARCHAR 및 TEXT 컬럼 압축
InnoDB 테이블에서는 기본 키의 일부가 아닌 BLOB
, VARCHAR
및 TEXT
컬럼이 개별적으로 할당 된 오버 플로우 페이지 에 저장 될 수 있습니다. 이러한 열은 오프 페이지 열 이라고합니다. 이 값은 오버 플로우 페이지의 단방향 목록에 저장됩니다.
ROW_FORMAT=DYNAMIC
또는 ROW_FORMAT=COMPRESSED
로 작성된 테이블은 컬럼의 길이와 전체 라인의 길이에 따라 BLOB
, TEXT
또는 VARCHAR
컬럼의 값이 완전히 해제 페이지에 저장되는 경우도 있습니다. 오프 페이지에 저장 될 컬럼에서는 클러스터 된 인덱스 레코드에 오버플 페이지에 20 바이트 포인터 만 열마다 하나씩 포함되어 있습니다. 열이 해제 페이지에 포함되는지 여부는 페이지 크기 및 행의 전체 크기에 따라 다릅니다. 행이 클러스터 된 인덱스 페이지에 완전히 들어 가지 못할 정도로 긴 경우에는 클러스터 된 인덱스 페이지에 행이 될 때까지, MySQL에 의해 오프 페이지 저장에 맞는 최대의 컬럼이 선택됩니다. 위의 주에서 나타낸 바와 같이 행 자체가 압축 된 페이지에 맞지 않으면 오류가 발생합니다.
ROW_FORMAT=DYNAMIC
또는 ROW_FORMAT=COMPRESSED
로 작성된 테이블은 40 바이트 이하의 TEXT
와 BLOB
컬럼은 항상 인라인에 저장됩니다.
이전 버전의 MySQL에서 작성된 테이블은 ROW_FORMAT=REDUNDANT
과 ROW_FORMAT=COMPACT
만 지원되는 Antelope 파일 형식이 사용됩니다. MySQL에서는 이러한 형식으로 클러스터 된 인덱스 레코드에 BLOB
, VARCHAR
및 TEXT
컬럼의 최초의 768 바이트가 기본 키와 함께 저장됩니다. 768 바이트의 프리픽스의 뒤에 나머지 컬럼 값을 포함 오버플 페이지에 20 바이트의 포인터가 계속됩니다.
테이블 형식이 COMPRESSED
인 경우는 오버 플로우 페이지에 기록되는 모든 데이터가 "있는 그대로"압축됩니다. 즉, MySQL에서 데이터 항목 전체에 zlib 압축 알고리즘이 적용됩니다. 압축 된 오버 플로우 페이지에는 데이터 이외에서는 특히 페이지 체크섬을 구성하는 비 압축 헤더와 트레일러 및 다음 오버 플로우 페이지에 대한 링크가 포함되어 있습니다. 따라서 텍스트 데이터를 사용하는 경우에 많이 볼 수 있도록 데이터의 압축 가능성이 높은 경우는 긴 BLOB
, TEXT
또는 VARCHAR
컬럼에서 매우 상당한 스토리지의 절약이 실현됩니다. 일반적으로 JPEG
등의 이미지 데이터는 이미 압축되어 있기 때문에 압축 테이블에 저장되는 장점이 거의 제공하지 않습니다. 공간 절약이 거의 없거나 전혀없는 경우는 이중 압축하여 CPU 사이클이 낭비 될 가능성이 있습니다.
오버 플로우 페이지의 크기는 다른 페이지와 동일합니다. 컬럼의 총 길이가 8K 바이트 뿐이다 경우에도 오프 페이지에 포함 된 10 개의 컬럼을 포함하는 행에서 10 개의 오버 플로우 페이지가 점유됩니다. 비 압축 테이블은 10 개의 비 압축 오버 플로우 페이지에서 160K 바이트를 차지합니다. 페이지 크기가 8K 압축 테이블은 80K 바이트 만 차지합니다. 따라서 긴 컬럼 값을 포함하는 테이블에서는 압축 테이블 형식을 사용하면 효율성이 높아질 수 많이 있습니다.
16K 압축 된 페이지 크기를 사용하면 대부분의 경우 이러한 데이터를 효율적으로 압축되는 것으로, 필요한 오버 플로우 페이지가
줄어들 가능성이 있기 때문에 B 트리 노드 자체의 페이지 수는 비 압축 형식의 경우와 동일하다하더라도, BLOB
, VARCHAR
, 또는 TEXT
컬럼의 스토리지 및 I / O 비용을 줄일 수 있습니다.
압축과 InnoDB 버퍼 풀
압축 된 InnoDB 테이블 (1K, 2K, 4 또는 8K)는 16K 바이트 ( innodb_page_size
이 설정되어있는 경우는 더 작은 크기)의 비 압축 페이지에 대응하고 있습니다. 페이지의 데이터에 액세스하기 위해 MySQL은 압축 된 페이지가 버퍼 풀 에 이미 존재하지 않는 경우 해당 페이지를 디스크에서 읽은 후 원래의 형태로 압축 해제합니다. 이 섹션에서는 압축 테이블의 페이지에 대해 버퍼 풀을 InnoDB로 관리되는 방법을 설명합니다.
I / O를 최소화하여 페이지를 압축 해제하는 필요성을 줄이기 위해 버퍼 풀에 압축 된 형식과 압축 형식의 두 데이터베이스 페이지가 포함될 수 있습니다. 기타 필요한 데이터베이스 페이지의 공간을 확보하기 위해 MySQL은 메모리에 압축 된 페이지를 유지하면서 버퍼 풀에서 비 압축 페이지를 새우 션 수 있습니다. 또한 잠시 동안 페이지가 액세스되지 않으면 다른 데이터에 대한 공간을 확보하기 위해 압축 된 페이지가 디스크에 기록 될 수 있습니다. 따라서 때때로 버퍼 풀에 압축과 비 압축 형식의 두 페이지가 포함되어 있으면 압축 된 페이지 만 포함되어있는 경우 모두 포함되어 있지 않을 수 있습니다.
MySQL은 핫 (자주 액세스되는) 데이터가 메모리에 체류하는 경향이되도록 최근 가장 사용되지 않은 ( LRU ) 목록을 사용하여 메모리에 유지되는 페이지 및 삭제되는 페이지가 추적됩니다. 압축 테이블에 액세스하면 MySQL은 적응 형 LRU 알고리즘을 사용하여 메모리에서 압축 된 페이지와 비 압축 페이지의 적절한 균형을 제공합니다. 이 적응 형 알고리즘은 시스템이 I / O 바운드 와 CPU 바운드 의 두 방식으로 실행되고 있는지의 영향을 받기 쉬워집니다. 이 목표는 CPU 부하가 높을 때 페이지를 압축 해제하는 데 걸리는 처리 시간이 길지을 피할 수 및 (메모리에 이미 존재하는 가능성이있는) 압축 된 페이지를 압축 해제 하는 데 사용할 수있는 여분의 사이클이 CPU에 제공되는 때 과도한 I / O가 발생하는 것을 방지하는 것입니다. 시스템이 I / O 바운드의 경우,이 알고리즘은 다른 디스크 페이지를 위해 더 많은 공간을 확보함으로써 메모리 상주되도록 페이지의 두 복사본이 아닌 비 압축 복사본을 삭제 것이 우선됩니다. 시스템이 CPU 바운드의 경우 MySQL은 "핫"페이지에 사용할 수있는 메모리가 많아지고, 압축 형식으로 만 메모리 내의 데이터를 압축 해제 할 필요성이 최소화되도록 압축 된 페이지와 비 압축 페이지 모두를 제거하는 것이 우선됩니다.
압축과 InnoDB의 Redo 로그 파일
압축 된 페이지가 데이터 파일 에 기록되기 전에, MySQL에 의해 페이지의 복사본을 Redo 로그에 기록됩니다 (마지막으로 데이터베이스에 기록 된 이후에 다시 압축 된 경우). 이것은 zlib
라이브러리가 업그레이드되어 그 변경에 의해 압축 된 데이터와의 호환성 문제가 발생할 가능성이 낮은 경우에도 충돌 복구 시 Redo 로그를 사용할 수 있는지 여부를 확인하기 위해 수행됩니다. 따라서 압축 사용할 때 로그 파일 의 크기를 약간 크게하는 것, 또는 더 자주 체크 포인트 를 발생시킬 필요성을 다소 많이하는 것이 요구 될 수 있습니다. 로그 파일의 크기를 크게하는 금액 또는 체크 포인트의 빈도를 많은 수는 재구성 및 재 압축이 필요한 방식으로 압축 된 페이지가 변경되는 횟수에 따라 다릅니다.
압축 테이블에서는 Redo 로그 및 테이블마다 테이블 스페이스에 사용되는 파일 형식이 MySQL 5.1 이전과는 다르다는 점에 유의하십시오. MySQL Enterprise Backup 제품은 압축 된 InnoDB 테이블에이 최신 Barracuda 파일 형식이 지원되고 있습니다.