web-dev-qa-db-ja.com

Javaアプリケーション-より重要なデータベース呼び出しとスペースと時間を最適化する方法は?

私はシンプルなJavaアプリを毎週実行するように書いています。アプリはデータを取得して確認し、更新するためにデータベースを呼び出す必要があります。

私が必要とする流れは次のように少しです:

  • _select configure,orgID where status=true from orgs;_
    • orgsには数千の行があり、configureはblobです
  • Blobオブジェクトの設定を確認し、orgIDリストをフィルタリングしました
  • フィルタリングされたorgIDリストの場合、select * from users where status=true and orgID in (orglist)
    • usersは巨大なテーブルです。 orgIDごとに、40万人のユーザーが存在する可能性があります。
  • ユーザー情報については、これらすべてのユーザーの1つの列を更新します

いくつか質問があります。

  1. configureを選択すると、このフィールドはblobであり、1kまで大きくなることがあります。一度に数千行を取得することは良い習慣ですか?または複数のdb呼び出しを行う方が良いですか?時間と空間、どちらがより重要ですか?

  2. usersテーブルには数百万の行があるので、おそらく100万行に対して1列を更新する必要があります。この更新を行うための良い方法は何ですか? 100万dbを呼び出す方が良いですか?または可能な限り少ないdb呼び出し?

2
c2340878
  1. 構成を選択すると、このフィールドはblobになり、1kまで大きくなる可能性があります。一度に数千行を取得することは良い習慣ですか?または複数のdb呼び出しを行う方が良いですか?時間と空間、どちらがより重要ですか?

これはアプリケーションに完全に依存しています。問題は、それがパフォーマンス要件を満たしているかどうかです。

週に1回実行される単純なアプリの場合、時間とメモリの使用はおそらくそれほど重要ではありません。最初に単純なバージョン(1つのクエリで一度にすべて取得する)を記述します。正常に動作する限り、心配する必要はありません。そして、1000倍の数千はおそらく問題を引き起こさないでしょう。

パフォーマンスの問題が発生した場合にのみ、複数のDB呼び出しを使用するように変更する必要があります。

  1. usersテーブルには数百万の行があるので、おそらく100万行に対して1列を更新する必要があります。この更新を行うための良い方法は何ですか? 100万dbを呼び出す方が良いですか?または可能な限り少ないdb呼び出し?

上記のように、パフォーマンス要件がそのような決定を推進するはずです。ただし、この場合、数百万のDB呼び出しを行うと問題が発生する可能性が高くなります。さらに、一度に多くの行を変更する単一の更新は、通常、簡単に書き込むことができます。

したがって、すべてを更新する単一の更新ステートメント、またはorgIDごとに最大1つの更新ステートメントを目指します。

1
user82096

構成を選択すると、このフィールドはblobになり、1kまで大きくなる可能性があります。一度に数千行を取得することは良い習慣ですか?

これにはいくつかの層があります。 DBから大量の行セットを選択しても、実際には巨大なバイトの塊は送信されません。何が起こるかというと、設定可能なサイズのカーソルがDBにあるということです。したがって、カーソルサイズが1000行の場合、すべての行を一度に取得することはできません。この回答で後述することを除いて、通常はこのことを心配する必要はありません。

ただし、この他の側面は、行で何をするかです。それらすべてをアプリケーションのリストに入れる場合(これはORMで行うことです)、これらのすべてのレコードにスペースを割り当てる必要があります。私はこのアプローチが嫌いです。これは、肥大化したJavaプログラムの最も一般的な原因です。実際には、データベース接続からのレコードをイテレータとしてループする必要があります。

または複数のdb呼び出しを行う方が良いですか?

これは、以下で説明する同時実行の考慮事項によって異なります。

時間と空間、どちらがより重要ですか?

時空間トレードオフ分析は、アルゴリズムが複雑な場合に適用されるものです。これは、それらのケースの1つではないようです。実行しているのが1つの行の読み取りと更新の書き込みだけの場合、より多くのメモリを使用しても速度は向上しません。実際、それはおそらくあなたのプログラムを遅くします。メモリの割り当てと管理には時間がかかります。次のタスクを実行するために必要な以上のメモリを割り当てようとしません。

usersテーブルには数百万の行があるので、おそらく100万行に対して1列を更新する必要があります。この更新を行うための良い方法は何ですか? 100万dbを呼び出す方が良いですか?または可能な限り少ないdb呼び出し?

