6

SQL リレーショナル データベース、中間サービス層用の Java、UI 用の Web など、多層データベース駆動の Web アプリケーションを設計しています。言語はあまり関係ありません。

中間サービス層は、データベースの実際のクエリを実行します。UI は単に特定のデータを要求するだけで、データベースに支えられているという概念はありません。

問題は、大規模なデータ セットをどのように処理するかです。UI はデータを要求しますが、結果が巨大になる可能性があり、大きすぎてメモリに収まらない可能性があります。たとえば、道路標識アプリケーションには、次のようなサービス レイヤーがあるとします。

StreetSign getStreetSign(int identifier)
Collection<StreetSign> getStreetSigns(Street street)
Collection<StreetSign> getStreetSigns(LatLonBox box)

UI レイヤーは、すべての道路標識がいくつかの基準を満たすように要求します。基準によっては、結果セットが膨大になる場合があります。UI レイヤーは、結果を別々のページに分割するか (ブラウザー用)、単にそれらすべてを表示する (Goolge Earth に提供する) 場合があります。潜在的に巨大な結果セットは、パフォーマンスとリソースの問題 (メモリ不足) である可能性があります。

1 つの解決策は、完全に読み込まれたオブジェクト (StreetSign オブジェクト) を返さないことです。むしろ、個々のオブジェクトを遅延ロードするある種の結果セットまたは反復子を返します。

別の解決策は、要求されたデータのサブセットを返すようにサービス API を変更することです。

Collection<StreetSign> getStreetSigns(LatLonBox box, int pageNumber, int resultsPerPage)

もちろん、UI は引き続き膨大な結果セットを要求できます。

getStreetSigns(box, 1, 1000000000)

このシナリオの業界標準の設計パターンは何ですか?

4

10 に答える 10

6

最初の質問は次のとおりです。

ユーザーはこの量のデータを管理する必要があるか、または管理できるか?

結果セットはページングする必要がありますが、潜在的なサイズが非常に大きい場合、答えは「おそらくそうではない」であるため、UI はそれを表示しようとしません。

私はヘルス ケア システムの J2EE プロジェクトに取り組みました。このプロジェクトでは、文字通り何百万もの患者、訪問、フォームなど、膨大な量の保存されたデータを扱います。一般的なルールは、ユーザー検索で 100 行または 200 行を超えて表示しないことです。これらの一連の基準によって、ユーザーが理解できるより多くの情報が生成されます。

これを実装する方法はプロジェクトごとに異なります。クエリを起動する前に、サービス層にクエリのサイズを問い合わせるように UI を強制することも、結果セットが大きくなった場合にサービス層から例外をスローすることもできます。多すぎます (ただし、この方法では、サービス層と UI の限定的な実装が結び付けられます)。

気をつけて!これは、結果のサイズが 100 を超える場合、サービス層のすべてのメソッドが例外をスローする必要があるという意味ではありません。この一般的な規則は、ユーザーに直接表示される結果セットにのみ適用されます。これは、コントロールを UI に配置するより良い理由です。代わりにサービス層で。

于 2008-10-23T23:39:05.040 に答える
2

この状況で私が見た最も頻繁なパターンは、ある種のページングであり、通常はネットワーク経由で送信される情報の量を減らすためにサーバー側で行われます。

テーブル変数を使用した SQL Server 2000 の例を次に示します (通常、一時テーブルよりも高速です)。道路標識の例と一緒に使用します。

CREATE PROCEDURE GetPagedStreetSigns
(
  @Page int = 1,
  @PageSize int = 10
)
AS
  SET NOCOUNT ON

  -- This memory-variable table will control paging
  DECLARE @TempTable TABLE (RowNumber int identity, StreetSignId int)

  INSERT INTO @TempTable
  (
     StreetSignId
  )
  SELECT [Id]
  FROM   StreetSign
  ORDER BY [Id]

  -- select only those rows belonging to the requested page
  SELECT SS.*
  FROM   StreetSign SS
         INNER JOIN @TempTable TT ON TT.StreetSignId = SS.[Id]
  WHERE  TT.RowNumber BETWEEN ((@Page - 1) * @PageSize + 1) 
                      AND (@Page * @PageSize)

SQL Server 2005 では、共通テーブル式や新しい SQL ランキング関数などを使用して、より賢くすることができます。しかし、一般的なテーマは、サーバーを使用して現在のページに属する情報のみを返すことです。

