2016-01-11 12 views
6

私は7つの関連するテーブルがあり、テーブルの1つにタイムスタンプの列があり、30日以上経過したすべての行を削除したいと思います。しかし、これは非常に大きな削除です。私は数千万の記録を話している。これらのレコードをメインテーブルからすべて削除すると、他の6つのテーブルを調べ、それらのテーブルから関連するレコードを削除する必要があります。MySQL - 複数のテーブルの大きな削除

私の質問は、これを最適化する最良の方法は何ですか?

私はPARTITIONを使用することを考えていますが、1つのテーブルにタイムスタンプ列があります。私は、メインテーブルに古いパーティションをドロップすると、他の6つのテーブルに関連するレコードが残ってしまうことが心配です。関連するレコードはフィールド(sid、cid)によって関連付けられます。

コンテキストのために私はIDSプロセッサであるsnortとbarnyardを使用しています。私はここでのMySQL 5.1.73、MyISAMテーブルに

を使用してい

は、クリーンアップのログからの抜粋です:

StartTime,EndTime,TimeElapsed,AffectedRows 
Wed Jan 6 01:00:01 EST 2016,Wed Jan 6 01:45:11 EST 2016,45:10,2911807 
Thu Jan 7 01:00:02 EST 2016,Thu Jan 7 01:25:29 EST 2016,25:27,2230255 
Fri Jan 8 01:00:01 EST 2016,Fri Jan 8 01:24:18 EST 2016,24:17,1400470 
Sat Jan 9 01:00:02 EST 2016,Sat Jan 9 05:47:10 EST 2016,287:8,23360088 
Sun Jan 10 01:00:01 EST 2016,Sun Jan 10 10:06:16 EST 2016,546:15,44970072 
Mon Jan 11 01:00:01 EST 2016,Mon Jan 11 09:40:39 EST 2016,520:38,43948091 

これは私の昔のクリーンアップスクリプトだった:

/usr/bin/mysql --defaults-extra-file=/old/.my.cnf snort_db >> /root/snortcleaner.log 2>&1 <<EOF 
use snort_db; 

DROP TRIGGER IF EXISTS delete_old; 

DELIMITER // 
CREATE TRIGGER delete_old AFTER DELETE ON event 
FOR EACH ROW 
BEGIN 
DELETE FROM data WHERE data.cid = old.cid AND data.sid = old.sid; 
DELETE FROM iphdr WHERE iphdr.cid = old.cid AND iphdr.sid = old.sid; 
DELETE FROM icmphdr WHERE icmphdr.cid = old.cid AND icmphdr.sid = old.sid; 
DELETE FROM tcphdr WHERE tcphdr.cid = old.cid AND tcphdr.sid = old.sid; 
DELETE FROM udphdr WHERE udphdr.cid = old.cid AND udphdr.sid = old.sid; 
DELETE FROM opt WHERE opt.cid = old.cid AND opt.sid = old.sid; 
END // 
DELIMITER ; 

EOF 

# Send the main MySQL command: Deletes all records betweeen the oldest  timestamp and 31 days from now() 
# Gets the oldest timestamp and ranges a deletion from that to 31 days before now(). If the oldest timestamp is more recent than 31 days, the following command returns 0 anyway. If it is older than 31 days, it will return them 
OLDEST_TIMESTAMP=$(mysql --defaults-extra-file=/old/.my.cnf -Dsnort_db -se "SELECT timestamp FROM event ORDER BY timestamp ASC LIMIT 1;") 
NUM_AFFECTED=$(mysql --defaults-extra-file=/old/.my.cnf -Dsnort_db -se "DELETE FROM event WHERE timestamp BETWEEN DATE_SUB('${OLDEST_TIMESTAMP}', INTERVAL 1 HOUR) AND DATE_SUB(NOW(), INTERVAL 31 DAY); SELECT ROW_COUNT();") 

これは、私の現在のクリーンアップスクリプト:

DELETE FROM event WHERE timestamp BETWEEN DATE_SUB('${OLDEST_TIMESTAMP}', INTERVAL 1 HOUR) AND DATE_SUB(NOW(), INTERVAL 31 DAY); 

DELETE FROM data USING data LEFT OUTER JOIN event USING (sid,cid) WHERE event.sid IS NULL; 
DELETE FROM iphdr USING iphdr LEFT OUTER JOIN event USING (sid,cid) WHERE event.sid IS NULL; 
DELETE FROM icmphdr USING icmphdr LEFT OUTER JOIN event USING (sid,cid) WHERE event.sid IS NULL; 
DELETE FROM tcphdr USING tcphdr LEFT OUTER JOIN event USING (sid,cid) WHERE event.sid IS NULL; 
DELETE FROM udphdr USING udphdr LEFT OUTER JOIN event USING (sid,cid) WHERE event.sid IS NULL; 
DELETE FROM opt USING opt LEFT OUTER JOIN event USING (sid,cid) WHERE event.sid IS NULL; 

どちらが速いのかわからないので、2つの間で前後に切り替えるが、現実はどちらも遅すぎるということです。

