0

基本的に私の問題は、大量の更新を非常に迅速に適用する必要がある約 17,000,000 製品の大きなテーブルがあることです。

テーブルには、int(10) AUTO_INCREMENT として設定された ID を持つ 30 の列があります。

このテーブルのすべての更新が保存されている別のテーブルがあります。これらの更新は、計算に数日かかるため、事前に計算する必要があります。このテーブルは [ product_id int(10), update_value int(10) ] の形式です。

これらの 1,700 万件の更新を迅速に発行するために私が取っている戦略は、これらすべての更新を Ruby スクリプトでメモリにロードし、それらを配列のハッシュにグループ化して、各 update_value がキーになり、各配列がソートされた product_id のリストになるようにすることです。 .

{ 
   150: => [1,2,3,4,5,6],
   160: => [7,8,9,10]
}

その後、更新は次の形式で発行されます。

UPDATE product SET update_value = 150 WHERE product_id IN (1,2,3,4,5,6);
UPDATE product SET update_value = 160 WHERE product_id IN (7,8,9,10);

product_id のソートされたバッチで更新を発行することが、mysql / innodb でそれを行う最適な方法であるという意味で、これを正しく行っていると確信しています。

奇妙な問題が発生しましたが、約 1,300 万件のレコードを更新してテストしていたところ、約 45 分しかかかりませんでした。現在、1,700 万レコードまでのより多くのデータでテストしており、更新には 120 分近くかかっています。ここでは何らかの速度低下が予想されますが、私が見ている程度ではありません。

どうすればこれをスピードアップできるか、またはこのより大きな記録セットで何が遅くなる可能性があるかについてのアドバイスはありますか?

サーバーの仕様に関する限り、メモリ/CPUのヒープはかなり優れており、DB全体がメモリに収まり、成長する余地が十分にあります。

4

2 に答える 2

0

mysql の複数テーブル更新構文を使用してみてください。

update product, sometable SET product.update_value=sometable.value WHERE product_id=sometable.whatever;

そうすれば、データベースを介した単一のパスと、mysql が処理できる単一の大きなクエリになります。

于 2012-10-30T20:57:36.877 に答える
0

インデックスとデータ ページへのアクセスを慎重に設計する必要があると思います。

クエリでの s の分布がランダムであると仮定するとproduct_id、更新 SQL ごとにランダムなインデックス ページ アクセスが発生します。もちろん、インデックスページアクセスに続くデータページアクセスもランダムです。すべての更新をすばやく実行したい場合は、すべてのインデックス ページを (少なくとも) メモリ内に保持する必要があります。したがって、これは更新操作の高速なセットではありません。

私がそれを設計していて、更新がトランザクションである必要がない場合は、トランザクションではなく、次のように product_ids ごとにすべての行を 1 つずつ更新します。

UPDATE product SET update_value = 150 WHERE product_id = 1
UPDATE product SET update_value = 150 WHERE product_id = 2
...

インデックス ページとデータ ページの両方が順次読み取り/更新されるため、このスキームは更新に時間がかかる可能性がありますが、キャッシュ管理の観点からははるかに安価です。もちろん、データベースへの全体的な影響は最小限であるため、更新以外の操作 (顧客からのクエリなど) は低下しません。

トランザクション操作が必要な場合は、おそらく 2 つのテーブルを使用するか、いくつかのトリックを使用して 2 つの論理テーブルを 1 つのテーブルにすることをお勧めします。しかし、トランザクショナルである必要がない場合は、遅い更新が適しproduct_idています。

于 2012-10-30T21:20:34.033 に答える