エンドユーザーが表示中のデータにその場でフィルターを適用できるようにしている場合、このアプローチは面倒になる可能性があることに注意してください。

于 2008-10-23T23:33:55.503 に答える
1

あなた (明らかに) が持っているような自家製の行ラッパー クラスを扱うときに注意すべきことの 1 つは、あなた (開発者) が気付かないうちにデータベースに追加の呼び出しを行うコードです。たとえば、Person オブジェクトのコレクションを返すメソッドを呼び出し、内部で行われているのは単一の "SELECT * FROM PERSONS" 呼び出しだけだと考えるかもしれません。実際には、呼び出しているメソッドは、返された Person オブジェクトのコレクションを反復処理し、追加の DB 呼び出しを行って、各 Person の Orders コレクションを設定する場合があります。

あなたが言うように、あなたの解決策の 1 つは完全に読み込まれたオブジェクトを返さないことなので、おそらくこの潜在的な問題を認識しています。私が行ラッパーの使用を避けがちな理由の 1 つは、行ラッパーを使用すると、アプリケーションの調整が難しくなり、データベース トラフィックのサイズと頻度を最小限に抑えることが常に困難になるためです。

于 2008-10-23T23:56:30.153 に答える
1

大規模なデータ セットの可能性が存在する場合は、ページング ルートに進みます。

超えてほしくない MAX を設定することもできます。

EG SO は 15、30、50... のページ サイズを使用します。

于 2008-10-23T22:41:13.220 に答える
0

この種の問題に対処するときは、通常、特定の基準を満たすデータの実際の合計サイズに関係なく、ブラウザー (または状況に適したシン/シック クライアント) に送信されるデータをチャンクします。ごく一部は、どの UI でも一度に実際に使用できます。

私は Microsoft の世界に住んでいるので、主な環境は SQL Server を使用した ASP.Net です。ページングに関する 2 つの記事 (結果セットをページングするためのいくつかの手法について説明しています) が参考になる場合があります。

ASP.NET 2.0 を使用して大量のデータを効率的に (Ajax 方式で) ページングする ASP.NET 2.0 DataList コントロールと ObjectDataSource を使用した効率的なデータ ページング

Microsoft が最近出荷したもう 1 つのメカニズムは、"動的データ" のアイデアです。この問題にどのように対処しているかについてのガイダンスとして、この内容を確認できるかもしれません。

于 2008-10-23T22:50:05.090 に答える
0

私は2つの異なる製品で同様のことをしました。1 つのケースでは、データ ソースはオプションでページ付けされます。Java の場合、次のような Pageable インターフェースを実装します。

public interface Pageable
{
    public void setStartIndex( int index );
    public int getStartIndex();
    public int getRowsPerPage() throws Exception;
    public void setRowsPerPage( int rowsPerPage );
}

データ ソースはアイテムの get() 用に別のメソッドを実装し、ページ分割されたデータ ソースの実装は現在のページを返すだけです。したがって、開始インデックスを設定し、コントローラーでページを取得できます。

考慮すべきことの 1 つは、サーバー側でカーソルをキャッシュすることです。Web アプリの場合、それらを期限切れにする必要がありますが、パフォーマンスに関しては非常に役立ちます。

于 2008-10-23T22:51:27.913 に答える
0

fedoraデジタル リポジトリプロジェクトは、result-set-id で最大数の結果を返します。その後、後続のクエリで結果セット ID を提供する次のチャンクを要求することで、結果の残りを取得します。クエリの外で検索や並べ替えを行いたくない限り、問題なく動作します。

于 2008-10-23T23:25:12.557 に答える
0

データ検索層から、標準的な設計パターンは、2 つのメソッド インターフェイスを持つことです。1 つはすべてのメソッド用で、もう 1 つはブロック サイズ用です。

必要に応じて、ページングを行うコンポーネントを重ねることができます。

于 2008-10-24T19:40:33.667 に答える
0

ASP.NET では、ユーザーがデータ ストアから要求したデータのページのみを取得するサーバー側のページングを使用します。これは、結果セット全体を取得してメモリに格納し、要求に応じてページングすることとは対照的です。

于 2008-10-23T22:39:37.670 に答える
0

JSF または JavaServerFaces には、大きな結果セットをまとめてブラウザーに送信するためのウィジェットがあります。あなたが提案するようにパラメータ化することができます。私はこれを決して「業界標準のデザインパターン」とは呼びませんが、他の誰かがどのように問題を解決したかを見る価値はあります。

于 2008-10-23T22:39:46.343 に答える