ここでは、各行を調べて、ワンショットSQLステートメントでは簡単に実行できない更新を行う必要があると想定しています。この質問に対する単純な答えはありません。これは、これを行っている間にこれらのテーブルと対話する他のアプリケーションがあるかどうかに依存するためです。

'select for update'を実行している場合、おそらくこれを1つの大きなコミットで実行したくないでしょう。これを使用する理由は、他のアプリケーションが選択と更新の間でデータを変更できないようにするためです。言い換えると、これらのすべてのレコードを期間ロックします。

同時実行やダーティリードについて心配していなくても、次の理由により、100万件のレコードを変更して最後にコミットしたくない場合があります。

  1. このプロセスのいずれかの時点で問題が発生した場合は、マイナーな問題であっても、最初からやり直す必要があります。
  2. コミットされていない大量の変更をDBに書き込むと、DBのリソースに大きな負荷がかかります。

したがって、コミットのパフォーマンスにはスイートスポットがあります。あなたはそれぞれをコミットし、少しのオーバーヘッドがあります。それらをバッチでコミットすることもできますが、再試行は少し複雑になります。個人的には、パフォーマンスの懸念があることを知らない限り、おそらくそれぞれの変更をすぐにコミットするでしょう。正しく理解するのが最も簡単です。 100万件のレコードは、実際にはそれほど多くありません。また、1Kはそれほど多くのデータではありません。 Oracleは、特に指示しない限り、1Kをテーブル外に置くことさえありません。

0
JimmyJames

ここにはおそらく先制的なマイクロ最適化の一部があるでしょうが、私はここでいくつかの一般的なポイントに取り組むことができると思います。

現実的なテストを準備する

ただし、できることはたくさんあるので、最初から始めましょう。

  1. これは毎週の操作なので、すぐに実行する必要はありません。時間実行の現実的なウィンドウを定義する
  2. 現実的なテストデータを作成する(または、真のテストデータを入手できる場合はさらに優れています)
  3. 基準。
  4. テストデータのサイズを変更して、時間の複雑さを大まかに見積もることができます。

メモリ不足ですか?

データとBLOBのサイズを考慮すると、おそらくメモリエラーが発生します。この点は StackOverflow で対処されています。

JPAのORMまたはEntityManagerを使用する場合は、未加工のJDBC操作用に変更することを検討できます。それ以外の場合は、メソッドflushを使用してキャッシュをフラッシュすることを忘れないでください。

データベース呼び出し

複数のネットワーク呼び出しは、簡単にボトルネックになる可能性があります。完全な結合は、データベースにも多くのコストがかかる可能性があります。 orgID in (orglist)を使用してすべてのユーザーをフェッチする代わりに、orgIDごとに1つのクエリを実行することを選択できます。 10000の異なるorgIDがない限り、これのコストは何もありません。もちろん、あなたはあなたのメモリの量が続くことを確認する必要があります。

マルチスレッド

次の要件がallを満たしている場合は、これを考慮してくださいonly

  • Javaでデータを処理して結果を計算するには、プロセス全体でかなりの時間がかかります。
  • 単一のトランザクションで実行するために、これらすべてが必要なわけではありません。
  • プロセスを分割して、各行が複数のスレッドによってロックされないようにすることができます(たとえば、スレッドごとに1/10のorgID)。レガシー環境を扱っている場合を除き、データベースが行レベルのロックを適切に適用することを確認してください。この点は問題ありません。 **
  • いくつかのマイクロ最適化が保守の面で本当に醜いのでない限り...、あなたはほとんど選択肢を失っています。

将来に備えて

時間枠が最大5時間程度であり、データベースが10年間成長して存続すると予想される場合は、次のいずれかを選択できます。

  1. 予想されるデータ量を見積もることにより、これが10年後でも適切に機能する可能性が高いことを確認してください。
  2. このコードを再処理する必要があるとき(またはデータ量が多い場合)を見積もり、またはウィンドウ時間を増やす。

ベンチマーク

はい、すでに言ったが、忘れないように、パフォーマンスを改善するためのすべての変更は、コードの複雑さを増す可能性が高い。

各設計/コードの変更をベンチマークで検証し、行ったことが実際の影響を与えたことを確認します。

0
Walfrat