web-dev-qa-db-ja.com

InnoDBテーブルから断片化をどのように削除しますか?

いくつかのテーブルを持つデータベースがあります。

テーブルからいくつかのレコードを削除したいのですが、レコード数が20Kまたは50Kを超えています。

すべてのテーブルはInnoDBです。そしてfile_per_tableoffです。

いくつかのテーブルからレコードを削除すると、テーブルが断片化されます。

断片化を取り除く方法はありますか?

4月17日に更新

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

だから今私の質問は、テーブルがフラグメント化されているかどうかをどのように決定するかです。

13
Abdul Manaf

2010年10月にStackOverflowでこれに対処しました

InnoDBインフラストラクチャで最も使用頻度の高いファイル/ var/lib/mysql/ibdata1に留意してください

このファイルには通常、4種類の情報が格納されています

  • テーブルデータ
  • テーブルインデックス
  • MVCC(マルチバージョン同時実行制御)データ
  • テーブルメタデータ(テーブルスペースIDのリスト)

Ibdata1に格納されているInnoDBテーブルに対してOPTIMIZE TABLEを実行すると、次の2つのことが行われます。

  • テーブルのデータとインデックスをibdata1内で連続させるため、アクセスが高速になります。
  • 連続したデータとインデックスページがibdata1に追加されるため、ibdata1が大きくなります。

テーブルデータとテーブルインデックスをibdata1から分離し、 innodb_file_per_table を使用して個別に管理できますが、 ibdata1は単に破棄されず、再利用できません。あなたはもっとやらなければならない。

ibdata1を1回だけ縮小するには、以下を実行する必要があります。

1)MySQLDumpですべてのデータベースをSQLテキストファイル(/root/SQLData.sqlと呼びます)

2)すべてのデータベースを削除します(mysqlスキーマを除く)

3)mysqlをシャットダウンします。

4)/etc/my.cnfに次の行を追加します

[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G

補足:innodb_buffer_pool_sizeの設定が何であれ、innodb_log_file_sizeがinnodb_buffer_pool_sizeの25%であることを確認してください。

5)ibdata1、ib_logfile0およびib_logfile1を削除します

この時点では、/ var/lib/mysqlにmysqlスキーマのみがあるはずです。

6)mysqlを再起動します

これにより、ibdata1が10または18MB(MySQLのバージョンによって異なる)、ib_logfile0およびib_logfile1がそれぞれ1Gで再作成されます。

7)/root/SQLData.sqlをmysqlにリロードします

ibdata1は大きくなりますが、テーブルメタデータのみが含まれます。実際、それは数年にわたって非常にゆっくりと成長します。 ibdata1が急速に成長する唯一の方法は、以下の1つ以上がある場合です。

  • 大量のDDL(CREATE TABLEDROP TABLEALTER TABLE
  • たくさんの取引
  • トランザクションごとにコミットする多くの変更

各InnoDBテーブルはibdata1の外に存在します

Mydb.mytableという名前のInnoDBテーブルがあるとします。/var/lib/mysql/mydbに移動すると、テーブルを表す2つのファイルが表示されます。

  • mytable.frm(ストレージエンジンヘッダー)
  • mytable.ibd(mydb.mytableのテーブルデータとテーブルインデックスのホーム)

ibdata1にInnoDBデータとインデックスが含まれることはなくなります。

/etc/my.cnfのinnodb_file_per_tableオプションを使用すると、OPTIMIZE TABLE mydb.mytable;を実行すると、ファイル/var/lib/mysql/mydb/mytable.ibdが実際に圧縮されます。

私はこれをMySQL DBAとしてのキャリアの中で何度も行ってきました

実際、これを初めて行ったとき、50GBのibdata1ファイルを500MBに縮小しました。

試してみる。これについてさらに質問がある場合は、メールでお問い合わせください。私を信じて。これは短期的にも長期的にも機能します!!!

UPDATE 2012-04-19 09:23 EDT

上記の手順を実行した後、どのテーブルを最適化する必要があるかをどのように判断できますか?見つけることは可能ですが、スクリプトを作成する必要があります。

次に例を示します。テーブルmydb.mytableがあるとします。 innodb_file_per_tableを有効にすると、ファイル/var/lib/mysql/mydb/mytable.ibdができます

2つの数値を取得する必要があります

OSからのファイルサイズ:このようにOSからファイルサイズを確認できます

ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'

FILESIZE FROM INFORMATION_SCHEMA:次のようにして、information_schema.tablesからファイルサイズを確認できます。

SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';

OS値からINFORMATION_SCHEMA値を減算し、その差をINFORMATION_SCHEMA値で除算するだけです。

そこから、そのテーブルをデフラグする必要があると見なす割合を決定します。もちろん、次のいずれかのコマンドを使用してデフラグします。

OPTIMIZE TABLE mydb.mytable;

または

ALTER TABLE mydb.mytable ENGINE=InnoDB;
14
RolandoMySQLDBA

行を頻繁に削除する(または可変長データ型で行を更新する)と、ファイルシステムの断片化と同様に、データファイルに大量の無駄なスペースができてしまう可能性があります。

innodb_file_per_tableオプションを使用していない場合、それに対して実行できる唯一のことは、データベースのエクスポートとインポートという、時間とディスクを集中的に使用する手順です。

ただし、innodb_file_per_tableを使用している場合は、このスペースを識別して再利用できます。

5.1.21より前のバージョンでは、free_spaceカウンターはinformation_schema.tablesのtable_comment列から利用できます。次に、少なくとも100M(実際には97.65M)の空き領域があるテーブルを特定するSQLをいくつか示します。

SELECT table_schema、table_name、table_comment FROM
information_schema.tables WHERE ENGINE LIKE 'InnoDB' AND table_comment RLIKE 'InnoDB free:([0-9] {6、})。*';

5.1.21以降、これはdata_free列(より適切な場所)に移動されました。

SELECT table_schema、table_name、data_free/1024/1024 AS data_free_MB FROM information_schema.tables WHERE ENGINE LIKE 'InnoDB' AND data_free> 100 * 1024 * 1024;

テーブルを再構築することで、失われたスペースを取り戻すことができます。これを行う最良の方法は、実際には何も変更せずに「代替テーブル」を使用することです。

ALTER TABLE `TableName` ENGINE=InnoDB;

これは、InnoDBテーブルで「テーブルの最適化」を実行した場合にMySQLが背後で行うことです。読み取りロックが発生しますが、テーブル全体のロックは発生しません。所要時間は、テーブル内のデータの量に完全に依存します(ただし、データファイルのサイズには依存しません)。大量の削除または更新を含むテーブルがある場合、これを毎月または毎週実行することもできます。

5
Mahesh Patil