2

OracleやSQL Serverなど、SQLデータベースで集計関数がどのように実装されているか教えてください。

つまり、select 句に集計関数が存在する場合、これらのデータベースは何らかの内部データ構造またはアルゴリズムを使用しますか。

私がこれを求めている理由は、Java ArrayList に 100,000 レコードがあり、すべての値の合計を計算しようとすると約 1 分かかりますが、同じ 100,000 レコードが DB に格納されていて、sum(column_nm) を使用する場合です。ほぼ 1/4 の時間で実行されます。

同様の方法でJavaコードのパフォーマンスを改善したいので、SQL集計関数の内部を知りたいです。

ありがとう。

4

5 に答える 5

2

これは、内部で定義された集計のしくみと完全には一致しませんが、SQL Server ではユーザー定義の集計を作成できます。そのような集約が定義しなければならないメソッドを確認することは有益かもしれません:

  • Init:

クエリ プロセッサは、このメソッドを使用して集計の計算を初期化します。このメソッドは、クエリ プロセッサが集計しているグループごとに 1 回呼び出されます。クエリ プロセッサは、複数のグループの集計を計算するために、集計クラスの同じインスタンスを再利用することを選択できます。Init メソッドは、このインスタンスの以前の使用から必要に応じてクリーンアップを実行し、新しい集計計算を再開できるようにする必要があります。

  • Accumulate:

... クエリ プロセッサは、このメソッドを使用して集計値を累積します。これは、集計中のグループ内の値ごとに 1 回呼び出されます。クエリ プロセッサは、aggregate-class の特定のインスタンスで Init メソッドを呼び出した後にのみ、常にこれを呼び出します。このメソッドの実装では、インスタンスの状態を更新して、渡される引数値の累積を反映する必要があります。

  • Merge:

このメソッドを使用して、この集約クラスの別のインスタンスを現在のインスタンスとマージできます。クエリ プロセッサは、このメソッドを使用して、集計の複数の部分的な計算をマージします。

  • Terminate:

このメソッドは集計計算を完了し、集計の結果を返します。...

Mergeおよびの説明からTerminate、サーバーが 1 つのグループ内で複数の部分集計を並行して実行している可能性があると推測できます。これらの並列累積がそれぞれ発生すると、クラスの 1 つのインスタンスに対する最終的な呼び出しが最終的な集計結果を生成するMerge前に、すべての結果がまとめられます。Terminate

したがって、(可能であれば) 高速化を実現する 1 つの明白な方法は、累積ステージを並列化することです。

于 2013-02-26T07:39:48.940 に答える
2

Javaコードが非常に遅い理由は、非常に簡単な説明です。

あなたはArrayListを使用しているので、そこに整数オブジェクトを入れていると思います。一部のスタックでは、C の int に対してかなりのオーバーヘッドがあります。次に、それらを合計し、部分合計ごとに別の整数を作成すると、GarbageCollector がすべてのパフォーマンスを消費します。

他の回答で述べたように、

  1. DB は直接数学プロセッサ アクセスを使用して int をレジスタに追加します - 高速にはなりません。
  2. 優れた DB は反復するだけでなく、合計、最小、最大などの集計をマップ + 削減します。したがって、マルチプロセッサの利点が得られ、I/O レイテンシはほとんど無視されます。

コードで解決するには: int[] を使用します。

 int[] parts;
 sum=0;
 for (int i:parts) {
   sum+=i;
 }

プロセッサ数に応じて配列を分割 (マッピング) し、これを Future で並列化することが役立つかどうかをテストすることをお勧めします - データのサイズによって異なります。

于 2013-02-26T10:12:21.467 に答える
1

パフォーマンスの違いは単純に、SUM を計算するためにすべてのデータを同時にメモリに格納する必要がないためです。

SUM を求めるクエリをデータベースに直接発行すると、ディスクから各レコードを読み取り、現在の合計をメモリ内の 1 つの変数に累積してから、次のレコードを読み取ることができます。すべてのレコードをメモリ内に保持する必要はありません。同時に。さらに重要なことは、これらのレコードを処理のためにネットワーク経由で他のサーバーに送信する必要がないことです。結果の SUM を最後に単一の数値として送信するだけで済みます。

さらに、全体の SUM は全体の個別のサブセットの SUM に等しいため、SUM は並列化できます。たとえば、データが分割されている場合、データベースは複数のクエリを発行して異なるセッションで実行できます。データのその部分を合計すると、制御セッションは各パーティションの結果を単純に合計できます。

Java プログラムで配列を使用して合計を計算する場合、最初にデータベースにクエリを発行して、必要なすべてのデータを要求する必要があります。すべてのデータをデータベースからアプリ サーバーに転送する必要があり、そのすべてのデータを格納するためにメモリを割り当てる必要があります。その後、プログラムはメモリ内の配列を反復処理し、Sum を計算します。次に、おそらくメモリから配列を解放する必要があります。

データの量が少ない場合、パフォーマンスの違いはおそらく重要ではありません。ただし、ボリュームが大きい場合、その差は非常に大きいと予想できます。

于 2013-02-26T08:22:28.670 に答える
0

興味深い質問です。

よく書かれたrdbmsは、博士課程の数学者とデータベースの達人の何千時間もの労働時間の集大成です。MSSQLまたはpostgressqlのパフォーマンスを模倣する試みは称賛に値しますが、風車では傾いています(ドン・キホーテに精通していない場合は無駄に読んでください)。

rdbmsに関する一般的な誤解は、リレーショナルは関連するテーブルを意味するということです。関連とは、実際には数学的関係を指します。基本的に-rdbmsは集合論に焦点を当てています。優れたrdbmsを使用している場合でも、開発者は、固有のネイティブセットを使用する代わりに、行ごとに計算することでパフォーマンスを損なう可能性があります。これは実際には、発生しているパフォーマンスの違いを適切に比較したものです。

この計算をdbではなくjavaで行うことに制限されている場合は、データ構造(最小のデータ型)とループ効率の最適化を検討する必要があります。それでも、SQLServerやPostgresと競合することはできません。パフォーマンスの向上が本当に必要な場合は、アイテムをデータベースに保存し、Javaから呼び出す価値があるかもしれません。

于 2013-02-26T09:34:20.500 に答える
0

集計は通常、結果セットを反復するだけで、合計、平均、カウントなどの集計を実行します。

操作の複雑さについて話している場合、ほとんど常に O(n) です。ここで、n は単純な集計の結果セット内のレコード数です。

RDBMSのようにディスクから読み取るよりも高速なメインメモリに配列がインスタンス化されるため、Javaで行うのに時間がかかる理由がわかりません。正直なところ、RDBMS からの集計は、arraylist 集計よりもわずかに遅くなるはずです。

これを拡張すると、特定のエントリ (PK またはインデックス付き) に対して 1 つの行が必要な場合、配列リストの場合は O(1)、適切なインデックスを持つ RDBMS の場合は O(1) (標準のリンクリストの場合) になります。 、その行を取得するには o(n) になりますが、集計の arraylist と同じです)。データセット全体 (配列であろうとテーブルであろうと) を反復処理し、集計を実行すると、ほぼ常に O(n) になります。

于 2013-02-26T05:54:51.570 に答える