SharePointのパフォーマンスに影響を与える5つのエラーを回避する方法


原文住所:How to avoid the Top 5 SharePoint Performance Mistakes
現在SharePointは間違いなく急速に発展しているプラットフォームであり、マイクロソフトは本当に多くのお金を稼いでいます.SharePointは、小さなリストとドキュメント管理システムから、ASPベースの独自のデータベースに発展しました.NETテクノロジーとAPIの開発プラットフォームを提供しても、約10年しかかかりません.
何年も経って、多くのものが変わったが、SharePointはすべてのitemsをデータベースのテーブルに保存しているなど、変わっていないものもある.これにより、最初のパフォーマンスの問題が発生しました.
#1:listのitemsを巡る
SPListオブジェクトを取得するには、現在のSPContextオブジェクトを使用するか、リストの名前を使用してSPListオブジェクトを作成するかの2つの方法があります.SPListオブジェクトにはItemsプロパティがあり、このプロパティはSPList ItemCollectionオブジェクトを返します.次のコードはSPListオブジェクトから最初の100個のitemを取得し、Titleを印刷します.
SPList activeList = SPContext.Current.List;
for(int i=0;i<100 && i<activeList.Items.Count;i++) {
  SPListItem listItem = activeList.Items[i];
  htmlWriter.Write(listItem["Title"]);
}
よさそうですね.上記のコードは正常に動作しますが、このようなコードは1番のパフォーマンス殺し屋です.問題は、Itemsプロパティを取得する方法です.Itemsプロパティはコンテンツデータベースからすべてのitemをクエリーし、Itemsプロパティにアクセスするたびにクエリーします.また、クエリーされたitemはキャッシュされません.コードのループでは、ループのたびにこのプロパティに2回アクセスします.一度にitemを取得する数と、インデックスを使用してitemを取得します.特定のSQL文を分析すると、次の結果が表示されます.
(この図は、上記のコードの実行中に200回のSQLクエリが実行されることを示しています)
質問:SQLクエリーを繰り返し実行し、上記のコードを例にとると、200回のSQLクエリーに1秒以上かかりました.
解決方法:簡単です.まずItemsを取り出して変数に保存し、この変数を使用します.
SPListItemCollection items = SPContext.Current.List.Items;
for(int i=0;i<100 && i<items.Count;i++) {
  SPListItem listItem = items[i];
  htmlWriter.Write(listItem["Title"]);
}
このように1回だけSQLクエリーを行い、その後はitemのデータをメモリに読み込みます.
詳細:The wrong way to iterate through SharePoint SPList Items and Performance Considerations when using the SharePoint Object Model
#2:コンテンツデータベースへの過剰なデータ要求
上のスクリーンショットをよく見ると、Itemsプロパティでitemを取得し、最終的に変換されたSQL文はSELECT TOP 2147483648...であることがわかります.SPListで定義されているcolumnのすべての値が返されます.しかし、これらのデータは、私たちのほとんどは使えません.多くの開発者は、実際にSPQueryオブジェクトを使用すると、本当に必要なデータを取得できることに気づいていません.SPQueryオブジェクトは次のことができます.
a)返却するitem数を制限する
b)返されるcolumnの数を制限する
c)CAMLで指定したitemを返す
まず最初に、返されるitemの数を制限します.リスト内の最初の100個のitemのみを取得したい場合、たとえばページング、各ページの100個のデータを使用すると、SPQueryのRowLlimitとListItemCollectionPositionプロパティを使用できます.ここでPage through SharePointリストでは、完全なコード例を見つけることができます.
SPQuery query = new SPQuery();
query.RowLimit = 100; //     100 item

query.ListItemCollectionPosition = prevItems.ListItemCollectionPosition; //         
SPListItemCollection items = SPContext.Current.List.GetItems(query);

の下のスクリーンショットは、SharePointが最終的にRowLimitをSQLクエリのSELECT TOPに使用し、返される数を表示するために使用されることを示しており、SharePointは最終的にListItemCollection PositionをSQLクエリのWHERE文に使用し、指定された位置のitemを取得する.
さらに2つ目はcolumnを返す数を制限します.必要なcolumnだけを取得するには、SPQueryを使用します.ViewFieldsプロパティ.デフォルトでは、SharePointはリスト内のすべてのcolumnを返します.これにより、データベース、帯域幅、メモリに追加の負担がかかります.次のコードは、ViewFieldsプロパティを使用して、ID、Text Field、XZYの3つのcolumnのデータのみを取得します.
SPQuery query = new SPQuery();
query.ViewFields = "<FieldRef Name='ID'/><FieldRef Name='Text Field'/><FieldRef Name='XYZ'/>";
//   :       column,                column  ,        column   ,     query.ViewFieldsOnly = true;

