ページ区切り付きデータを返すRESTサービスにデータをキャッシュすることは可能ですか?

RESTアーキテクチャーの原則の下では、RESTfulアプリケーションはステートレスである必要があります。そのため、何万ものレコードを取得するASP.NET 4 RESTサービス(GET動詞を使用)を呼び出すたびに、RESTサービスは10個のチャンクを使用します。毎回10レコードしかロードしないため、UIが軽量になりますが、ユーザーが次の10レコードのチャンクを呼び出すたびに、ASP.NETコントローラがデータアクセスレイヤのreadメソッドを呼び出します(Dapper micro ORM)。 ODataページ付けエンジンのおかげで、コントローラが毎回10レコードしか返さないにもかかわらず、データアクセス層(Dapper)が毎回同じ数千レコードを照会するのでは、コストがかかります。そして遅い。 Dapperが使用するクエリを変更して、ページネーションフィルタがクエリレベルになるように変更できることはわかっていますが、ODataが送信するフィルタは非常に複雑であり、生成するのに贅沢がないため、負担が大きすぎます。 WHERE句でフィルタを生成するためのセマンティックツリー、それにODataはそもそも機能するのではないでしょうか。同じファイラーが何度も何度も要求されている場合、毎回データベースを呼び出すことを避けるために、何千ものレコードをどこかに単純にキャッシュすることはできませんか?

そうです、そしてEntity Frameworkは絶対に必要ありません。Dapperは代わりに必須です。

3
nl ru de
追加された 著者 glacier,

4 答え

毎回データベースを呼び出さないようにするために、何千ものレコードを単純にどこかにキャッシュすることはできません。

はい。ただし、ステートレス、つまりRESTとは正反対です。あなたはRESTfulサービスの主なイデオロギーに反することを試みています。

できますか?技術的なレベルでは、本当に必要ならば、確かに。しかし、これは XY問題の場合です。あなたの提案した解決策(Y - データのキャッシュ)は実際の問題に対する回避策です(返されるデータ量を減らすためにX - ページ分割をする)。

データセット全体を保存しても、問題の半分しか解決できません。ユーザーが平均して2ページしか表示していない場合でも、便利な行は20行、役に立たない行は9980行あります(合計10,000行と仮定して)。つまり、取得されたデータの 99.8%は決して使用されません。それはまだスペースの大きな無駄です。

さらに、フィルタの一意の組み合わせごとに個別のデータセットをキャッシュする必要があります。つまり、特定のレコードがいくつかの異なるフィルタを適用されたデータセットに表示される可能性があるため、メモリ内に大量の重複データがある可能性があります。
大量の同時ユーザーがいて、それらのすべての要求をキャッシュしていると仮定すると、重複を排除するためには、テーブル全体を一度メモリに格納するほうが効率的であると考え始めます( これを行うべきだと言っているわけではありません、すべてをキャッシュすると解決するよりも多くの問題が発生することを指摘しています)。

ページネーション問題の解決策として、ページ付けされていないデータをキャッシュしようとしないほうがよい理由はたくさんあります。

Dapperが使用するクエリを変更して、ページネーションフィルタがクエリレベルまで下がる可能性があることはわかっていますが、それを行うには負担がかかりすぎることに気付きます

データセットのページ区切りを拒否した場合は、ページ区切り付きデータセットは期待できません。しかし、それでは、より簡単で信頼できない解決策を支持する正しい解決策を除外しています。これは将来の技術的な負債を生み出す可能性があります。

Have a look at this pagination with Dapper example. You'll have to change the subquery to your own query.

SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY InsertDate) AS RowNum, *
          FROM      Posts
          WHERE     InsertDate >= '1900-01-01'
        ) AS result
WHERE   RowNum >= 1//*your pagination parameters
    AND RowNum =< 10  //*
ORDER BY RowNum

これを自分で実装するために必要なことは、行の制限(例では 110 )を理解することだけです。これらは簡単な計算を使って見つけることができます。

