2017-04-20 1 views
1

25 GBの大きなテーブルを更新する方法、MyISAMの350,000,000以上のレコード? すべてのレコードについて、timeフィールドにランダムな日付を設定する必要があります。負荷のないサーバーでは、コマンドが実行されました:25 GBの大きなテーブルを更新する方法、MyISAMの350万以上のレコード?

UPDATE table SET time = FROM_UNIXTIME(1451595600 + FLOOR((RAND() * 31536000))) 

mysqldがプロセッサをロードし、RAMの多くを取り上げ、午前中にサーバーへの負荷は最小限ですが、クエリがすべてのより多くの、実行されます55時間が経過しました。

enter image description here

私は何が起こっているかを理解することはできません!

CREATE TABLE `table` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `job_id` int(10) unsigned NOT NULL, 
    `lock` mediumint(6) unsigned DEFAULT '0', 
    `time` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `job_id` (`job_id`), 
    KEY `lock` (`lock`), 
    KEY `time` (`time`) 
) ENGINE=MyISAM; 

ADD:解決しよう

[email protected]:~ # iostat -p md1 60 5 

enter image description here

私は、更新プロセスを中断。主除く

削除インデックス:

MariaDB [base]> ALTER TABLE `table` DROP INDEX `job_id`, DROP INDEX `lock`, DROP INDEX `time`; 
Query OK, 339468609 rows affected (1 hour 3 min 28.89 sec) 
Records: 339468609 Duplicates: 0 Warnings: 0 

アップデート `time`フィールド:

MariaDB [base]> UPDATE `table` SET `time` = FROM_UNIXTIME(1451595600 + FLOOR((RAND() * 31539599))); 
Query OK, 339468609 rows affected (16 min 8.09 sec) 
Rows matched: 339468609 Changed: 339468609 Warnings: 0 

追加インデックス:

MariaDB [base]> ALTER TABLE `table` ADD INDEX (`job_id`), ADD INDEX (`lock`), ADD INDEX (`time`); 
Query OK, 339468609 rows affected (2 hours 18 min 58.32 sec) 
Records: 339468609 Duplicates: 0 Warnings: 0 

合計更新時間:3時間38分35.3秒

+0

申し訳ありませんが、あなたの質問は分かりません。正確にしてください:_has_クエリが正しく終了しましたか?列が更新されたかどうか – arkascha

+0

そのテーブルにはどのようなインデックスが存在するのかが重要です。質問にテーブルとインデックスの作成に関する情報を追加してください。 – arkascha

+0

テーブルはまだ更新されていますが、私はそれが長いことを心配しています。そして、この時間の大部分はサーバにロードされていません – Dmitry

答えて

2

まず、 そのテーブルのすべてのインデックスを削除してください。また、は、外部キー制約があれば削除します。その後、火災更新クエリ。更新が完了したら、すべてのインデックスと制約を再度作成します

すべてのインデックスと制約の作成には時間がかかりますが、テーブルを直接更新する場合に比べてはるかに少なくなります。

+0

誰がこの回答を投票し、なぜですか?これは必ずしも質問に対する答えではないかもしれませんが、ヒントは確かに意味があります! – arkascha

+0

(1)MyISAMはFKをサポートしていません。 (2)すべてのインデックスを削除することは過度です。 –

+0

私は更新プロセスを中断しました。プライマリ以外のインデックスを削除し、\ 'time \'フィールドを更新し、インデックスを追加します。合計更新時間:3時間38分35.3秒 – Dmitry

0

ここには何が起こっているのですか...

各レコードは最初は13バイトでした。行を更新すると、17バイト(古いバージョンのMySQL)または18バイト(新しいバージョン)になります。

これは、更新された行は単純に古い行を置き換えることはできませんが、別の場所に配置してから古い領域を解放する必要があることを意味します。そのような最初の更新は、テーブルの最後に移動します。または、古い領域から13〜6バイトを使用し、新しい行の残りの部分を置く場所へのリンクを置きます。

2番目の行は同様に乱雑です。

したがって、操作はテーブル内で境界をつけており、データはかなり断片化しています。

timeのインデックスも(key_bufferを使用して)再構築されています。それは「ランダム」なので、インデックスBTreeへの更新はランダムです。key_bufferが十分に大きくなければ、そのために多くのI/Oがあります。この特定の態様は、そのインデックスをあらかじめ指し示しておき、その後にそれを再追加することにより、高速化することができる。DROPping。悲しいことに、DROPADDの両方が遅くなりますが、インデックスの増分ビルディングほど遅くはありません。

あなたは本当にInnoDBに移動する必要があります。InnoDBは、データの更新とインデックスの更新の両方を全く異なる方法で行い、より効率的に変更します。 1つの注意:テーブル+インデックスは、MyISAMの2〜3倍のディスクスペースを消費します。

本当に4つのインデックスがすべて必要ですか?

MyISAMでは、key_buffer_sizeの値が重要です。 InnoDBの場合、innodb_buffer_pool_size

関連する問題