0

そのため、パフォーマンスに少し問題があります。データベースを構築する Java プログラムを作成しました。問題は、データをロードするときです。SQL データベースに 5,000 個のファイルを読み込んでいます。プログラムが開始されると、10 分間で約 10% のファイルを処理できますが、進行するにつれて速度が大幅に低下します。現在 28% で、現在の速度で 16 時間で終了します。ただし、その速度は大幅に低下しています。

私の質問は、プログラムが実行されるにつれてプログラムが徐々に遅くなるのはなぜですか、そしてそれを修正する方法です。

編集: 2 つのバージョンがあります。1 つはねじ山 (最大 5 スレッド) で、もう 1 つはねじ山ではありません。両者の違いはごくわずかです。誰かが好きなら、コードをもう一度投稿できますが、ボトルネックがMySQLであることがかなり確信で​​きるようになったので、取り出しました(適切に再タグ付けされました)。私は先に進み、バッチ挿入を使用しました。これにより、最初は速度が向上しましたが、データの約 30% を処理した後、すぐに速度が低下しました。

だからSQLポイント

  1. 64 個のテーブルすべてのエンジンは InnoDB バージョン 10 です。
  2. この時点で、テーブルには約 30 万行あります (データの約 30%)。
  3. すべてのテーブルには、1 つの「結合」主キーがあります。ID と日付。
  4. MySQL WorkBench を見ると、スレッドごとに 1 つのクエリ (5 つのクエリ) があることがわかります。
  5. 時間の単位はわかりませんが (MySQL 管理者から読み取っただけです)、ファイルが既に挿入されているかどうかを確認するためのクエリに 300 がかかっています。(このクエリは、MyTable Limit 1 to 1 の SELECT MyIndex であるため、高速である必要があります。プログラムを開始および停止しているため、このチェックを組み込み、ファイルが既に挿入されているかどうかを確認しました。そうすれば、変更のたびに開始して、プロセスを再度開始することなく、改善点があるかどうかを確認できます。
  6. パフォーマンスの低下がテーブルのサイズに関連していることは確かです。(今すぐプログラムを停止して開始できますが、プロセスは遅いままです。プロセスが許容できる速度で進行しているのは、テーブルが小さい場合のみです。)
  7. どうぞ、お尋ねください。あなたが必要とするあらゆる情報を掲載します。

終わり!まあ、必要な4日間実行させただけです。助けてくれてありがとう。

乾杯、

--オーラン

4

5 に答える 5

1

Q1: プログラムが徐々に遅くなるのはなぜですか?

問題空間では、相互作用する 2 つのシステムがあります。ファイル システムから読み取ってデータを生成するプロデューサーと、そのデータをレコードに変換してデータベースに保存するコンシューマーです。あなたのコードは現在、これら 2 つのプロセスをハード リンクしており、システムは 2 つの中で最も遅い速度で動作しています。

プログラムでは、固定の到着率があります (1/秒 - 10 を超えるスレッドを実行している場合の待機)。いっぱいになるテーブルにインデックスがある場合、テーブルが大きくなるにつれて、挿入に時間がかかります。つまり、到着率は 1/秒に固定されていますが、退出率は継続的に増加しています。したがって、同じ CPU/IO リソースを共有するスレッドをますます多く作成し、単位時間あたりの処理量を減らすことになります。スレッドの作成も非常にコストのかかる操作です。

Q2: 文字列からクエリを作成する方法に関係があるのでしょうか?

部分的にのみ。文字列操作は、システム内の固定コストです。1 つの要求を処理するのにかかるコストが増加します。ただし、文字列操作は CPU バウンドであり、問​​題は I/O バウンドです。つまり、文字列処理を改善しても (必要な場合)、システムのパフォーマンスはわずかしか改善されません。(アムダールの法則を参照)。

Q3: それを修正する方法 (パフォーマンスの問題)

  • ファイル リーダー プロセスを db 挿入プロセスから分離しますConsumer-Producerパターンを参照してください。JDK に組み込まれた実装については、Completion Serviceも参照してください。

(FileReaderProducer) --> キュー --> (DBBulkInsertConsumer)

  • 新しいスレッドを作成しないでください。上記の executor サービスや Completion サービスなど、java.util.concurrent パッケージによって提供される機能を使用します。「ベア」スレッドプールの場合は、Executorsファクトリを使用します。

  • この特定の問題では、2 つの個別のスレッド プール (コンシューマー用とプロデューサー用) を用意することで、システムを最適なパフォーマンスに調整できます。ファイルの読み取りは並列化によって (I/O バウンドまで) 改善されますが、db 挿入は (I/O + インデックス + リレーショナル整合性チェック) では改善されないため、ファイル読み取りスレッド (3-5) の量を制限する必要がある場合があります。挿入率 (2-3) と一致します。キューのサイズを監視して、システム パフォーマンスを評価できます。

  • JDBC 一括挿入を使用します: http://viralpatel.net/blogs/batch-insert-in-java-jdbc/
  • 文字列連結の代わりに StringBuilder を使用します。Java の文字列は不変です。つまり、次のことを行うたびに: myString += ","; 新しい文字列を作成し、古い文字列をガベージ コレクションの対象にします。これにより、ガベージ コレクションのパフォーマンスが低下します。
于 2012-06-14T11:05:43.320 に答える
1

ファイルからデータベースへの直接挿入を使用できます (こちらをお読みください)。それはより速く動作します。postgres で同じことを行うと、パフォーマンスが 20 倍向上します。

また、キットのプロファイラーをダウンロードして、アプリケーションのパフォーマンスをプロファイリングします。あなたがあなたの時間がかかるものを見るよりも。

于 2012-06-14T06:32:27.040 に答える
0

コードには速度の問題の原因となる可能性のあるものがいくつかあり、文字列が役割を果たしていると疑うのは正しいことです。

たとえば、次のコードを見てください。

文字列rowsString=""; //-(int i = 0; i <= numberOfRows-3; i ++){rowsString + = "(DATA)、\n";の末尾にコンマがない余分な1 } rowsString + = "(DATA)";

行数によっては、これは潜在的なボトルネックであり、メモリを大量に消費します。ここでStringBuilderを使用するのが最善だと思います。StringBuilderに適した文字列操作がたくさんあります。文字列の処理について少し読んで、特に+ =文字列の場合は、これらを最適化することをお勧めしますか?

次に、次の質問は、テーブルがどのように設計されているかです。varcharのデフォルトの長さが正しくない、インデックスがない、インデックスが多すぎるなど、挿入が遅くなる可能性があります。

于 2012-06-14T06:29:12.280 に答える
0

データベースへのアクセスを高速化するための、試行済みでテスト済みの優れたオプションがいくつかあります。

  1. ExecutorServiceスレッドに を使用します。これは速度的には役に立たないかもしれませんが、次のことを実装するのに役立ちます.
  2. ThreadLocal Connectionすべてのファイルに対して新しい接続を作成する代わりに、a を保持します。また、明らかに、それを閉じないでください。
  3. PreparedStatement毎回新しいものを作るのではなく、シングルを作成してください。
  4. ステートメントの実行をまとめます。
于 2012-06-14T13:34:57.297 に答える