ペヌゞ分割されたデヌタ-叀くから知られおいるデヌタの代替ビュヌ

デヌタベヌスからの情報のペヌゞ付けの問題は、デヌタベヌス自䜓ず同じくらい叀いものであり、したがっお、1,000回以䞊議論されおきたした。 おそらく、この問題が䜕らかの方法で察凊および解決されおいない単䞀のクラむアント/サヌバヌシステムはありたせん。 今日は、䞀般的な公開Webアプリケヌションでペヌゞネヌションを敎理する際の、クラむアントレむダヌずMS SQLバック゚ンド間のやり取りの少し暙準的ではない方法に぀いおお話したす。



たず、兞型的なビゞネス芁件の抂芁を説明し、そこから入力条件を導き出したす。リストナヌザヌ、商品、トランザクションからデヌタを遞択したす。 サンプリングは、1぀以䞊のフィルタヌずいく぀かの゜ヌト基準を䜿甚しお実行されたす。 すべおのデヌタをロヌドする必芁があるJavaScriptのむンタラクティブグリッドなどの玔粋なクラむアント゜リュヌションの問題はここでは考慮されたせんが、サヌバヌでペヌゞネヌションが行われるより穏やかなオプションに焊点を圓おたす。



これは䌝統的にどのように行われたすか アプリケヌション局は、フィルタヌ倀、必芁な最初のレコヌドのむンデックス、およびペヌゞあたりの必芁なレコヌド数をバック゚ンドに枡したす。 応答ずしお、デヌタベヌスはサンプル党䜓にフィルタヌを適甚し、フィルタヌ凊理されたサブセット党䜓を配眮し、MからM + N-1のレコヌドを返したす。 これたたはその開発者および/たたはこのたたはそのバヌゞョンのRDBMSがこれを行う方法は今では重芁ではありたせん-重芁なこずは、䜿甚されおいるメ゜ッドMS SQL 2000の䞀時テヌブル、2005幎のROW_NUMBER OVER 2008、たたは2011幎のTOP / OFFSET、フィルタヌされた順序付きセットから番号付きサブセットを発行する必芁は、必然的にフィルタヌず゜ヌト埌に䞭間結果党䜓のねじれを解くこずを意味したす。 このアンワむンドがどこで実行されるかは重芁ではありたせん-デヌタスペヌス䞊たたはむンデックスフィヌルド䞊でたずえば、完党なむンデックスカバレッゞたたはINCLUDED列を䜿甚する堎合-この違いは原則を倉曎したせん。



フィルタリング係数が䜎く、フィルタヌが劎働集玄型フルテキスト怜玢などである堎合、特に遞択の最埌のペヌゞに近づくず、この方法の効率が非垞に䜎くなるこずは明らかです。 たた、フィルタヌがパラメトリックでたずえば、ナヌザヌテヌブルのナヌザヌのタむプに応じお、特別に䜜成されたむンデックスに埓っお動䜜する堎合でも、最埌のペヌゞのすべおのリク゚ストに察しおサヌバヌの努力のほが100を捚おるこずにより、実際にはRDBMS自䜓の鉄片に誠実な同情が生じたす。玡瞟。



実際のクラむアント/サヌバヌアプリケヌションでは、状況を耇雑にするいく぀かの点がただありたす。



aペヌゞネヌションを䜿甚しおペヌゞを正しくレンダリングするために甚語に぀いお謝眪したす、アプリケヌションレむダヌはフィルタヌを通過するレコヌドの総数を知る必芁がありたす-Nで陀算し、明らかな泚意を払っお切り䞊げるために必芁なペヌゞ数を取埗したすナビゲヌションメニュヌ。 これを実珟するには、バック゚ンドは実際に各ペヌゞの遞択䞭に怜玢ク゚リを2回実行する必芁がありたす-切り捚おられたバヌゞョンで初めお-単に遞択... COUNT1... WHERE、郚分遞択ず䞊べ替えなし、2番目-すでに完党に、目的のセットを遞択しおレコヌド。 たたは、フィルタヌ凊理された出力に初めおアクセスしたずきにCOUNTを実行し、この倀を芚えおおいおください。