次は、ViewFieldsを使用しないSQLクエリ文と、ViewFieldsを使用しないSQLクエリ文の比較です.
最後に、CAMLを使用して指定したitemを返します.CAMLでは、どのデータを返すかを正確に指定できます.SQLのWHERE文に似た文字列を指定する必要があります.たとえば、ID 15のitemを取得する必要があります.次の方法を使用します.
SPQuery query = new SPQuery();
query.Query = “<Where><Eq><FieldRef Name=\”ID\”/><Value Type=\”Number\”>15</Value></Eq></Where>”;
       
問題:開発者は通常、最も便利な方法でデータを取得しますが、多くの場合、不要なデータを取得しすぎます.
解決策:SPQueryオブジェクトとそのプロパティを使用して、不要なデータを削減します.
詳細:Only request the data you really need and Page through SharePoint lists
#3:SPSiteとSPWebはメモリの漏洩を引き起こす可能性があります冒頭で私は「多くのものが変わったが、いくつかのものが変わっていない」と言ったことがありますが、SharePointのいくつかのコア機能は、COMコンポーネントを使用しています.COMコンポーネントに問題があるわけではありませんが、現在は管理コードの時代であり、COMコンポーネントを使用するにはリソースを解放する必要があります.SPSiteとSPWebオブジェクトにはCOMオブジェクトの参照が含まれているので、使い終わったら必ず明示的に解放してください.
問題:SPSiteとSPWebオブジェクトを正しく解放しなかった結果、メモリが漏洩し、最終的にメモリが不足し、IISを再起動するしかありません.IISの再起動は、すべてのセッションが失われ、ページキャッシュが失われ、ユーザーがページを再開するのが遅くなることを意味します.
解決方法:ツールを使用して、どのオブジェクトによるメモリ漏洩を検出するか、SPSiteとSPWebオブジェクトについては、ベストプラクティスを参照することができます.マイクロソフトもあなたのコード:SPDisposeCheckを検出するツールを提供しています.
次のスクリーンショットでは、synaTraceを使用して検出されたメモリの漏洩を示します.
詳細:identifying memory problems introduced by custom code 4:インデックスを使用するとパフォーマンスが向上するとは限らない
SharePointの研究を始めたばかりの頃、データベース・テーブルを使用してすべてのitemを格納したり、インデックスを定義してパフォーマンスを最適化したりするのはおかしいという「面白い」ものを見つけました.しかし、コンテンツ・データベースで「AllUserData」というテーブルを表示すると、64個のnvarchar、16個のint、12個のfloatsなど、可能なすべてのcolumnが含まれていることがわかります.
「My SharePoint list 1」の最初のcolumnにインデックスを定義し、別のリスト「My SharePoint List 2」の2番目のcolumnにインデックスを定義すると、最後にコンテンツ・データベースにインデックスがあふれます.インデックスとAllUserDataテーブルについては、SharePoint:List Performance-How list column indices really work under the hoodを参照してください.
質問:インデックスcolumnはSharePointリストへのアクセス速度を向上させることができますが、SharePointのデータベース設計のため、インデックスには以下の制限があります.
a)各インデックスについて、SharePointは各itemのインデックス値を他のテーブルに保存し、1つのテーブルに10000個のitemがある場合、SharePointはAllUserDataに10000個のレコードを保存し、NameValue Pairテーブルの10000個のレコード(インデックス値)を追加する.
b)SharePointクエリ(CAML)は最初のインデックスcolumnのみであり、他のインデックスcolumnはデータベースへのアクセス速度を向上させない.
解決方法:インデックス列をよく考察します.彼らが本当に役に立つのはlookupの他の列の時です.インデックスを過度に使用しないでください.
詳細:How list column indices really work under the hood and More on column index and their performance impact
#5:SharePointは、高容量トランザクション(high volume transactional processing)を処理するために設計されたデータベースではありません.
SharePointは地球上で最も柔軟なデータベースだと思っています.リストを勝手に定義したり修正したりして、データベースの気持ちを少しも考えません.したがってSharePointのコンテンツ・データベースは通常のリレーショナル・データベースとして使用されます.
質問:上記の4つの質問を真剣に読んだ場合は、SharePointは真のリレーショナル・データベースではなく、高容量のトランザクションではないことを認識する必要があります.すべてのデータは1つのデータベーステーブルに保存され、データベースのインデックスは別のテーブルに保存され、使用すると2つのテーブルにjoinが来ます.したがってlistへのパラレルアクセスは、すべてのデータが同じテーブルから来ているため、問題です.
解決策:SharePointプロジェクトを開始する前に、あなたのデータストレージを真剣に考えてみてください.これらのデータは頻繁にアクセスされますか?データを同時に変更できるユーザーはどれくらいですか?よく変更されるitemがたくさんある場合は、自分のリレーショナル・データベースを使用することを考慮する必要があります.SharePointの偉大な点は、コンテンツ・データベースを使用したくない場合は、外部のデータベースを使用できることです.
詳細:Monitoring individual List usage and performance、もう一つ:How list column indices really work under the hood
以上、SharePointの2年間の経験をまとめました.私はすでに多くの会議で、SharePointのパフォーマンスを向上させる経験を異なる会社と共有しました.あなたたちを助けてほしい.