はじめに
大量のデータを処理することは、常に悩みの種です。大手のデータベースベンダの中には、「当社のデータベースエンジンはテラバイト級のデータにも対応」と謳っている所もあります。そしてそれは、ある程度までは事実です。しかし、そのテラバイト級のデータが、静的なデータではなく、絶えず変動するデータだとしたらどうでしょう。つまり、ユーザーがひっきりなしに更新し、検索し、レポートを作成し、Webアプリケーション実行の基にするデータだとしたらです。さらには、データに同時アクセスするユーザー数が急増することがあるとしたらどうでしょう。そのテラバイト級のデータへの高速アクセスを滞りなく実現することは、かなりの難題となります。
ハードウェアのグレードアップで解決できれば話は簡単なのですが、あいにくこの場合、ハードウェアの馬力を増やすだけでは、さほどエンドユーザーのプラスにはなりません。率直に言って、エンドユーザーにとってパフォーマンスとは、単一のデータベースレコードのパフォーマンスがどうかという点に尽きます。
しかしそのレコードは、処理する側から見ると、さまざまなプロセスが更新や読み取りを同時に行おうとしているものなのです。多くの場合、パフォーマンスとスケーラビリティを得るためには、データベース側で設計上の特別な工夫が必要です。そして、そうした工夫は、データベースエンジンごとに異なる場合がほとんどです。
ストアドプロシージャを作成する理由
アーキテクチャの観点から言うと、データベースを基盤とするアプリケーションのパフォーマンスとスケーラビリティを向上させる方法はいくつかあり、通常は、十分な結果を得るためには、それらをすべて実装する必要があります。例えば、特定の部分でデータベースのパフォーマンスを向上させるために、データベースアーキテクチャを変更するという方法があります。データベースの分割、データの正規化と非正規化、テーブルの分割(水平分割と垂直分割)、インデックスと制約の追加などの手法による変更です。この記事では、これらの手法の詳細は割愛します。
一方、複数の要件が互いに矛盾することもあります。例えば、高速な更新を実現する必要があるのと同時に、高速な検索やリアルタイムのレポートも実現する必要がある、といった具合です。後者の要件を満たすためには、データベースのアーキテクチャを大きく変更するわけにはいきません。つまり、すべての要件を最大限に満たすよう、一定の安定した状態を維持する必要があります。これと同時に、パフォーマンスとスケーラビリティに優れた複雑な処理をデータベース側で実行する必要がある場合、通常は、入念に設計したストアドプロシージャを作成する必要があります。
ストアドプロシージャを作成する理由はいくつかあります。1つ目は、論理的な観点からの理由です。バックエンドのロジックをビジネスロジックとデータロジックに分割できる場合、データロジックはデータベース側に置くのが自然だということです。その方が、設計がすっきりし、保守性も高まります。
2つ目は、ストアドプロシージャはデータベースエンジンによってコンパイルされ、実行プランと併せて保存されるため、パフォーマンスがおのずと向上するということです(これは、開発者の観点からの理由です)。
3つ目は、この記事のテーマに関連する特に重要な点です。データ処理のロジックをストアドプロシージャに配置すると、パフォーマンスとスケーラビリティを大きく向上させるためのさまざまな手法や仕組みを使用できるということです。
こうした手法の中には、自明で分かりやすい、汎用的なものもあれば、特定のデータベースエンジンに固有のものもあります。中には、定型的な方法ではない、目的の処理に応じた設計や考え方を取り入れないと適切に実装できない手法もあります。これこそが、データベース設計の真価が発揮される部分です。しかし、特定のデータベース設計による手法は、不適切な設計の場合に比べて、複雑なスクリプトになりがちです。こうした手法があまり使われない最大の理由はその点にあります。
本稿の目的
この記事では、SQL Serverのストアドプロシージャを開発するうえで特に重要だと私が思っている、いくつかのヒントを紹介します。ここで取り上げる手法には、パフォーマンスの向上を目指して私自身がデータベースと格闘して得た成果と、非常に有能なソフトウェア開発者たちと共に作業する中で得た経験のエッセンスが盛り込まれています。まずは一連のヒントを示したうえで、その具体例として私が設計した、ストアドプロシージャベースの「数独」解法プログラムを紹介します。