断片化されたMySQLテーブルを見つけて修正する方法


27

いくつかのテーブルが断片化されていることを指摘したMySQLTunerを使用しました。使った

mysqlcheck --optimize -A

すべてのテーブルを最適化します。いくつかのテーブルを修正しましたが、MySQLTunerはまだ19個のテーブルが断片化されていることを発見しました。最適化が必要なテーブルを確認するにはどうすればよいですか?mysqlcheckが機能しなかった場所でOPTIMIZE TABLEが機能する可能性はありますか?または、他に何を試してみる必要がありますか?


1
同様の問題があります。MySQL 5.5を使用して新しいDBを設定していますが、特定のInnoDBテーブルは断片化を解除しません。Data_freeチェック(KayakJimの答えに示されている)がInnoDBテーブルで間違っているのではないかと思っています。
-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テーブルが断片化されることを理解する必要があるため、これは通常の状況です。テーブルを作成すると、たとえば、データを含むダンプを使用してインポートすると、多くの固定サイズのページにすべての行が断片化せずに保存されます。可変長の行を更新すると、この行を含むページは2つ以上のページに分割されて変更が保存され、これらの新しい2つ(またはそれ以上)のページには未使用スペースを埋める空白スペースが含まれます。

もちろん、断片化が大きくなりすぎない限り、これはパフォーマンスに影響しません。断片化が多すぎるので、探しているクエリを見てみましょう。

  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)= 1212 MBを使用するテーブルがあり、データには5 MBの空き領域があります。これは、次の「断片化の比率」を意味します。

5/1212 = 0.0041

...これは非常に低い「断片化率」です。

私は0.2に近い比率(空白スペースの20%を意味する)でテーブルを操作してきましたが、テーブルを最適化してもパフォーマンスが同じであっても、クエリのスローダウンに気付くことはありません。ただし、800MBのテーブルに最適化テーブルを適用すると、時間がかかり、テーブルが数分間ブロックされます。これは、実稼働環境では実行不可能です。

したがって、パフォーマンスで勝つものと、テーブルの最適化に費やされる時間を考慮すると、最適化は好ましくありません。

ストレージに適していると思われる場合は、比率を確認し、最適化するときに節約できるスペースを確認してください。通常は多すぎないので、最適化しないことをお勧めします。

また、最適化すると、次の更新でページが2つ以上に分割されて空白スペースが作成されます。ただし、表が断片化されている場合、行の更新は必ずしもページを分割するとは限らないため、断片化された表を更新する方が、断片化されていない表よりも高速です。

これがあなたのお役に立てば幸いです。


1
これは数年前の回答ですが、data_freeはそれぞれのテーブルではなく、テーブルスペース全体の統計であると指摘したいと思いました。1つのテーブルスペースに複数のテーブルを一緒に格納すると、data_freeは、テーブルスペースに空きエクステントがあることを意味するだけで、テーブルの最適化が必要であると誤解する可能性があります。最適化テーブルを実行しても、空きエクステントは減少しません。テーブルを最適化すると、空きエクステントが増加することさえあります。
ビルカーウィン

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%未満?)、おそらくそのままにしておくことができます。

より大きなものはすべて、テーブルの最適化がいかに重要であるかについて、データベースの使用量、テーブルのロックなどに基づいて評価する必要があります。


2

テーブルの最適化は実際にあなたが抱えている問題を解決します。

少数のデータベースしかない場合は、PHPMyAdminを使用してすべてのデータベースを確認できます。オーバーヘッドのあるテーブルを選択してから、最適化を選択します。

多数のデータベースがある場合は、別の方法が望ましいと思われます。

cronで次のPHPスクリプトセットアップを使用して、1時間ごとに実行します。

$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のDefragment tableリンクを使用しました。

ALTER TABLE `table_name` ENGINE = InnoDB;

0

MySQLのInnoDBエンジンを使用するテーブルは、基本的には必要ありませんOPTIMIZEd

Data_freefrom information_schema.tablesまたはor の値はSHOW TABLE STATUS、テーブルを最適化するためにできることをすべて完了したと思われる場合でも、多くの場合ゼロ以外です。さらに、そのメトリックは、発生する可能性のあるいくつかの断片化のうちの1つにすぎません。(また、ブロック内の無駄なスペース、取り消しリスト、インデックスBTreeとデータBTreeなどなど。

そしてinnodb_file_per_table、の使用を複雑にしますData_free。テーブルがである場合ibdata1、次いで、Data_free表領域全体を指します。かなり役に立たない数。テーブルが独自の.ibdファイルにある場合、数MBまたはテーブルサイズの数パーセントのいずれか大きい方になる可能性があります。

削除した場合にのみ、多くの行をし、テーブルを補充するつもりはない、かもしれないそれは価値が実行されていますOPTIMIZE TABLE

PARTITIONsまたData_freeパーティションは通常4〜7MBの「空き容量」を示すため、不安な量を示します。そして、これは消えません。

最適化する理由

  • 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.