SQL クエリを発行するアプリを開発する時の注意点

クライアントから DB に接続してデータを取得する際、基本的には SQL クエリを書くことになる。 クエリについてはメンテがしやすい構成になっている方がもちろん好ましいが、それ以上に重要なのは、以下の点。

  • 速度
  • メモリ使用量

基本的には、当該クエリが扱うデータ量が少なければそこまで気にする必要ないが、大量のデータを扱う可能性がある場合、上記を考慮したクエリを作成しないと、本番のデータ量で期待したパフォーマンスを発揮できない可能性が高い。

クエリ作成時に考慮が必要な要素は以下。

  • 当該クエリで操作することになるデータ量 (テーブルに格納されているレコード数。結合等も考慮)
  • DB からクライアントに送信するデータ量
  • クエリの発行頻度。例えば、1 分間に何回の発行が見込まれるクエリなのか、など。サーバー、クライアント共に、それぞれの側の観点で考慮が必要

ケースバイケースではあるが、DB からクライアントに送信するデータ量は、可能な限り最小限にした方が良い。 クライアントアプリだと、最終的には不要なデータも含めて一度取得し、クライアントアプリ側でフィルタする事も可能だが、データ量によってはまずい可能性がある。 クエリでのフィルタが難しい場合は、ストアドの使用も検討する。

何度も書くようだがケースバイケースなので、データ量が少ない場合は、そこまで気にする必要ないと思う。

オンプレ ASP.NET Web.config のセクション暗号化

Web.config に記載する DB 接続文字列などは暗号化したい場合があるが、オンプレ ASP.NET であれば以下のような IIS コマンドを使用して、暗号化した文字列を取得できる。

> aspnet_regiis.exe -pef "connectionStrings" ~

また、接続文字列以外にもアプリの設定で暗号化したいセクションが出てくる可能性がある。 appSettings セクションを丸ごと暗号化して良いのであれば上述の方法で対応できるが、暗号化したセクションは値の変更が手間になるため、通常は <secureAppSettings> のように、暗号化用のセクションを用意して使いたいはず。

この場合、Web.config にカスタムセクションの追加を行い、そのセクションに暗号化したいアプリ設定を含め、connectionStrings と同様の方法で暗号化することで対応できる。 <appSettings> と同じ形式のセクションで良ければ、以下のセクションを追加すれば、カスタムセクションが使用できる。

<configuration>
    <configSections>
        <section name="secureAppSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </configSections>

参考 URL

ASP.NET 使用時の注意点

セッション情報の格納方法について

ASP.NET のセッション情報は既定ではメモリに格納しているが (InProc モード)、これだと、ワーカープロセスが複数になった場合に各ワーカープロセス単位でセッション情報を格納して使用することになり、セッションが維持できなくなる。

Web.config で以下の設定を行うことでステートサービスを利用するようになり、ワーカープロセスの数に依らず、同じ場所にセッション情報を格納できるようになる。

<sessionState mode="StateServer"

ステートサービスにセッション情報を格納するには、格納対象のクラスオブジェクトがシリアライズ可能である必要がある。 そのためには対象クラスにシリアライズ可能の属性を設定する必要があるが、この状態であれば、IIS でワーカープロセスを増やす必要が出てきた場合もセッションの問題は発生しないので、開発時からステートサービスを使用するように変更しておくことを強く推奨。

参考 URL

ADO.NET 使用時の注意点

■ DB 接続クローズ漏れがないかの確認

ADO.NET は既定で 100 接続までをプールして使用し、上限に達すると接続時に例外が発生する。 使用していない接続は 30 分程すると自動でクローズされるため、ローカルでデバッグしている時は、クローズ漏れのバグがあってもこの問題が発生する可能性は低い。 下記 クエリ (SQL Server) で DB 側の接続数が確認できるが、操作する度にこの数が増えるようだと、リークが疑われる。

SELECT hostname, count(*)
FROM master..sysprocesses
WHERE hostname != ''
GROUP BY hostname

また、Windows のカウンターログもある。

[SQLServer:General Statistics] - [User Connections]

開発時にリークを見つけやすくするため、接続文字列の MaxPoolSize を 3 ~ 5 ぐらいにセットしておいた方が良いかも (接続プロセス単位の制限になる様子)。 クライアントアプリのようにプロセスがある程度のタイミングで終了する場合はリークが存在しても問題にはなりづらいが、ASP.NET のように同一プロセスから長時間多数の DB 接続を行う場合は、本番時に本問題が表面化しやすい。

参考 URL

Azure Data Lake Store について

  • 大容量、大量のデータを保存できるクラウドストレージ (サイズやデータ量の制限なし)
  • 構造は階層型ファイルシステムなので、Windowsファイルシステムと同じようなものとの認識で良い
  • 所謂ビッグデータの保存・分析にフォーカスしているため、小さいデータを扱うのはパフォーマンスが良くない (パフォーマンスの話なので、扱えないというわけではない)。 ドキュメントでは、「適切なファイル サイズの範囲は 256 MB ~ 1 GB で、100 MB を下回らず、2 GB を超えないのが理想」と記載されている
  • ファイルやフォルダを管理するためのメタデータが存在し、その関係で 1 オブジェクトについて 256 KB が最小課金単位となる。つまり、1 B のファイル 100 個と 256 KB のファイル 100 個は、請求額としては同じになる。小さいサイズのファイルを大量に保存するのは、課金額的にもあまりよろしくない
  • 単にデータ保存用のクラウドストレージとしてではなく、Azure Data Lake Analytics を使用することで、Data Lake Store 上に保存されたファイルを Azure 側で分析処理することが出来る。例えば、U-SQL と言う SQL ライクな Data Lake Analytics 用言語を使用して Data Lake Store 上の csv ファイルを読み込み、好きな条件に従ってデータをフィルタ・加工し、その結果を Data Lake Store 上にファイル保存することが出来る。これを Data Lake Analytics を使用しないで実現しようとすると、一度対象ファイルをローカルに全て落とした上でフィルタ・加工処理を行う必要があるが、ADLA を使用する事でこの作業が不要になる。ADL は GB, TB レベルの大容量サイズのファイルを保存する可能性があるので、これらの大容量データを Azure 上だけで分析できるのは、効率が良い。また、Azure 上で実行する分析処理は簡単にスケールアウトすることが出来るので (例えば、50 ユニットで並列処理)、料金の問題はあるが、処理速度を上げたい時の柔軟性も高い
  • Data Lake Analytics を使用する場合は、ファイルを保存する形式について事前によく検討する必要がある。csv などの形式で保存されていれば U-SQL で直接処理しやすいし、圧縮ファイルも gzip であれば対応しているらしい (未検証)
  • Data Lake Store の 1 リージョンに作成できるアカウントは、既定では最大で 10 なので注意。テストとかでポンポン作ると、上限に達してしまう可能性が高い。リージョン毎のカウントなのでリージョン変えれば作成できるが、どうしても上限に達したリージョンで新規アカウントを作成したい場合は、MS サポートに連絡して上げてもらうことが可能。ただし、それなりのビジネスインパクトの提出が必要

参考 URL

Azure Data Lake Store の .NET SDK 使用時の注意点

  • ADL の SDK は基本的に http を使用した Azure 上のデータ操作となるが、その関係で、エラーが発生しやすい
  • 思っている以上にエラーが発生する可能性があるので、基本的には、通信が発生する全てのメソッドについて、リトライ処理を実装するべき
  • データのアップロード、ダウンロードはストリーム操作で行うことも可能だが、データサイズが大きい場合 (100 MB 以上とか) は、一度ファイルに変換して、ファイル単位でのアップロード・ダウンロードメソッドを使用することも検討した方が良いかもしれない。エラー発生時のリトライ処理の必要性について上述したが、大容量データを操作する場合はそれが必須に近いのと、データの分割・結合やバッファ処理、メモリ管理、速度を上げるための並行処理など、考慮しなければならない点が多い。ファイル単位のアップロード・ダウンロードメソッドを使用すると、サイズに応じて分割・結合・並行処理をメソッド側で行ってくれるため、カスタムで実装・メンテする手間が省ける。ただ、自分が使用していた時は、このファイル単位のメソッドもあまり信頼性が高くなく、エラーにはならないけどアップロードが中途半端な状態で終わっていたりすることがあったので、処理完了後にファイルサイズをチェックするなどの検証処理を追加する必要があった (分割アップロード時に使用された一時ファイルが ADL 上に残ってゴミになることもあったので、その後処理とかも)。この辺りはメソッドの完成度などによっても変わってくるので、十分動作検証した上で、必要な処理を見極める必要がある
  • メソッドの完成度について上述したが、Azure Data Lake 自体がまだ出来てそこまで経っていないこともあり、SDK の方も頻繁に更新されて、新機能が追加されたり不具合修正が行われたりする。そのため、基本的には常に最新のライブラリを使用できるようなプロジェクト状態が望ましい

.NET の StringBuilder 使用時の注意点について

StringBuilder 使用時の注意点として、状況によってメモリを大量に使用する点がある。 string の結合だと数 MB ぐらいしか使用しない状況でも、StringBuilder だと 1GB ぐらい必要になったりするので、結果、ToString() でメモリ不足例外 (OutOfMemoryException) が発生する事がある。 使う場面に気をつける必要があるが、何となくの目安としては、以下。

  • Append する文字列のサイズが 1KB 以下
  • 且つ、Append 回数が 1,000 回以上