Windows Azure

image

ASP.NET Univarsal Providers のセッションプロバイダを使ってみる」で、次のような紹介がありました。

ASP.NET Univarsal Providersのセッションプロバイダって、セッションの破棄もしてくれるの?という話題から。結論から言うと、「期限切れのセッションは削除してくれます。但しパフォーマンスに問題がありそうなやり方で。」となります。

定期ジョブを処理する機能SQL Server Agentが提供されていないSQL Aureへの対応としては仕方ないと思います。とは言え、アクセスの度に何をしているのかを調べてみようと思います。

毎回アクセス時にしていること(SQL的にね)

アクセスした時間に、セッション有効時間切れしてるものがあるかどうかを確認します。

SELECT
[Extent1].[SessionId] AS [SessionId],
[Extent1].[Created] AS [Created],
[Extent1].[Expires] AS [Expires],
[Extent1].[LockDate] AS [LockDate],
[Extent1].[LockCookie] AS [LockCookie],
[Extent1].[Locked] AS [Locked],
[Extent1].[SessionItem] AS [SessionItem],
[Extent1].[Flags] AS [Flags],
[Extent1].[Timeout] AS [Timeout]
FROM [dbo].[Sessions] AS [Extent1]
WHERE [Extent1].[Expires] < @now’

@now datetime2(7) 2011-08-07 06:38:04.1649431

期限切れのセッションがあれば、セッション情報を削除します。

delete [dbo].[Sessions]
where ([SessionId] = @0)

自分のセッション情報を取得します。

SELECT
[Limit1].[SessionId] AS [SessionId],
[Limit1].[Created] AS [Created],
[Limit1].[Expires] AS [Expires],
[Limit1].[LockDate] AS [LockDate],
[Limit1].[LockCookie] AS [LockCookie],
[Limit1].[Locked] AS [Locked],
[Limit1].[SessionItem] AS [SessionItem],
[Limit1].[Flags] AS [Flags],
[Limit1].[Timeout] AS [Timeout]
FROM ( SELECT TOP (1)
    [Extent1].[SessionId] AS [SessionId],
    [Extent1].[Created] AS [Created],
    [Extent1].[Expires] AS [Expires],
    [Extent1].[LockDate] AS [LockDate],
    [Extent1].[LockCookie] AS [LockCookie],
    [Extent1].[Locked] AS [Locked],
    [Extent1].[SessionItem] AS [SessionItem],
    [Extent1].[Flags] AS [Flags],
    [Extent1].[Timeout] AS [Timeout]
    FROM [dbo].[Sessions] AS [Extent1]
    WHERE [Extent1].[SessionId] = @id
)  AS [Limit1]

@id nvarchar(4000) lbw5dkyodyilchsipwuzo5dj/LM/W3SVC/1273337584/ROOT

無かったら、セッション情報を格納します。

insert [dbo].[Sessions]([SessionId], [Created], [Expires], [LockDate], [LockCookie], [Locked], [SessionItem], [Flags], [Timeout])
values (@0, @1, @2, @3, @4, @5, @6, @7, @8)

もっかい自分のセッション情報があるかを確認しセッション情報があれば、セッション情報の有効期限を更新します。

update [dbo].[Sessions]
set [Expires] = @0, [LockDate] = @1, [Locked] = @2
where ([SessionId] = @3)

まとめ

一回のアクセスで、都合8SQL流れているように見えます。アクセスする度に8SQL流れ、アクセスの都度セッションの有効期限を更新しています。

SessionテーブルのExpiresにインデックスを貼ってないので、アクセスの度にフルスキャンが走るのは間違いありません。しかし、データ量が少ない場合はインデックスが貼ってあっても、インデックスを使用せずにテーブルをフルスキャンします。一方、アクセスする度に有効期限の日付を更新するUpdate文が流れますので、インデックスが貼ってあると更新時のコストが増加します。

どのタイミングでインデックスが貼ってある効果が出るかまでは今回調べてませんが、同時セッション数10~20程度であれば、インデックスが無い方がパフォーマンス上優位だと思います。
同時セッション数が多いシステムで運用する場合には、インデックスを作成するとパフォーマンス改善する可能性があります。

Windows Azure

image

Windows Azure ASP.NET MVC 3 Web Role で使っているプロバイダ « ブチザッキで、

どうもこのASP.NET MVC 3 Webロールテンプレートで使っているセッションやメンバシッププロバイダ等各種プロバイダはEntityFrameworkベースのSystem.Web.Providersだそうです。

なんて紹介されています。
System.Web.Providersって、何やつ?どー使ってあげれば良いの?
ってことで、答えを「Deploying the Windows Azure ASP.NET MVC 3 Web Role」から拝借してきました。

MVC 3テンプレートでは、ASP.NET Universal Providerを使用しています。
セッションステートの格納先が初期設定では、SQL Expressを使用するようにしているASP.NET Universal Providerをテンプレートでは、使用しています。

<sessionState mode="Custom" customProvider="DefaultSessionProvider">
  <providers>
    <add name="DefaultSessionProvider"
         type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         connectionStringName="DefaultConnection"
         applicationName="/" />
  </providers>
</sessionState>

さて、ベストな対応はなんでしょうか?

SQL Azureにシンプルなデータベース「UniversalProviders」を作成します。

image

接続文字列をコピーし、所りゅーしょんのApplicationServiesDefaultConnection接続文字列をSQL Azureの接続文字列に変更します。

接続文字列では、MultipleActiveResultSets=True と設定する必要があります。

<connectionStrings>
  <add name="ApplicationServices"
       connectionString="Server=tcp:YOURDB.database.windows.net,1433;Database=UniversalProviders;User ID=YOURLOGIN@YOURDB;Password=YOURPWD;Trusted_Connection=False;Encrypt=True;MultipleActiveResultSets=True;"
       providerName="System.Data.SqlClient" />
  <add name="DefaultConnection"
       connectionString="Server=tcp:YOURDB.database.windows.net,1433;Database=UniversalProviders;User ID=YOURLOGIN@YOURDB;Password=YOURPWD;Trusted_Connection=False;Encrypt=True;MultipleActiveResultSets=True;"
       providerName="System.Data.SqlClient" />
</connectionStrings>

後は、Windows Azureにデプロイすれば動作します。

動作させた後、データベースを確認すると「dbo.Sessions」テーブルが作成されています。

ログオンし、ユーザのセットアップをすると、Windows Azureで動作するMVCアプリケーション内のメンバーシップとロールがすべてSQL Azureに格納されます。

Picture