SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

ASP.NET 2.0でカスタムのページング処理と並び替えを併用する

動的SQLステートメントを作成して効率よく並べ替える

並べ替え後の正しいページを表示する

 カスタムのページング処理と並べ替えを正しく実装するには、まず特定の列を基準に並べ替えた後の従業員レコードの正しいサブセットを取得する必要があります。「Custom Paging in ASP.NET 2.0 with SQL Server 2005」で紹介した、従業員の適切なサブセットを返す場合に使う次のようなストアドプロシージャを思い出してください。

SELECT EmployeeID, LastName, FirstName, DepartmentID, Salary,
         HireDate, DepartmentName
FROM
   (SELECT EmployeeID, LastName, FirstName, e.DepartmentID, Salary,
         HireDate, d.Name as DepartmentName,
         ROW_NUMBER() OVER(''ORDER BY EmployeeID'') as RowNum
    FROM Employees e
      INNER JOIN Departments d ON
         e.DepartmentID = d.DepartmentID
   ) as EmpInfo
WHERE RowNum BETWEEN @startRowIndex AND
    (@startRowIndex + @maximumRows) - 1

 このストアドプロシージャは、連続する行番号を、EmployeeID順に並べ替えたそれぞれの従業員レコードに関連付けます。次に、@startRowIndexパラメータと@maximumRowsパラメータで指定された範囲のレコードを返します。

 ほかの列(Salaryなど)を基準として従業員を並べ替えたうえで、特定のページを取得する場合は、ORDER BY句を変更する必要があります。次の例では、Salaryを基準として昇順で(最低給与から順に)結果が並べ替えられます。この結果をSalaryの降順で並べ替える場合は、ORDER BY句にDESCキーワードを追加します。

SELECT EmployeeID, LastName, FirstName, DepartmentID, Salary,
         HireDate, DepartmentName
FROM
   (SELECT EmployeeID, LastName, FirstName, e.DepartmentID, Salary,
         HireDate, d.Name as DepartmentName,
         ROW_NUMBER() OVER(''ORDER BY Salary'') as RowNum
    FROM Employees e
      INNER JOIN Departments d ON
         e.DepartmentID = d.DepartmentID
   ) as EmpInfo
WHERE RowNum BETWEEN @startRowIndex AND
    (@startRowIndex + @maximumRows) - 1

 理論上は、並べ替える列ごとに別々のストアドプロシージャを用意するか、処理を担当する1つのストアドプロシージャ内にT-SQLのIF/ELSEステートメントを複数追加する必要があります。これは大変です。

 しかし嬉しいことに、ストアドプロシージャにはダイナミックSQLの選択肢がいくつかあります。1つは、「Dynamic ORDER BY Statements in Stored Procedures」と「The Power of SQL CASE Statements」で説明したように、ORDER BY句でCASEステートメントを使う方法です。残念ながら、この方法で非文字列の列を並べ替えると、変換要件などが原因でパフォーマンスが低下します。

 パフォーマンスが向上する選択肢は、動的SQLステートメントを作成して実行する方法です。この方法は「Dynamic ORDER BY Statements in Stored Procedures」でも説明しました。このアプローチでは、並べ替える列にインデックスを使うことによって、並べ替えのないカスタムのページング処理と同じパフォーマンスが実現されます。

-- Issue query
DECLARE @sql nvarchar(4000)
SET @sql = 'SELECT EmployeeID, LastName, FirstName, DepartmentID,
         Salary, HireDate, DepartmentName
FROM
   (SELECT EmployeeID, LastName, FirstName, e.DepartmentID, Salary,
         HireDate, d.Name as DepartmentName,
         ROW_NUMBER() OVER(ORDER BY ' + @sortExpression + ')
         as RowNum
    FROM Employees e
      INNER JOIN Departments d ON
         e.DepartmentID = d.DepartmentID
   ) as EmpInfo
WHERE RowNum BETWEEN ' + CONVERT(nvarchar(10), @startRowIndex) +
            ' AND (' + CONVERT(nvarchar(10), @startRowIndex) + ' + '
            + CONVERT(nvarchar(10), @maximumRows) + ') - 1'

-- Execute the SQL query
EXEC sp_executesql @sql

 本稿のダウンロードサンプルに収録されているデータベースには、次の2つのストアドプロシージャが含まれています。

  • GetEmployeesSubset(@startRowIndex, @maximumRows)
  • @startRowIndex行から@maximumRows行までのレコードのサブセットを返し、結果をEmployeeID列を基準に並べ替えます。
  • GetEmployeesSubsetSorted(@sortExpression, @startRowIndex, @maximumRows)
  • @startRowIndex行から@maximumRows行までのレコードのサブセットを返し、結果を@sortExpressionを基準に並べ替えます。

 また、「Employees」テーブルでは、並べ替えることができる列のそれぞれに充てん率(Fill Factor)を90とするインデックスが割り当てられています。このインデックスがないと、結果の並べ替えに時間がかかり、全体的な実行時間が著しく長くなる可能性があります。この後で紹介する非常に非科学的なテスト結果から分かるように、インデックスを使わなかった場合の並べ替え時間は平均0.189秒だったのに対し、インデックスを追加した場合の平均時間は0.038秒でした。