+1

「他の」テーブルの外部キーがメインテーブルにありますか? – Bohemian

+0

InnoDB? MyISAM?テーブル定義? –

+0

はい、外部キーがありますが、他のテーブルは同じ数の行を持ちます。 これらはMyISAMテーブルです。 –

答えて

0

削除時にカスケードするように外部キーを設定してください。そのため、トリガーを作成して関連するレコードを手動で結合および削除する必要はありません。例以下は

Mysql website

+0

私はMyISAMテーブルを使用していますが、InnoDBテーブルに変換すると、カスケード削除はトリガ削除より速くなりますか? –

+0

確かに、私はおそらくそれを排除しようとすると、パーティションのアプローチを試してみよう。 – Jack

+0

何が最も速く興味深い質問があるのか​​を教えてください。 – Jack

0

からカスケード削除

CREATE TABLE parent (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE) ENGINE=INNODB; 

例という関係を作成する方法を示しています私たちは、パーティションを作成し、落下して、このような問題を解決しました。 それでは、テーブルの日付でパーティションを作成します(ベストプラクティス - MySqlイベントを使用した自動化)。古いデータを削除する必要がある場合は、単にパーティションを削除してください。

+0

それは私が最も興味を持っているルートですが、私は6つの関連テーブルを管理する方法を知らない。他のテーブルには、分割するフィールドはありません。 –

0

削除する行のIDを削除する前に一時テーブルに保存する方法について説明します。

次に、あなたは小さな(ER)テーブルのid <>ヌルに入社idが= nullの大きなテーブルに参加するから、あなたのクリーンアップスクリプトを切り替えることができます。

+1

そして、MySQL 5.6+では、結合するパーティションを指定することができ、データを一時テーブルにコピーする必要がなくなります。 '... inner join the_big_table partition(partition_name)on ... ' – weirdan

+0

これは大幅に高速でしょうか?私は間違いなくこれを試すことができます。 –

0

私は二つのことをするだろう:

は、単純な削除

にLIMITを追加し、

ON DELETE CASCADE 

というより時間によって行の時間で離れてかじると他のテーブルの外部キーを定義します。

DELETE FROM event 
WHERE timestamp < DATE_SUB(NOW(), INTERVAL 31 DAY) 
LIMIT 500000 

影響を受けた行がないか、経験が必要であることが何回表示されるまで、再実行してください。

500000をクエリが死ぬことなく作成できるほど大きく調整します。

+0

私が見たところでは、 'ON DELETE CASCADE'はInnoDBテーブル上にしかありません。私はMyISAMテーブルを使用しています。私はチャンクで削除する方法について聞いたことがある。私はそれからパフォーマンスの向上を理解していない。どのように速く/より効率的ですか? –

+0

'event.cid'はインクリメンタルです(値は常に増加しています)? – Bohemian

+0

私はそうは思わない。必ずしも。 –

0
にスクリプトを変更し

:すべてのテーブル

  • は、イベントから
  • ではなく、古いすべてをターゲットを削除しようとしているcid値を取り込むためcidにインデックスがあることを確認

    • 行。ターゲット(、理にかなっているものは何でも、毎時間、毎日、5分ごとに言う)

    何か、それは

  • が頻繁にスクリプトを実行する比較的早く実行して、古い行の(小)最大量(まで)以下のように:

    CREATE TABLE IF NOT EXISTS deleted_cids(int cid); -- ensure same datatype as cid in tables 
    TRUNCATE deleted_cids; 
    INSERT INTO deleted_cids 
    SELECT cid FROM event 
    WHERE timestamp BETWEEN DATE_SUB('${OLDEST_TIMESTAMP}', INTERVAL 1 HOUR) 
        AND DATE_SUB(NOW(), INTERVAL 31 DAY) 
    LIMIT 100000; -- Choose largest LIMIT that gives acceptable execution time 
    DELETE event FROM deleted_cids, event WHERE event.cid = deleted_cids.cid; 
    DELETE data FROM deleted_cids, data WHERE data.cid = deleted_cids.cid; 
    DELETE iphdr FROM deleted_cids, iphdr WHERE iphdr.cid = deleted_cids.cid; 
    DELETE icmphdr FROM deleted_cids, icmphdr WHERE icmphdr.cid = deleted_cids.cid; 
    DELETE tcphdr FROM deleted_cids, tcphdr WHERE tcphdr.cid = deleted_cids.cid; 
    DELETE udphdr FROM deleted_cids, udphdr WHERE udphdr.cid = deleted_cids.cid; 
    DELETE opt FROM deleted_cids, opt WHERE opt.cid = deleted_cids.cid; 
    

    ここでの利点は、各削除がすべての対象行を削除するためにインデックスを付けベース、単一の実行であるということである - それはすぐに実行する必要があります。

    実行のLIMITと頻度を調整することで、サーバーの負荷が適切にバランスすることがわかります。私は少量の頻繁な実行を選ぶでしょう、あなたのサーバーは決してプロセスによって粉砕停止に持ち込まれません。