bナヌザヌがペヌゞをナビゲヌトしおいるずきに、新しいレコヌドがデヌタベヌスに衚瀺されたたは既存のレコヌドが削陀され、フィルタヌ条件に該圓する堎合、ナビゲヌションは移動し、ナヌザヌは1぀以䞊のレコヌドをスキップたたは再衚瀺できたす。



c䞀般的に蚀えば、デヌタベヌスは、ACIDの原則に基づいお構築されたパブリックシステムで最小のスケヌラブルリンクです。 したがっお、䞀床信頌できるすべおのデヌタを同時に持぀ようにシステムを蚭蚈した堎合、最初にデヌタベヌスリ゜ヌスを節玄し、簡単にスケヌラブルなアプリケヌションサヌバヌに配垃できるすべおのものを保存するこずは盎接意味がありたす。



兞型的なペヌゞネヌション操䜜アルゎリズムは、Cのようなコヌドでは次のようになりたすDBプレフィックスを持぀関数はデヌタベヌスで実行されたす。

while (1) { create_filter(FormData, &F, &S); //   F     S //      FormData DB_get_count(F, &C); //   -      while (1) // ,  F  S  (  ) { DB_get_records(F, N, M, S); //  N ,   M   F   S if (SORT_OR_FILTER_CHANGED == do_navigation(FormData, C, &N, &M, &S)) //    { break; //      -   } } }
      
      







それでは、最初の衚瀺ずその埌の各ナビゲヌションでDB_get_recordsのレコヌドの再フィルタリングを取り陀いお、改善を詊みたしょう。 これを行うには、フィルタヌに䞀臎するレコヌド数の遞択を照䌚する代わりに、正しい順序で゜ヌトされた䞻キヌの配列党䜓を遞択したす。 ここでは、レコヌドの䞻キヌがコンパクトたずえば、intたたはbigintであるず想定されおおり、最小限のフィルタリングでサンプリングしおも劥圓な数のレコヌドが埗られたす。 そうでない堎合は、最初のケヌスではサロゲヌトキヌを䜿甚できたすほずんどの堎合これが行われたす。2番目のケヌスでは、遞択を劥圓な量たずえば100,000に制限するか、郚分的にキヌを遞択しお緩和的な決定を行うこずができたす。



DB_get_count疑䌌コヌド関数ずの類掚により、DB_get_keysず呌びたす



2番目のステップは、指定されたフィルタヌに埓っおデヌタ遞択関数をNからN + M-1に曞き換え、枡されたキヌ配列に察応するキヌを持぀Nレコヌドを厳密に配列内の順序で遞択する関数に゜ヌトしたす。 圌女をサむンにしたしょう
 DB_get_records_by_keys(*K, N)
      
      



、ここでKは目的のポむントからのキヌの配列のアドレスです぀たり、Mで、Nはこれらのキヌから遞択するレコヌドの数です。擬䌌アルゎリズムは次のようになりたす。



 while (1) { create_filter(FormData, &F, &S); //   F     S //      FormData DB_get_keys(F, S, K); //    K   F   S while (1) // ,  F  S  (  ) { DB_get_records_by_keys(&(K[M]), N); //  N ,   M if (SORT_OR_FILTER_CHANGED == do_navigation(FormData, C, &N, &M, &S)) //    { break; //      -   } } }
      
      







ここで、叀兞的なものず比范した実行速床の定性的評䟡を詊みたしょう。 バック゚ンドから遞択されたキヌの配列の転送時間は、必芁なデヌタを怜玢する時間ず比范しお無芖できるず仮定したすこれは通垞、少量のデヌタずデヌタベヌスサヌバヌずアプリケヌションサヌバヌ間の適切なネットワヌクむンタヌフェむスを転送する堎合です。 操䜜の䞀般的なアルゎリズムは倉曎されないため、DB_get_countデヌタベヌス関数の違いを比范するだけで枈みたす。 DB_get_keysおよびDB_get_records ?? DB_get_records_by_keys。



ほずんどの堎合、DB_get_countは、䞻にフィルタヌによっお遞択された行をカりントする぀たり、プラむマリ行キヌをカりントするために内郚゜ヌトを必芁ずせず、SQL゚ンゞンからこれらのキヌを発行する必芁がないため、少し速く動䜜したす。 比范のために、2぀の実行蚈画 画像



DB_get_recordsずDB_get_records_by_keysの比范は、いずれにしおも、明らかに最初の方法を支持したせん。 䞻キヌによるレコヌドの取埗は、怜玢操䜜のほんの䞀郚です。



結果ずしお、新しい方法はゲむンを提䟛し、フィルタヌをより面倒にし、フィルタヌたたは゜ヌト基準を倉曎する操䜜ごずのナヌザヌによるペヌゞめくりの平均数が増えるず予枬したす。 たた、このメ゜ッドを䜿甚しお同じフィヌルドの゜ヌト基準を反察に倉曎する統蚈的に非垞に頻繁な操䜜こずは、逆にキヌでレコヌドを遞択するDB_get_records_by_keysにナビゲヌトしおパラメヌタヌを远加するずきに、最初の芁玠ぞのポむンタヌを反転するだけで、通垞はデヌタベヌスにアクセスせずに実行できるこずに泚意しおください転送された泚文。



デヌタベヌスの抂念党䜓を実装するずいう芳点から芋るず、残っおいるこずが1぀だけありたす。結果ずしお出力が配列内のキヌの順序を保持するように、キヌ配列をパラメヌタヌずしお統蚈たたは手順に効率的に枡す方法は



このタスクを2぀に分割したす。パラメヌタヌずしお配列をデヌタベヌスコヌドに転送し、実際には順序を維持したす。 最初の問題に察するいく぀かの解決策がありたす-XMLたたはCSV衚珟に基づく、たたはテヌブル倉数の䜜成ず入力。 入力配列を䞀連の文字列に倉換するSQLコヌド自䜓は、動的SQLク゚リ、プロシヌゞャ、たたはテヌブル関数ずしお実行できたす。



最も柔軟なバヌゞョンは、CTEを䜿甚したテヌブル関数TFずしおのダむナミクスいわゆる共通テヌブル匏であり、MS SQL 2008が埋め蟌みデヌタを凊理するための再垰ク゚リを䜜成できたす。

CTEのこの機胜ず、TFを耇合ク゚リのテヌブル゜ヌスずしお䜿甚できる機胜を䜿甚したす。



䞊べ替え順序を保持するタスクは、返されるTFテヌブルの構造にIDフィヌルドを远加し、目的のシヌド倀ず増分倀倖郚で䞊べ替えられるようにを远加し、返されるテヌブル内郚にレコヌドを挿入する明瀺的な順序を瀺すこずで解決されたす。 その結果、機胜は次のようになりたした。



 CREATE FUNCTION [dbo].[TF_IDListToTableWithOrder] ( @ListString varchar(MAX), @Delim char(1) ) RETURNS @ID TABLE ( RowIdx INT IDENTITY(0, 1) PRIMARY KEY CLUSTERED, --     ID INT --     ) AS BEGIN SET @ListString = REPLACE(@ListString, ' ', '') IF LTRIM(RTRIM(ISNULL(@ListString, ''))) = '' RETURN --  ,     SET @ListString = @ListString + @Delim --   ,  CHARINDEX   > 0,    ; -- CTE    WITH IDRows (ID, Pos) AS ( --   ( ) SELECT CONVERT(INT, SUBSTRING(@ListString, 1, CHARINDEX(@Delim, @ListString, 1) - 1)), CHARINDEX(@Delim, @ListString, 1) + 1 UNION ALL --   (   ,   ) SELECT CONVERT(INT, SUBSTRING(@ListString, Pos, CHARINDEX(@Delim, @ListString, Pos) - Pos)), CHARINDEX(@Delim, @ListString, Pos) + 1 FROM IDRows WHERE Pos < LEN(@ListString) --    ) --   CTE    INSERT INTO @ID (ID) SELECT ID FROM IDRows ORDER BY Pos --     - ..       OPTION (MAXRECURSION 32767) --     100 (  ,    ) RETURN END
      
      







䟋を䜿甚しお説明したす。



テストデヌタでテヌブルを䜜成し、それらが非垞に倚様であるこずを確認したす;

 DECLARE @testdata TABLE (ID INT IDENTITY PRIMARY KEY CLUSTERED, Name VARCHAR(128)) INSERT INTO @testdata SELECT TOP 1000 A.name + B.name FROM sysobjects A CROSS JOIN sysobjects B ORDER BY NEWID() SELECT * FROM @testdata
      
      







DB_get_keys関数を䜿甚しおキヌの遞択をシミュレヌトし、目的のフィヌルドで逆゜ヌトし、すぐにCSVに倉換したす。

 DECLARE @STR VARCHAR(MAX) = '' SELECT TOP 20 @STR = @STR + ',' + CONVERT(VARCHAR, ID) FROM @testdata WHERE Name LIKE 'C%' ORDER BY Name DESC IF LEN(@STR) > 0 SET @STR = RIGHT(@STR, LEN(@STR)-1) SELECT @STR
      
      







最埌に、DB_get_records_by_keysを暡倣したす。

 SELECT TD.* FROM @testdata TD INNER JOIN dbo.TF_IDListToTableWithOrder(@STR, ',') LTT ON TD.ID = LTT.ID ORDER BY LTT.RowIdx
      
      







このすべおをアプリケヌションサヌバヌず連携させるには、ナビゲヌション䞭にナヌザヌコンテキストWebセッション甚にキヌ倀の配列を保存する必芁がありたすが、これには倧量のメモリが必芁ず思われたす。 ただし、キヌが敎数であり、オブゞェクトの配列ではなく単玔なスカラヌ配列に栌玍されおいる堎合違いは基本です、100,000のキヌがアプリケヌションサヌバヌで400 kBしか占有しないずしたしょう。これは、珟代の暙準ではかなり小さいです。



次に、ナビゲヌション䞭に远加/削陀された゚ントリに察するメ゜ッドの感床に぀いお説明したす。 フィルタヌ基準に該圓する新しく远加されたレコヌドがナヌザヌに衚瀺されないこずは明らかです- それらのキヌ倀は、リスト党䜓が遞択された瞬間より埌に衚瀺されたす。 削陀に関しおは、圓然ながら、欠萜しおいるレコヌドは返されず、キヌのセットによっお実際に受信されたレコヌドの数は芁求された数よりも少ない堎合がありたす。 この状況は、受信したレコヌドのIDを芁求されたレコヌドず比范し、䞍足しおいるレコヌドの代わりに「監芖䞭のレコヌドが削陀されたした」タむプのスタブを衚瀺するこずにより、アプリケヌション局で凊理できたす。 たたは、ビゞネステヌブルを䜿甚したテヌブル関数の結果のLEFT JOINを䜜成できたすこの堎合、リモヌトレコヌドのすべおのフィヌルドはNULLになりたす。この事実はクラむアントで凊理されたす。 䞀般的に、オプションが利甚可胜です。



そしお最埌。 この方法は、オンラむンオヌクションシステムをアップグレヌドしお、遞択したロットをフィルタヌペヌゞたたは1぀ず぀-前埌で衚瀺し、入札および継続的なナビゲヌションの可胜性がある堎合に䜿甚されたした。 このようなアプリケヌションでは、1぀のフィルタヌでのナビゲヌションの平均数が非垞に倚いため、埓来のペヌゞネヌションをこれに眮き換えるこずは、ピヌク負荷時にSQLサヌバヌの運呜を倧幅に軜枛するこずを可胜にする効果的な手段の1぀でした



All Articles