注: pageNumber は1から始まるインデックスであると想定しています。これは一般的にUIで表現されているからです。 pageSize は10です。

var row_limit_lower = ((pageNumber - 1) * pageSize) + 1;
var row_limit_upper = (pageNumber * pageSize) - 1;

どのページ番号が要求されているかを把握します。それに基づいて(そして私が推測しているページサイズはあなたのアプリケーションでは常に10です)、あなたはクエリ自体の中で必要なページ区切りを計算して実装することができます。

2
追加された
追加された 著者 user4127,
これまでのところ最良の答え。丸みを帯びた正確な答えのために、平らにされたFlaterを感じてください。 SQL Serverの OFFSET キーワードと FETCH キーワードを使用して、ページ区切りフィルターをSQLクエリに投影することにします。これに対する唯一の欠点は、クエリレベルでフィルタ処理を行うほど、ODataが無駄で無意味に感じられることです。
追加された 著者 Phil Gore,

1つのオプション(既に実際に言及されている)は追加コンポーネントとしてあなたのシステムにキャッシュ層を導入することでしょう。それ以外は、すべて同じままにしておくことができます。ただし、データベースにクエリを実行する必要がある場合は、最初にキャッシュを調べます。キャッシュが満たされない場合は、クエリがデータベースに渡されます。あなたのキャッシュキーは基本的にあなたがストアドプロシージャに渡したパラメータである - 文字列化。

このタイプの透過キャッシングは、システムを実際にステートフルにしたり、RESTプリンシパルに違反したりすることはありません。 SLAが自分のデータに対して何を意味するのかを自由に定義し、それをキャッシュの有効期間と一致させることができます。

データをBLOB、Redis、File、Mongoのいずれかのストレージにシリアル化し(あなたのユースケースに最適なものを試してみる必要があるでしょう)、その上に小さなサービスを追加することをお勧めします。

クエリをページ分割することが常に最善の選択肢とは限りません。クエリの実行に30秒かかるとしたらどうでしょうか。あなたはすべてのページでそれを実行しますか?また、あなたのケースでは、あなたはフィルタリングが複雑であると言います - そしてストアドプロシージャと通信するのは難しいかもしれません。

特定の要件を満たすために可能な解決策を適用する最善の方法を決定する必要があるため、ここでは1つの最良の回答が実際にあるわけではありません。

また、「キャッシュが大きくなりすぎる」という問題を解決する方法はたくさんあります。もう一度 - あなたはあなたのために働くものを見つける必要があります。 1つの可能性があります - ユーザごとのキャッシュの1つのエントリだけ。

1
追加された

UIを少し変更しても構わない場合は、このような問題に対する純粋なRESTソリューションが役に立ちます。ユーザーに最初にGETを実行させる代わりに、それをPOSTに変更します。クエリの実行を開始して、結果をどこかにキャプチャします。実行中に、結果を指すURIを返します。

その後、UIは結果の引き戻しを開始し、必要に応じてページ区切りを付けます。必要に応じて、ある時点で結果を期限切れにして410応答を返すことができます。

1
追加された

私はASP.Netを使ったことは一度もありませんが、まず最初に、データアクセス層に必要なレコードだけを取り出させないのはなぜでしょうか。ほとんどのリレーショナルデータベースはLIMITやOFFSETのようなものでページ付けすることをあなたに許しています、そして私はDapperがあなたにこれらの機能へのアクセスを与えてくれると思います。

それが整ったら、ページ番号をキャッシュキーに組み込めます。

ただし、後のページにアクセスするユーザーはそれほど多くないため、ペースがキャッシュされないカットオフポイントを設けることをお勧めします。ただし、そのコンテンツを保存しようとすると、キャッシュから頻繁に使用されるデータが削除されます。

1
追加された
ODataはページ付けもサポートしています。重要なのは、oDataクエリ言語がOPが必要とする種類のクエリをサポートするかどうかです。そうであれば、あなたがよく言ったようにデータソースをページ分割しない理由はありません。
追加された 著者 glacier,