0

毎週、InnoDB エンジンを使用する MySQL テーブルから約 500,000 レコードを削除する cron ジョブが起動されます。このテーブルには、毎週処理する Web ログ データが含まれており、その後、不要になったデータは削除されます。このテーブルには、UNIX タイムスタンプである時刻を含む 3 つのインデックス (外部キーなし) があります。

グローバルビューログから削除 WHERE 時間 <1354391592

問題は、先週実行したこのクエリの実行に 2 時間以上かかり、その間、サーバー全体が遅れていたことです。「iotop」は、MySQL によって書き込まれるハードディスクが大量に引用され、サーバーの負荷が異常なレベルまで劇的に増加したことを明らかにしました。

クリックするたびにテーブルが書き込まれます。私が見ていない部屋に象がいますか?つまり、この毎週のクエリを最適化するために盲目的に明らかなことはありますか?

ありがとう

4

2 に答える 2

5

時間に基づいて古いデータを定期的に削除する場合、同じ列に基づいてテーブルをパーティション分割すると、はるかに高速になります。異なる期間をディスク上の異なる領域に分割するため、削除は個々の行を見るのではなく、チャンク全体を削除することになります。

http://dev.mysql.com/doc/refman/5.5/en/partitioning.html

于 2012-12-01T20:02:22.107 に答える
2

InnoDB を使用しているため、暗黙的なトランザクションがあります。大量のレコードを削除しているため、トランザクションは大きくなります。@Erik Ekmanは正しいです。パーティショニングを機能させることができれば、これを処理する良い方法です。

しかし、ここに別の良い方法があります。そのように、小さなバッチで削除を行ってみてください。

  DELETE 
    FROM global_viewlog 
   WHERE time<135439159
   LIMIT 1000

削除するものがなくなるまで、このステートメントを発行し続けます。ほとんどのクライアント ライブラリ (JDBC など) は、影響を受けたレコードの数を返します。または、これを安価な方法で実行したい場合は、スクリプトからステートメントを 1000 回発行することもできます。

(ステートメント内のレコードの数をいじることができますLIMIT。) 1 つの削除ステートメントよりも時間がかかる場合とそうでない場合がありますが、サーバーをそれほど拘束することはありません。

このテーブルのアクセス方法を MyISAM に変更して、これを使用してみてください。

  DELETE LOW_PRIORITY QUICK
    FROM global_viewlog 
   WHERE time<135439159

これにより、クリーンアップ操作が本番環境に干渉しなくなります。

cron ジョブの頻度を週 1 回から 1 日 1 回に変更します。これにより、削除バッチのサイズが縮小されるため、クリーンアップする必要がなくなります。

于 2012-12-01T21:25:20.860 に答える