SHOEISHA iD

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

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

japan.internet.com翻訳記事

SQL Server 2000で大量の結果セットを効率的にページングする方法

主キーをテーブル変数に読み込みページングのパフォーマンスを改善する

  • このエントリーをはてなブックマークに追加

本稿では、ストアドプロシージャを使って特定のページのデータを取得する効率的な方法を解説します。この方法は、大量の結果セットに対して、ASP.NET 1.xのDataGridやASP.NET 2.0のGridViewを使って効率的なカスタムページングを行う場合に役立ちます。

  • このエントリーをはてなブックマークに追加

はじめに

 大量のデータをユーザーに表示する場合は、すべての情報を一気に表示するのではなく、ある程度のまとまりごとに表示することが重要です。例えば、Googleで「Microsoft」という単語を検索すると約2,190,000,000もの結果が返されますが、一度に表示されるのはそのうちの10個です。特に大量の結果セット(1万、10万、または100万のレコードから成るテーブル)にページングアクセスを提供する場合は、要求された特定のページのデータだけが返されるように、データのクエリに注意を払う必要があります。

 ASP.NET 1.xのDataGridとASP.NET 2.0のGridViewは、2種類のページング方法を備えています。

2種類のページング方法
種類特徴
既定ページング実装は簡単ですが、データベースのすべてのレコードを単純に取得し、結果をトリムすることで、要求されたページのレコードのみを表示します。
カスタムページング開発者が、現在のページに表示するレコードのサブセットのみを適切に取得する必要があります。実装に手間がかかります。

 既定ページングは短時間で簡単に実装できますが、必要な大きさの結果セットだけを取得したい場合はカスタムページングが不可欠です。私は2006年3月に、カスタムページングを利用して大量の結果セットを効率的にページングする方法についての記事を本サイト(4GuysFromRolla.com)にいくつか投稿しましたが、そこでは、ObjectDataSourceとSQL Server 2005の新しいROW_NUMBER()キーワードを使ってGridViewでカスタムページングを行いました。ROW_NUMBER()という新しいキーワードは、行番号で並べられたデータの特定のサブセットを効率的に取得するものです。3月の投稿の後、多くの読者から、ROW_NUMBER()のないSQL Server 2000でこのような効率的なカスタムページングを実装する方法について問い合わせがありました。

 本サイト(4GuysFromRolla.com)に以前に投稿された「Paging through Records using a Stored Procedure」(Daniel Anderson著)は、既定ページングの実装をはるかにしのぐ1つの方法を示しています。しかし、パフォーマンスという点では改善の余地があります。本稿では、Danielのストアドプロシージャに手を加えて、さらに効率的な方法を示します。本稿の最後に示すストアドプロシージャは、典型的なASPアプリケーションや、ASP.NET 1.xのDataGridによるカスタムページングで使用できます。また、ObjectDataSourceで使用してASP.NET 2.0アプリケーションのGridViewでカスタムページングを実現することもできます。詳細については、以下を参照してください。

Danielの方法

 「Paging through Records using a Stored Procedure」の中で、Daniel Andersonは、sp_PagedResultsという名前のストアドプロシージャを作成しました。これは、2つの整数型の入力パラメータ(@Pageおよび@RecsPerPage)を受け取り、基になるデータベーステーブルから、指定ページのデータに属するレコードを返します。例えば、1ページが10レコードの場合に2ページ目のデータを表示するときは、ストアドプロシージャsp_PagedRecordsを呼び出して@Page@RecsPerPageにそれぞれ2と10の値を渡します。

 テーブルの一意キー(ID)が連番になっていて、番号に抜けがない場合、このようなテーブルからページ単位でデータを取得するのは簡単です。単純なWHERE句を指定すればよいのです。例えば、次のようなデータのテーブルがあるものとします。

Employeesテーブル
EmployeeIDLastNameFirstNameDepartmentIDSalaryHireDate
1MitchellScott.........
2LeeSam.........
3SmithHans.........
4JohnsonErnie.........
5GonzalezLaura.........
6WangHugo.........
7JacksonTito.........
8MaherTodd.........
..................

 EmployeeIDの値は連続していて番号に抜けがないため、汎用的なクエリで特定のページのデータを簡単に取得できます。

SELECT ...
FROM Employees
WHERE EmployeeID BETWEEN (''page * recsPerPage'') + 1
AND (''page * recsPerPage'') + ''recsPerPage ''
 ここでは、ページのインデックスを0から始めるものとします。つまり、1ページ目のデータは「ページ0」、2ページ目は「ページ1」という具合に数えます。DataGridとGridViewの両方とも、ページインデックスは0から始まります。

 例えば、1ページに表示する従業員が3人の場合、1ページ目のデータを表示するには、次のように指定します。

SELECT ...
FROM Employees
WHERE EmployeeID BETWEEN (0 * 3) + 1 AND (0 * 3) + 3
-- Which is tantamount to... SELECT ...
FROM Employees
WHERE EmployeeID BETWEEN 1 AND 3

 これにより、最初の3人の従業員が返されます。2番目のページを表示するには、次のように指定します。

SELECT ...
FROM Employees
WHERE EmployeeID BETWEEN (1 * 3) + 1 AND (1 * 3) + 3
-- Which is tantamount to... SELECT ...
FROM Employees
WHERE EmployeeID BETWEEN 4 AND 6

 これにより、2ページ目のデータであるEmployeeID 4、5、6が返されます。

 この方法は、ページングされるデータの主キー値に抜けがなければうまくいきます。しかし、レコードが削除されると、欠番が生じます。例えば、Sam LeeとHans Smithが解雇されると、「Employees」テーブルは次のようになります。

「Employees」テーブル
EmployeeIDLastNameFirstNameDepartmentIDSalaryHireDate
1MitchellScott.........
4JohnsonErnie.........
5GonzalezLaura.........
6WangHugo.........
7JacksonTito.........
8MaherTodd.........
..................

 EmployeeID 1と4の間に欠番があるため、先ほど使用した単純なアルゴリズムではうまくいきません。

 このような欠番に対処するため、Daniel Andersonのストアドプロシージャでは偽の連番IDを作成しています。この処理は、次のアルゴリズムによって行われます。

  1. まず、ページング対象のデータの各列に対応する列と、IDという名前の列を含んだ一時テーブルを作成します。このID列を「IDENTITY列」としてマークします(IDENTITY列としてマークされた列の値は、レコードが挿入されるたびに自動的に増分します)。
  2. ページング対象のテーブルの内容全体を、ステップ1で作成した一時テーブルにダンプします。これによって、ID列の値は1、2、3、...に設定されます。
  3. この一時テーブルに対してSELECTクエリを行い、WHERE句に前述の単純な式を適用します。

 Danielのストアドプロシージャの詳細については、「Paging through Records using a Stored Procedure」を参照してください。ストアドプロシージャの具体的なコードは、ここで参照できます。

 一見するとこの方法は、すべてのレコードをそのまま返すより良いように思えます。しかし、結局は一時テーブルにダンプしているだけで、「Employees」のすべてのレコードを処理していることに変わりありません。とはいえ、Danielの方法は、データベースサーバーとWebサーバーとの間のトラフィックを大きく削減します。「Employees」テーブルのデータ全部を処理するという点は同じですが、ストアドプロシージャが返すのは10レコード(または、設定されている1ページ当たりのレコード数)だけです。

会員登録無料すると、続きをお読みいただけます

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

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

メールバックナンバー

次のページ
Danielのストアドプロシージャの現代化

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

  • このエントリーをはてなブックマークに追加
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/391 2006/08/22 15:47

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング