web-dev-qa-db-ja.com

mysql-InnoDBからの行の削除が非常に遅い

私は約でmysqlデータベースを取得しました。 1 TB。テーブルfuelinjection_strokeには約1.000.000.000行があります。DBIDは、挿入ごとに1ずつ自動的にインクリメントされる主キーです。

私は非常に単純なステートメントを使用して最初の1.000.000行を削除しようとしています:

Delete from fuelinjection_stroke where DBID < 1000000;

このクエリは、専用の8コアXeonサーバー(32 GBメモリ、SASストレージ))で非常に時間がかかります(> 24時間)。

プロセスをスピードアップできるかどうか考えていますか?

15
user1938509

テーブルがロックされたと思います。私は同じ問題に直面し、それが10kレコードをかなり速く削除できることがわかりました。したがって、チャンクごとにレコードを削除する単純なスクリプト/プログラムを作成することができます。

   DELETE FROM fuelinjection_stroke WHERE DBID < 1000000 LIMIT 10000;

そして、すべてを削除するまで実行し続けます

21
Uriil

スペースが不足していますか?ダウンタイムは不可能ですか?

そうでない場合は、新しいINT列の長さを1に合わせ、デフォルトで「アクティブ」(または用語が何であれ)の場合は1に、「非アクティブ」の場合は0に設定できます。実際には、必要に応じて0〜9を10の異なる状態として使用できます。

この新しい列を追加すると、かなり時間がかかりますが、終了すると、PRIMARYから(DELETEで行うように)オフにし、この新しい列にインデックスを付けない限り、UPDATEは高速になります。

InnoDBがあなたのような大規模なテーブルでDELETEに非常に時間がかかる理由は、クラスターインデックスが原因です。 PRIMARY(または最初に見つかったUNIQUE、またはPRIMARYまたはUNIQUEが見つからない場合はどのように感じるかに基づいて)に基づいてテーブルを物理的に並べ替えるので、1つの行を取り出すと、物理的にENTIREテーブルが並べ替えられます速度とデフラグ用のディスク。したがって、それほど時間がかかっているのはDELETEではありません。その行が削除された後の物理的な並べ替えです。

デフォルト値を使用して新しいINT列を作成すると、スペースが埋められるため、UPDATEを実行するときに、巨大なテーブル全体で物理的に並べ替える必要はありません。

スキーマが正確に何であるかは正確にはわかりませんが、行の状態に列を使用する方がDELETEingよりもはるかに高速です。ただし、より多くのスペースが必要になります。

値を設定してみてください:

innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT (for non-windows machine)
innodb_buffer_pool_size=25GB (currently it is close to 21GB)
innodb_doublewrite=0
innodb_support_xa=0
innodb_thread_concurrency=0...1000 (try different values, beginning with 200)

参照:

さまざまな変数の説明については、MySQLドキュメント

MySQLサーバー設定のチューニング

MySQLパフォーマンス最適化の基本

http://bugs.mysql.com/bug.php?id=28382

5
jmail

どのようなインデックスがありますか?

あなたの問題は、削除が反復ごとにインデックスを再構築することだと思います。

インデックスがある場合は削除し、削除してからインデックスを再度追加します。はるかに速くなります(私は思う)。

4
i-CONICA

私も同じ問題を抱えていて、テーブルにはいくつかのインデックスがあり、削除して再作成する必要はありませんでした。だから私は次のことをしました:

create table keepers
select * from origTable where {clause to retrieve rows to preserve};
truncate table origTable;
insert into origTable null,keepers.col2,...keepers.col(last) from keepers;
drop table keepers;

約220万行が約3分で処理されました。

2
user5883982

データベースが、外部キー(カスケード、削除)で変更する必要があるレコードをチェックしている可能性があります。

しかし、I-Conicaの回答は良い点です(+1)。単一のレコードを削除し、100000回実行中に多数のインデックスを更新するプロセスは非効率的です。インデックスを削除し、すべてのレコードを削除して、もう一度作成してください。

そしてもちろん、データベースに何らかのロックが設定されていないか確認してください。 1人のユーザーまたはアプリケーションがレコードまたはテーブルをロックすると、クエリは、ユーザーがリソースを解放するか、リソースがタイムアウトになるまで待機します。データベースが実際の作業を行っているか単に待機しているかを確認する1つの方法は、-innodb_lock_wait_timeoutパラメーターを数秒に設定する接続からクエリを起動することです。少なくとも失敗した場合は、クエリに問題がなく、そのロックを見つけて理解する必要があることがわかります。ロックの例は、更新およびコミットされていないトランザクションの場合、Select * from XXXです。

0
borjab

そのような長いテーブルでは、特に大量のトランザクションが必要でない場合は、MYISAMを使用します。

0
user6850438