結合を行う場所-データベースサーバーまたはアプリケーションサーバー

StackOverflow https://stackoverflow.com/questions/633211

質問

現在、パフォーマンスの問題に直面しています(後でスケーリングの問題につながる可能性があります)。私が取り組んでいるアプリケーションは非常に複雑で、SQL Server 2005で実行されています。目的のデータを取得するには、6〜7個のテーブルを結合する必要があります。各テーブルには、これまでに100,000行を超えるデータが含まれています。データベーススキーマは変更できません(そのままにしておく必要があります)。そのため、可能な限り最適化することしかできません。 2つのことが思い浮かびます:

  • データベースに参加せず、LINQを使用してアプリケーションサーバーにフィルタリングを実行させます。

    • 長所:アプリサーバーを追加することで簡単に拡張できます。
    • 短所:より多くの努力。応答性が低下するかどうかはわかりません。
  • アプリケーションサーバーはそのままで、可能な限りSQLクエリを最適化しようとします(インデックスの追加、インデックスの頻繁な再構築など):

    • 長所:最小限の労力
    • 短所:テーブルのレコードが大きくなると、問題が再発します

基本的にキャッシングは現時点では私にとって解決策ではありません(ハードウェアの問題、ホスティングの問題など)。そのため、最初はキャッシュを作成しませんでした。しかし、私はキャッシングの利点が私にもたらすものを知っており、何度も使ってきました。

役に立ちましたか?

解決

一般的に、DBMSで結合を行います。アプリケーションサーバーでそれを行う場合、DBMSを書いた人よりも結合を最適化するより良い仕事をすることができ、(さらに)あなたのコストを相殺するのに十分なだけ彼らの最善の努力をアウトパフォームできることを賭けています結合されていないデータをネットワーク経由で転送します。

ここで、2つの幅の広いテーブルのクロス積(幅がW1のN1行と幅がW2のN2行のT1とする)のクロス積を行う場合、DBMSはN1 * N2 *(W1 + W2)バイトのデータを作成し、ネットワーク経由で送信する必要がありましたが、N1 * W1 + N2 * W2バイトのデータとして個別にテーブルを削除することもできます。 N1 = N2 = 1MおよびW1 = W2 = 100の場合、200 TB対200 MBのデータ転送が行われ、アプリサーバーでクロスプロダクトが実行されます。しかし、それはDBMSにとって正確ではありません。ほとんどのクエリはばかげているわけではありません。列で結合し、条件を適用します。DBMSオプティマイザーは、作業を最小限に抑えるために強力に(そして自動的に)苦労します。さらに、適切なデータのみが送信されます。条件に一致しないすべての行を送信する必要はありません。

(DBMSに有利な)代替シナリオを示すために、T1には幅W1 = 100のN1 = 1M行があり、T2には幅W2 = 50のN2 = 100K行がある場合を考えます。整数列に2つのテーブルがあるため、T2の各オンに対してT1に10行あります。 T1とT2のすべてをアプリサーバーに吸い込むと仮定します。これには、N1 * W1 + N2 * W2 = 105 MBのデータが必要です。ただし、フィルター条件はデータをT2の行の1/10に制限し、T2の行に一致するT1の各行には、実際にはフィルター条件に一致する行は2つしかありません。これで、DBMSは転送のみを行います N2 *(W1 + W2)/ 5 = 3 MB、DBMSによるデータ転送の100 MB以上の節約。ここで、賢く管理して、T2の値に対応するN2 * W2 / 10 = 500 KBのデータのみをダウンロードする場合、値に対してT1の「半結合」を実行するようにDBMSを取得する必要がありますT1からアプリサーバーに適切な行を取得する必要があります。列のサブセットのみが必要な場合は、別の節約方法があります。また、DBMSはかなり巧妙なソートパッケージを使用する傾向があります。データを正しい順序で表示するには、アプリサーバーに適切な並べ替えパッケージが必要です。

通常、DBMSでの結合にとっては、手に負えない勝ちです。そうでない場合は、サーバーが処理できる以上の作業をサーバーに要求しているためです。その場合は、データベースサーバーの複製が意味をなすかどうか、コアを追加するか、ネットワーク帯域幅を追加するか、メインメモリを追加することでジョブが実行されるかどうかを調べる必要があります。

他のヒント

