いくつかのテーブルを持つデータベースがあります。
テーブルからいくつかのレコードを削除したいのですが、レコード数が20Kまたは50Kを超えています。
すべてのテーブルはInnoDBです。そしてfile_per_table
はoffです。
いくつかのテーブルからレコードを削除すると、テーブルが断片化されます。
断片化を取り除く方法はありますか?
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)
だから今私の質問は、テーブルがフラグメント化されているかどうかをどのように決定するかです。
2010年10月にStackOverflowでこれに対処しました 。
InnoDBインフラストラクチャで最も使用頻度の高いファイル/ var/lib/mysql/ibdata1に留意してください
このファイルには通常、4種類の情報が格納されています
Ibdata1に格納されているInnoDBテーブルに対してOPTIMIZE TABLE
を実行すると、次の2つのことが行われます。
テーブルデータとテーブルインデックスを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つ以上がある場合です。
CREATE TABLE
、DROP TABLE
、ALTER TABLE
)各InnoDBテーブルはibdata1の外に存在します
Mydb.mytableという名前のInnoDBテーブルがあるとします。/var/lib/mysql/mydbに移動すると、テーブルを表す2つのファイルが表示されます。
ibdata1にInnoDBデータとインデックスが含まれることはなくなります。
/etc/my.cnfのinnodb_file_per_tableオプションを使用すると、OPTIMIZE TABLE mydb.mytable;
を実行すると、ファイル/var/lib/mysql/mydb/mytable.ibdが実際に圧縮されます。
私はこれをMySQL DBAとしてのキャリアの中で何度も行ってきました
実際、これを初めて行ったとき、50GBのibdata1ファイルを500MBに縮小しました。
試してみる。これについてさらに質問がある場合は、メールでお問い合わせください。私を信じて。これは短期的にも長期的にも機能します!!!
上記の手順を実行した後、どのテーブルを最適化する必要があるかをどのように判断できますか?見つけることは可能ですが、スクリプトを作成する必要があります。
次に例を示します。テーブル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;
行を頻繁に削除する(または可変長データ型で行を更新する)と、ファイルシステムの断片化と同様に、データファイルに大量の無駄なスペースができてしまう可能性があります。
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が背後で行うことです。読み取りロックが発生しますが、テーブル全体のロックは発生しません。所要時間は、テーブル内のデータの量に完全に依存します(ただし、データファイルのサイズには依存しません)。大量の削除または更新を含むテーブルがある場合、これを毎月または毎週実行することもできます。