5

レガシ アプリケーションで多くのn+1 の問題を回避するために、いくつかのユーティリティ メソッドを追加しようと考えています。

一般的なパターンは次のとおりです。

select a.* /* over 10 columns */
from [table-A] a
where /* something */

ClassAレコード インスタンスのコレクションに取得されます

次に、サブインスタンスが遅延取得されます。

select b.* /* over 10 columns */
from [sub-table-B] b
where b.ParentId = @ClassA_ID

これにより、n+1 選択の問題が発生します。ほとんどの場合、ヒットする頻度の低いページで 2 つのインスタンスしか取得されないため、これは大きな問題ではありませClassAんが、アプリケーションのスケーリングに伴い、この n+1 の問題によりページが遅くなりすぎる場所が増えています。

ClassAインスタンスとClassBインスタンスが一緒に取得されるように、このアプリケーションの既存のデータ アクセス コードの一部を置き換えようとしています。

これを行うには、次の 3 つの方法があると思います。

1)ClassA今と同じようにインスタンスを取得してからClassB、1 回の集約呼び出しでインスタンスを取得します。

select b.*
from [sub-table-B] b
where b.ParentId in ( /* list of parent IDs */ )

これは 2 つの別個の DB 呼び出しであり、動的 SQL のクエリ プランはキャッシュできません (ID のリストのため)。

2) サブクエリでClassBインスタンスを取得します。

select b.*
from [sub-table-B] b
    inner join [table-A] a
        on b.ParentId = a.[ID]
where /* something */

これも 2 つの DB 呼び出しであり、クエリに対するクエリ[table-A]は 2 回評価する必要があります。

3) すべてをまとめて、ClassAインスタンスの重複を排除します。

select a.*, b.*
from [table-A] a
    left outer join [sub-table-B] b 
        on a.[ID] = b.ParentId
where /* something */

これは 1 回の DB 呼び出しにすぎませんが、内容が[table-A]繰り返されるようになりました。結果セットが大きくなり、DB からクライアントにデータを送信する時間が長くなります。

したがって、実際にはこれは 3 つの可能な妥協点です。

  1. 2 つの DB 呼び出し、クエリ キャッシュなし
  2. 2 つの DB 呼び出し、複雑なクエリが 2 回評価される
  3. 1 DB 呼び出し、非常に大きな結果セット

これらの 3 つのパターンは、任意の 1 つの親子ペアのテーブルに対してテストできますが、大量のテーブルがあります。私が知りたいのは、一貫してどのパターンが速いかということです。もっと重要なのはなぜですか?これらの妥協の 1 つは、明らかなパフォーマンスの低下要因ですか?

Linq、EF、NHibernate などの既存のメカニズムは何を使用していますか?

3つすべてよりも優れた4番目の方法はありますか?

4

3 に答える 3

1

EF と L2S は 3 番目のアプローチを使用していると思います。db 呼び出しは 1 つだけです。

通常、結果セットが大きくなると、db ラウンドトリップが多いほど、db ラウンドトリップが少ない場合よりも時間がかかります。

おそらく、テーブル A に大量のデータがあり、結果セットが大きいとクライアントへの転送時間が長くなりすぎるという、いくつかのエッジ ケースがあります。

しかし、それは主に、db サーバーとクライアント間のレイテンシと帯域幅の問題です。

4 つ目の方法は、複数の結果セットを返すストアド プロシージャを作成することです。クエリを実行するテーブルごとに 1 つずつ、必要なレコードのみを使用します。それはあなたの最初のアプローチに適合しますが、1回の往復に減ります。しかし、それは少し複雑になり、他のアプローチほど柔軟ではありません。

于 2011-09-23T08:36:39.053 に答える
0

私の意見では、「どちらが最速の方法か」は、データベース サーバーへの待機時間と帯域幅、および結果セットの大きさによって異なります。

レイテンシーがボトルネック (ADSL ネットワーク?) であるシナリオでは、結果セットが大きくない場合は、単一のクエリをサーバーに送信することをお勧めします。[table-A] レコードが複数回送信されるため、使用される帯域幅は大きくなりますが、世界的に言えば、これがクライアントにデータを取得する最速の方法である可能性があります。

于 2011-09-23T08:52:21.313 に答える
0

最近のほとんどのデータベース (パラメーター化されたクエリを使用する場合は Oracle が確実です) は、クエリの評価をキャッシュし、それらに対するヒットはほとんどありません。

Django のような一部の ORMでは、カスタム クエリを作成して、ページのレンダリングに必要な部分的な結果のみを返すことができます。これは良いアプローチです。DB ホットスポットがあればそれを最適化しますが、それ以外の場合は ORM を残して入札を行います。

財務マネージャーが何を言おうと、ハードウェアは安価です (コンサルタントの 2 日間の作業コストはサーバーのアップグレードと同じです)。

于 2011-09-23T08:53:44.460 に答える