私はシンプルなJavaアプリを毎週実行するように書いています。アプリはデータを取得して確認し、更新するためにデータベースを呼び出す必要があります。
私が必要とする流れは次のように少しです:
select configure,orgID where status=true from orgs;
_ orgs
には数千の行があり、configure
はblobですorgID
リストをフィルタリングしましたorgID
リストの場合、select * from users where status=true and orgID in (orglist)
users
は巨大なテーブルです。 orgID
ごとに、40万人のユーザーが存在する可能性があります。いくつか質問があります。
configure
を選択すると、このフィールドはblobであり、1kまで大きくなることがあります。一度に数千行を取得することは良い習慣ですか?または複数のdb呼び出しを行う方が良いですか?時間と空間、どちらがより重要ですか?
usersテーブルには数百万の行があるので、おそらく100万行に対して1列を更新する必要があります。この更新を行うための良い方法は何ですか? 100万dbを呼び出す方が良いですか?または可能な限り少ないdb呼び出し?
- 構成を選択すると、このフィールドはblobになり、1kまで大きくなる可能性があります。一度に数千行を取得することは良い習慣ですか?または複数のdb呼び出しを行う方が良いですか?時間と空間、どちらがより重要ですか?
これはアプリケーションに完全に依存しています。問題は、それがパフォーマンス要件を満たしているかどうかです。
週に1回実行される単純なアプリの場合、時間とメモリの使用はおそらくそれほど重要ではありません。最初に単純なバージョン(1つのクエリで一度にすべて取得する)を記述します。正常に動作する限り、心配する必要はありません。そして、1000倍の数千はおそらく問題を引き起こさないでしょう。
パフォーマンスの問題が発生した場合にのみ、複数のDB呼び出しを使用するように変更する必要があります。
- usersテーブルには数百万の行があるので、おそらく100万行に対して1列を更新する必要があります。この更新を行うための良い方法は何ですか? 100万dbを呼び出す方が良いですか?または可能な限り少ないdb呼び出し?
上記のように、パフォーマンス要件がそのような決定を推進するはずです。ただし、この場合、数百万のDB呼び出しを行うと問題が発生する可能性が高くなります。さらに、一度に多くの行を変更する単一の更新は、通常、簡単に書き込むことができます。
したがって、すべてを更新する単一の更新ステートメント、またはorgID
ごとに最大1つの更新ステートメントを目指します。
構成を選択すると、このフィールドはblobになり、1kまで大きくなる可能性があります。一度に数千行を取得することは良い習慣ですか?
これにはいくつかの層があります。 DBから大量の行セットを選択しても、実際には巨大なバイトの塊は送信されません。何が起こるかというと、設定可能なサイズのカーソルがDBにあるということです。したがって、カーソルサイズが1000行の場合、すべての行を一度に取得することはできません。この回答で後述することを除いて、通常はこのことを心配する必要はありません。
ただし、この他の側面は、行で何をするかです。それらすべてをアプリケーションのリストに入れる場合(これはORMで行うことです)、これらのすべてのレコードにスペースを割り当てる必要があります。私はこのアプローチが嫌いです。これは、肥大化したJavaプログラムの最も一般的な原因です。実際には、データベース接続からのレコードをイテレータとしてループする必要があります。
または複数のdb呼び出しを行う方が良いですか?
これは、以下で説明する同時実行の考慮事項によって異なります。
時間と空間、どちらがより重要ですか?
時空間トレードオフ分析は、アルゴリズムが複雑な場合に適用されるものです。これは、それらのケースの1つではないようです。実行しているのが1つの行の読み取りと更新の書き込みだけの場合、より多くのメモリを使用しても速度は向上しません。実際、それはおそらくあなたのプログラムを遅くします。メモリの割り当てと管理には時間がかかります。次のタスクを実行するために必要な以上のメモリを割り当てようとしません。
usersテーブルには数百万の行があるので、おそらく100万行に対して1列を更新する必要があります。この更新を行うための良い方法は何ですか? 100万dbを呼び出す方が良いですか?または可能な限り少ないdb呼び出し?
ここでは、各行を調べて、ワンショットSQLステートメントでは簡単に実行できない更新を行う必要があると想定しています。この質問に対する単純な答えはありません。これは、これを行っている間にこれらのテーブルと対話する他のアプリケーションがあるかどうかに依存するためです。
'select for update'を実行している場合、おそらくこれを1つの大きなコミットで実行したくないでしょう。これを使用する理由は、他のアプリケーションが選択と更新の間でデータを変更できないようにするためです。言い換えると、これらのすべてのレコードを期間ロックします。
同時実行やダーティリードについて心配していなくても、次の理由により、100万件のレコードを変更して最後にコミットしたくない場合があります。
したがって、コミットのパフォーマンスにはスイートスポットがあります。あなたはそれぞれをコミットし、少しのオーバーヘッドがあります。それらをバッチでコミットすることもできますが、再試行は少し複雑になります。個人的には、パフォーマンスの懸念があることを知らない限り、おそらくそれぞれの変更をすぐにコミットするでしょう。正しく理解するのが最も簡単です。 100万件のレコードは、実際にはそれほど多くありません。また、1Kはそれほど多くのデータではありません。 Oracleは、特に指示しない限り、1Kをテーブル外に置くことさえありません。
ここにはおそらく先制的なマイクロ最適化の一部があるでしょうが、私はここでいくつかの一般的なポイントに取り組むことができると思います。
現実的なテストを準備する
ただし、できることはたくさんあるので、最初から始めましょう。
メモリ不足ですか?
データとBLOBのサイズを考慮すると、おそらくメモリエラーが発生します。この点は StackOverflow で対処されています。
JPAのORMまたはEntityManagerを使用する場合は、未加工のJDBC操作用に変更することを検討できます。それ以外の場合は、メソッドflush
を使用してキャッシュをフラッシュすることを忘れないでください。
データベース呼び出し
複数のネットワーク呼び出しは、簡単にボトルネックになる可能性があります。完全な結合は、データベースにも多くのコストがかかる可能性があります。 orgID in (orglist)
を使用してすべてのユーザーをフェッチする代わりに、orgID
ごとに1つのクエリを実行することを選択できます。 10000の異なるorgIDがない限り、これのコストは何もありません。もちろん、あなたはあなたのメモリの量が続くことを確認する必要があります。
マルチスレッド
次の要件がallを満たしている場合は、これを考慮してくださいonly:
将来に備えて
時間枠が最大5時間程度であり、データベースが10年間成長して存続すると予想される場合は、次のいずれかを選択できます。
ベンチマーク
はい、すでに言ったが、忘れないように、パフォーマンスを改善するためのすべての変更は、コードの複雑さを増す可能性が高い。
各設計/コードの変更をベンチマークで検証し、行ったことが実際の影響を与えたことを確認します。