一般的に、スケールについて話すときはいくつかの点を考慮します:

  1. どのくらいの頻度で実行されますか?アクセス頻度の低いクエリについては、パフォーマンスの低下を受け入れることができる場合があります。

  2. 成長/変化の速度はどのくらいですか?これらのテーブルの一部でレコードが比較的静的である場合、dbmタイプのファイル(またはWindowsの同等のもの)にコンテンツを外部的にキャッシュすることを検討する必要があります。 memcacheのようなものもあります。ただし、これは可能である場合とできない場合があります。これは、「結合」の実行に基づいています。アプリケーションコードで。

  3. プロファイル。インデックス付きの列に参加している場合(そうですね?)、行の数が増えても必ずしも低下するわけではありません。これは、1:1または1:Nの関係を処理しているかどうか、Nの平均サイズ、データベースサーバーで使用可能なメモリ量、処理方法に非常に依存します多くの場合、テーブル統計が計算され、列とインデックスのタイプが計算されます。 1:1の関係を処理していて、それが一意である場合、データベースは単純なハッシュを実行して検索できるようになります。

2つのテーブルを結合するために必要なのがすべてインデックス付きの列である場合、データベースはテーブルを考慮しないこともあるため、フェッチされる列を必要以上に絶対に制限しないようにしてください。まったく;インデックスのみを使用して結合を実行できます。これにより、競合が減少し、テーブルをプルするクエリが少なくなるため、テーブルの実際のコンテンツを処理する必要がある最適度の低いクエリのパフォーマンスが向上します。

すべてのリレーショナルデータベースには、特定のクエリのクエリ実行プランを表示するツールまたは機能があります。これを使って。出力が意味をなさない場合は、学習してください。これは、データベースが特定のクエリで何をするか、どのインデックスが使用されるか、各実行ステップで遭遇する推定(または実際の)行数、およびその他の楽しいことを理解するための主要なウィンドウです。

クエリオプティマイザーが実際にクエリで実行していることに関する情報を取得し、すべてのインデックス/統計情報/列の選択をまっすぐにすると、そこからどこに進むべきかがよくわかります。データベースでできることをすべて実行する場合、データのキャッシュの使用や、より具体的でより良いwhere句を使用して、より少ないテーブルに移動することなどを行う必要があります。

免責事項:SQL Serverを直接使用した経験はありませんが、他のRDBMS(Oracle、MySQL、PostgreSQLなど)および一般的なアーキテクチャについて多くの経験があります。

どのインデックスがすでに配置されているか、それら(および統計)が最新かどうか、および新しいインデックスがクエリワークロードに役立つかどうかを調べる必要があります。

「参加しない」でさらにサーバーを追加することにより、結合を最適化しようとすると、パフォーマンスがさらに向上します。そのとおりです。データが増えると問題が再発します。

最善の解決策は、メモリキャッシュを使用することです。主にサイズが小さく、常にフェッチしないテーブルとテーブルの関係をキャッシュできます。

最適なのは、結合を最小化し、選択を最小化し、ほとんど変更されていないデータをメモリにキャッシュすることです。それが後押しとなります。

Microsoft(および他のDBメーカー)による結合に関する推奨事項-可能な限り最適に使用します。私の経験から-複雑な選択の場合、上位2〜3を超える結合。

各テーブルには「100,000行を超える」ことがあります。ただし、選択するデータの量や結合の複雑さについては言及しません。正しく設定され、インデックスが作成されたSQLServerの場合、10万行は 大きくありません。数ミリ秒で結果を返す17方向の結合がありますが、インデックスが適切に作成され、いくつかの行が選択されています。アプリケーションの再設計を開始する前に、SQLServerのプロファイリング情報を確認します。

サーバー間でデータを転送するオーバーヘッドを無視しないでください。負荷がかかると、イーサネットはかなり急速に劣化します(持続転送速度は、シングルパケットレートの30%のようなものです。つまり、100Mb /秒のリンクは実際に30Mbの大量のトラフィックしか処理しません)。 DBサーバーでリンクを飽和状態にした後、アプリサーバーを追加しても問題はありません。データをより速く取り出すことができないからです。

アプリサーバーに参加すると、最も遅いサーバーに翻弄されます。クライアントサイトでパフォーマンスタンクを確認し、プライマリアプリサーバーがクラッシュしたことを発見しました。クライアントの回復戦略は、他のサーバーのいずれかで実行されている仮想マシンにマシンをフェールオーバーすることでした。一種のきちんとした解決策ですが、確かにパフォーマンスが良くありません。また、ルーターに障害が発生し、突然すべてのピアサーバーが同じサブネット上にあるのではなく、3ホップまたは4ホップ離れている場合にも速度低下が見られます。

RAMを追加するだけです。 RAMに完全に収まるデータベースは、多くの間違いを許します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top