조각난 MySQL 테이블을 찾아서 수정하는 방법


27

일부 테이블이 조각화되었음을 지적하는 MySQLTuner를 사용했습니다. 나는 사용했다

mysqlcheck --optimize -A

모든 테이블을 최적화합니다. 일부 테이블을 수정했지만 MySQLTuner는 여전히 19 개의 테이블을 조각화합니다. 조각 모음이 필요한 테이블을 어떻게 알 수 있습니까? 어쩌면 OPTIMIZE TABLE이 mysqlcheck가 작동하지 않은 곳에서 작동합니까? 아니면 다른 무엇을 시도해야합니까?


1
비슷한 문제가 있습니다. MySQL 5.5를 사용하여 새 DB를 설정하고 있으며 특정 InnoDB 테이블이 조각 모음되지 않습니다. InnoDB 테이블에서 Data_free 검사 (KayakJim의 답변에 표시)가 올바르지 않은지 궁금합니다.
docwhat

답변:


38

짧은 대답 :

select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

"알아야합니다"답변

먼저 행이 업데이트 될 때 MySQL 테이블이 조각화된다는 것을 이해해야하므로 정상적인 상황입니다. 데이터가있는 덤프를 사용하여 가져온 테이블을 만들면 모든 행이 여러 고정 크기 페이지에서 조각화없이 저장됩니다. 가변 길이 행을 업데이트 할 때이 행을 포함하는 페이지는 변경 사항을 저장하기 위해 둘 이상의 페이지로 나뉘어지고 새 두 개 이상의 페이지에는 사용되지 않은 공간을 채우는 빈 공간이 포함됩니다.

물론 조각화가 너무 커지지 않는 한 성능에 영향을 미치지 않습니다. 조각화가 너무 많으면 원하는 쿼리를 보도록하겠습니다.

  select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

DATA_LENGTH 및 INDEX_LENGTH는 데이터 및 인덱스가 사용하는 공간이며 DATA_FREE는 모든 테이블 페이지에서 사용되지 않은 총 바이트 수입니다 (조각화).

실제 생산 테이블의 예는 다음과 같습니다.

| ENGINE | TABLE_NAME               | data_length | index_length | data_free |
| InnoDB | comments                 |         896 |          316 |         5 |

이 경우 (896 + 316) = 1212MB를 사용하는 테이블이 있고 데이터의 여유 공간이 5MB입니다. 이것은 다음과 같은 "단편화 비율"을 의미합니다.

5/1212 = 0.0041

... "조각화 비율"이 정말 낮습니다.

0.2에 가까운 비율 (빈 공간의 20 %를 의미)로 테이블을 작업하고 있으며 테이블을 최적화하더라도 성능이 동일하더라도 쿼리 속도가 느려지지 않습니다. 그러나 800MB 테이블에 최적화 테이블을 적용하는 데 많은 시간이 걸리고 몇 분 동안 테이블을 차단하므로 프로덕션에서는 불가능합니다.

따라서 성능에서이기는 것을 고려하고 테이블을 최적화하는 데 낭비되는 시간을 고려하지 않으면 최적화하지 않는 것이 좋습니다.

스토리지에 더 적합하다고 생각되면 비율을 확인하고 최적화 할 때 절약 할 수있는 공간을 확인하십시오. 일반적으로 너무 많지 않으므로 최적화하지 않는 것이 좋습니다.

그리고 최적화하면 다음 업데이트에서 페이지를 둘 이상으로 분할하여 빈 공간을 만듭니다. 그러나 테이블이 조각난 경우 행에 대한 업데이트가 반드시 페이지를 분할하지는 않기 때문에 조각난 테이블보다 조각화 된 테이블을 업데이트하는 것이 더 빠릅니다.

이것이 도움이되기를 바랍니다.


1
이것은 몇 년 전의 대답이지만, data_free는 해당 테이블이 아닌 전체 테이블 공간에 대한 통계라고 지적했습니다. 하나의 테이블 스페이스에 여러 테이블을 함께 저장하는 경우 테이블 스페이스에 여유 범위가 있음을 의미 할 때 data_free는 테이블 조각 모음이 필요하다고 잘못 판단 할 수 있습니다. 최적화 테이블을 실행해도 여유 범위가 줄어들지 않습니다. 테이블 조각 모음을 수행 하면 여유 범위가 늘어날 수도 있습니다 .
Bill Karwin 17 년

14

Felipe-Rojas 의 답변에 추가하기 위해 쿼리의 일부로 조각 비율을 계산할 수 있습니다.