カスタムのページング処理と並べ替えを併用できるようにObjectDataSourceを設定する

 GetEmployeesSubsetSortedストアドプロシージャが完成したら、最後に、ObjectDataSourceがこのストアドプロシージャにGridViewのSortExpression値を渡すようにします。このためには、型指定されたDataSetのEmployeesTableAdapterクラスに、GetEmployeesSubsetSortedストアドプロシージャを呼び出すGetEmployeesSubsetSortedというメソッドを追加します。次に、この新しいメソッドを使うようにObjectDataSourceを設定します。最後に、ObjectDataSourceのSortParameterNameプロパティに、並べ替え式を受け取るパラメータの名前(sortExpression)を指定します。

 ObjectDataSourceの宣言マークアップは次のようになります。

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetEmployeesSubsetSorted"
    TypeName="EmployeesTableAdapters.EmployeesTableAdapter"
    EnablePaging="True"
    SelectCountMethod="GetEmployeesRowCount"
    ''SortParameterName="sortExpression"''>
</asp:ObjectDataSource>

 本稿のダウンロードサンプルには、並べ替えのないカスタムのページング処理と、並べ替えのあるカスタムのページング処理の両方を示す例が含まれています。並べ替えのないカスタムのページング処理の例については、「Default.aspx」のデモを参照してください。カスタムのページング処理と並べ替えの両方を使っている例については、「CustomPagingAndSorting.aspx」のデモを参照してください。

並べ替えのあるカスタムのページング処理のパフォーマンス

 動的なORDER BY句を使って並べ替え機能を追加すると、カスタムのページング処理のパフォーマンスに影響しますが、それでも、データセットがかなり大きい場合は、既定のページング処理に比べて実行時間は著しく短くなります。次の表に、既定のページング処理、カスタムのページング処理、および並べ替えのあるカスタムのページング処理の非常に非科学的なトレース結果を示します。

ASP.NETのトレース結果

既定のページング処理カスタムのページング処理
(Employeesから全レコードを選択する)(Employeesから1ページ分のレコードを選択する)
ページ読み込み時間(秒)ページ読み込み時間(秒)
2.3413685260.025961121
2.357722280.028004677
2.4336827730.035905401
2.4323756230.029553477
2.3316706450.03000968
平均: 2.379363969平均: 0.029886871
並べ替えのあるカスタムのページング処理並べ替えのあるカスタムのページング処理
(インデックスを使わない並べ替え)(インデックスを使う並べ替え)
ページ読み込み時間(秒)ページ読み込み時間(秒)
0.2076995820.03687843
0.2314964610.059062534
0.1422602590.027032765
0.1391986970.033962696
0.22379660.031374379
平均: 0.18889032平均: 0.037662161

 列にインデックスを付けずに並べ替えを行った場合、データを昇順にするASP.NETページの平均読み込み時間は0.189秒です。充てん率を90とする非クラスタ化インデックスを追加すると、平均読み込み時間は0.038秒に短縮され、パフォーマンスは大幅に向上します。この差は、データセットが大きい場合にさらに顕著になります(理想的なパフォーマンスを考えた場合、インデックスの実際の充てん率と埋め込み設定は、アプリケーションの「Employees」テーブルに対する読み取り対書き込みの比率によって異なります)。

まとめ

 カスタムのページング処理は、結果セットがかなり大きければアプリケーションのパフォーマンスを大幅に向上させることができますが、「Custom Paging in ASP.NET 2.0 with SQL Server 2005」で説明したように、実装は既定のページング処理の簡便さに遠くおよびません。カスタムのページング処理を実装すると、既定のページング処理に内在する昇順/降順の並べ替え機能が使えなくなってしまいます。カスタムのページング処理と並べ替えの両方を利用するには、まず、データを指定の順序に並べ替えて正しいページのデータを返すストアドプロシージャを追加します。その後、データアクセス層(この例では型指定されたDataSet)に、並べ替えの基準列を入力パラメータとして受け取り、このストアドプロシージャを呼び出すメソッドを組み込みます。最後に、ObjectDataSourceのSortParameterNameパラメータに、並べ替えの基準となる入力パラメータの名前を指定します。

 本稿で説明したように、動的なORDER BY句を使って並べ替えを行う単一のストアドプロシージャを作成することもできますが、これを使うと最適なパフォーマンスを得ることができなくなります。

 それでは、ハッピープログラミング!

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Scott Mitchell(Scott Mitchell)

http://www.4guysfromrolla.com/ScottMitchell.shtml

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/360 2006/08/22 15:46

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー