조각난 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. 테이블이에 있으면 전체 테이블 스페이스 ibdata1를 Data_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.