select ENGINE,
  concat(TABLE_SCHEMA, '.', TABLE_NAME) as table_name,
  round(DATA_LENGTH/1024/1024, 2) as data_length,
  round(INDEX_LENGTH/1024/1024, 2) as index_length,
  round(DATA_FREE/1024/1024, 2) as data_free,
  (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
ORDER BY frag_ratio DESC;

테이블이 작은 비율 (5 % 미만)로 조각난 경우에는 그대로 두어도됩니다.

더 큰 것이면 테이블 사용량을 조각화하는 것이 얼마나 중요한지 DB 사용, 테이블 잠금 등을 기준으로 평가해야합니다.


2

테이블 최적화는 실제로 발생한 문제를 해결합니다.

데이터베이스가 몇 개인 경우 PHPMyAdmin을 사용하여 모든 데이터베이스를 살펴볼 수 있습니다. 오버 헤드가있는 테이블을 선택한 다음 최적화하도록 선택하십시오.

데이터베이스가 많으면 다른 방법이 바람직 할 것입니다.

나는 cron에서 다음 PHP 스크립트 설정을 사용하여 매 시간마다 실행합니다.

$DB = new mysqli ('localhost', 'DbUser', 'DbPassword');
$results = $DB->query('show databases');
$allDbs = array();
while ($row = $results->fetch_array(MYSQLI_NUM))
{
    $allDbs[] = $row[0];
}
$results->close();
foreach ($allDbs as $dbName)
{
    if ($dbName != 'information_schema' && $dbName != 'mysql')
    {
        $DB->select_db($dbName);
        $results = $DB->query('SHOW TABLE STATUS WHERE Data_free > 0');
        if ($results->num_rows > 0)
        {
            while ($row = $results->fetch_assoc())
            {
                $DB->query('optimize table ' . $row['Name']);
            }
        }
        $results->close();
    }
}
$DB->close();

3
나는 그것이 mysqlcheck --optimize -ASQL과 동일 하다고 확신한다OPTIMIZE TABLE <tablename>;
docwhat

2

이 페이지를 방문하여 Felipe-Rojas와 sysadmiral의 쿼리가 매우 유용하다는 것을 알았습니다. 그러나 필자의 경우 WHM의 phpMyAdmin에서 쿼리를 실행하고 데이터베이스가 나열되지 않았기 때문에 TABLE_NAME 만 얻는 것이 도움이되지 않았으며 여러 데이터베이스의 테이블 이름이 동일합니다. 따라서 단순히 추가 TABLE_SCHEMA하면 해당 열도 제공됩니다.

select  ENGINE, TABLE_SCHEMA, TABLE_NAME, Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free, (data_free/(index_length+data_length)) as frag_ratio from information_schema.tables  where  DATA_FREE > 0 order by frag_ratio desc

DB를 보여줍니다

ENGINE  | TABLE_SCHEMA  | TABLE_NAME    | data_length   | index_length  | data_free | frag_ratio

InnoDB  | db_name       | db_table      | 0             | 0             | 8         | 170.6667

"수정"하기 위해 phpMyAdmin에서 실행되는 "frag_ratio"가 높은 각 테이블에 대해 phpMyAdmin의 조각 모음 테이블 링크를 사용했습니다.

ALTER TABLE `table_name` ENGINE = InnoDB;

0

MySQL의 InnoDB 엔진을 사용하는 테이블은 기본적으로 반드시 그럴 필요는 없습니다 OPTIMIZEd.

Data_freefrom information_schema.tables또는 from 값은 SHOW TABLE STATUS0이 아닌 경우가 많습니다. 모든 작업을 완료했다고 생각하더라도 테이블 조각 모음을 수행 할 수 있습니다. 또한이 메트릭은 발생할 수 있고 발생할 수 있는 여러 조각 중 하나 일뿐 입니다. 또한 블록의 공간 낭비, 목록 실행 취소, 색인 BTree 대 데이터 BTree 등

그리고 innodb_file_per_table의 사용을 복잡하게한다 Data_free. 테이블이에 있으면 전체 테이블 스페이스 ibdata1Data_free나타냅니다. 다소 쓸모없는 숫자. 테이블이 자체 .ibd파일에 있으면 테이블 크기의 몇 MB 또는 몇 퍼센트 중 큰 값일 수 있습니다.

당신이 삭제 한 경우에만 많은 행을 하고 테이블을 보충하지 않으려 그것은 가치가 실행 OPTIMIZE TABLE.

PARTITIONs또한 파티션은 일반적으로 4-7MB "사용 가능"을 나타 내기 Data_free때문에 방해하는 양을 나타냅니다. 그리고 이것은 사라지지 않을 것입니다.

조각 모음이 필요한 이유

  • 공간을 OS로 되돌리려면? 글쎄, 당신 이 있다면 이것을 간단히 달성 할 수 있습니다innodb_file_per_table=1 . 그러나 행을 추가하면 OS에서 다시 가져옵니다.
  • 액세스 속도를 높이려면? 잊어 버려. 디스크의 블록 레이아웃은 비교적 임의적이며 지난 수십 년 동안 사용되었습니다. 반세기 전에 블록을 재정렬하는 것이 다소 중요했습니다.
  • BTree를 재조정하려면? 그래서? 그들은 즉시 다시 불균형이 될 것입니다. 무작위로 삽입되는 BTree의 정상 상태는 69 %입니다. 그리고 그것도 고려되지 않았습니다 Data_free.
  • MySQLTuner가 말합니다. 그 제품은 차가워 야합니다.

역사 기록. 내가 주로 MyISAM 테이블을 사용하여 DBA를 도울 때, 아마도 매월 도움을받은 1000 개의 테이블 중 2 개를 발견했습니다 OPTIMIZE. 그 이후로 수천 개의 InnoDB 테이블로 작업했지만 아직 도움이 될만한 성능 문제를 발견했습니다 OPTIMIZE. (물론, OPTIMIZE도움 이 될 수 있는 디스크 공간 문제가 있었지만 까다로워집니다. 일반적으로 DBA에는 실행할 디스크 공간이 충분하지 않습니다 OPTIMIZE!)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.