猫型iPS細胞研究所

Windows、Linux、iOS、DB、Network

DataBase SQLServer

「.NET」と「ASP.NET」からのSQL Serverへのコネクションを確認する(2)

投稿日:

「.NET」と「ASP.NET」からの接続には大きな違いがあります。
それは普通の?(exe形式の)アプリケーションか、Webアプリケーションかです。

この違いはアプリの終了というタイミングに大きく影響してきます。
「.NET」の場合は、例えどれだけコネクションがあろうとも、exeが終了した段階でコネクションはCloseされます。
更に正確にいうと、exeが終了した段階で、Close処理を実施していないコネクションも、ガベージコレクションによりCloseされます。

定期的に実行されるexeでは、もはやclose処理を意識しなくてもいいかもしれません。
このことは下記リンクのプログラムで確認することができます。

https://msdn.microsoft.com/ja-jp/library/ms254503(v=vs.110).aspx

ポイントは2つ。app.configと、コメントアウトです。

肝心なNumberOfPooledConnectionsを確認するには下記設定が必用です。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
    <system.diagnostics>
      <switches>
        <add name="ConnectionPoolPerformanceCounterDetail" value="4"/>
      </switches>
    </system.diagnostics>

</configuration>

またサンプルでは、重要な個所がコメントアウトされているので注意しましょう。

    Private Enum ADO_Net_Performance_Counters
        NumberOfActiveConnectionPools
        NumberOfReclaimedConnections
        HardConnectsPerSecond
        HardDisconnectsPerSecond
        NumberOfActiveConnectionPoolGroups
        NumberOfInactiveConnectionPoolGroups
        NumberOfInactiveConnectionPools
        NumberOfNonPooledConnections
        NumberOfPooledConnections
        NumberOfStasisConnections
        ' The following performance counters are more expensive to track.
        ' Enable ConnectionPoolPerformanceCounterDetail in your config file.
        '     SoftConnectsPerSecond
        '     SoftDisconnectsPerSecond
        '     NumberOfActiveConnections
        '     NumberOfFreeConnections
    End Enum

多くの人の感心は「ASP.NET」でのコネクションと解放でしょう。
同じプログラムを流用して、.NETのコネクションも確認することができます。

私は下記サンプルを使用して何度も試行しました。
Default.aspx

Imports System.Data.SqlClient
Imports System.Diagnostics
Imports System.Runtime.InteropServices


Partial Class _Default
    Inherits System.Web.UI.Page


    Private con As New SqlConnection
    Private PerfCounters(13) As PerformanceCounter
    Private connection As SqlConnection = New SqlConnection

    Private Enum ADO_Net_Performance_Counters
        NumberOfActiveConnectionPools
        NumberOfReclaimedConnections
        HardConnectsPerSecond
        HardDisconnectsPerSecond
        NumberOfActiveConnectionPoolGroups
        NumberOfInactiveConnectionPoolGroups
        NumberOfInactiveConnectionPools
        NumberOfNonPooledConnections
        NumberOfPooledConnections
        NumberOfStasisConnections
        ' The following performance counters are more expensive to track.
        ' Enable ConnectionPoolPerformanceCounterDetail in your config file.
        SoftConnectsPerSecond
        SoftDisconnectsPerSecond
        NumberOfActiveConnections
        NumberOfFreeConnections
    End Enum

    Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load

        con.ConnectionString = "Data Source=localhost;User Id=user;Password=pass;Initial Catalog=TestDB;Pooling=true;Min Pool Size=0;Max Pool Size=10;Connection Lifetime=1"
        con.Open()
        System.Threading.Thread.Sleep(5000)
        con.Close()

        Me.PerfCounters(13) = New PerformanceCounter()

        Dim instanceName As String = GetInstanceName()
        Dim apc As Type = GetType(ADO_Net_Performance_Counters)
        Dim i As Integer = 0
        Dim s As String = ""
        For Each s In [Enum].GetNames(apc)
            Me.PerfCounters(i) = New PerformanceCounter()
            Me.PerfCounters(i).CategoryName = ".NET Data Provider for SqlServer"
            Me.PerfCounters(i).CounterName = s
            Me.PerfCounters(i).InstanceName = instanceName
            i = (i + 1)
        Next


        Response.Write("---------------------------" & "<br/>")
        For Each p As PerformanceCounter In Me.PerfCounters
            Response.Write(p.CounterName & ":" & p.NextValue & "<br/>")
        Next
        Response.Write("---------------------------" & "<br/>")

    End Sub

    Private Declare Function GetCurrentProcessId Lib "kernel32.dll" () As Integer
    Private Function GetInstanceName() As String
        'This works for Winforms apps. 
        ''Dim instanceName As String = System.Reflection.Assembly.GetEntryAssembly.GetName.Name
        '''Dim instanceName As String = System.Web.Hosting.HostingEnvironment.ApplicationID
        ' Must replace special characters like (, ), #, /, \\ 
        Dim instanceName2 As String = AppDomain.CurrentDomain.FriendlyName.ToString.Replace("(", "[").Replace(")", "]").Replace("#", "_").Replace("/", "_").Replace("\\", "_")

        'For ASP.NET applications your instanceName will be your CurrentDomain's 
        'FriendlyName. Replace the line above that sets the instanceName with this: 
        Dim instanceName As String = AppDomain.CurrentDomain.FriendlyName.ToString.Replace("(", "[") _
            .Replace(")", "]").Replace("#", "_").Replace("/", "_").Replace("\\", "_")

        Dim pid As String = GetCurrentProcessId.ToString
        instanceName = (instanceName + ("[" & (pid & "]")))
        Console.WriteLine("Instance Name: {0}", instanceName)
        Console.WriteLine("---------------------------")
        Return instanceName
    End Function



End Class

もちろんapp.configの代わりにweb.configに以下の追加を行います。
web.config

  <system.codedom>
・・・・
  </system.codedom>
  <system.diagnostics>
  <switches>
    <add name="ConnectionPoolPerformanceCounterDetail"
         value="4"/>
  </switches>
  </system.diagnostics>
</configuration>

このようなクライアントからのアクセスと、SQLSERVERでのコネクション状況を確認すると見えてくるのが、
コネクションはクライアントが管理しているということです。

SQLSERVER側で

select hostname,count(*) from master..sysprocesses where hostname!='' group by hostname

というコマンドで接続状況を監視してみてください。

WEBサーバー側のweb.configを変更しなくて結構ですので上書きしてみてください。
もし、Closeされていなくて待ちとなっていたコネクションがあればCloseされることが確認できるはずです。

SQLSERVER側ではClose処理をしたコネクションなのか、まだ使用しているコネクションなのかが明確にはわかりません。
それはSQLSERVER側からみたら、どちらも使用中のコネクションだからです。
コネクションプールという概念は、実はクライアント側からみたコネクションの概念なのです。
再利用するためにプールに保存してるか、まだ使用中なのかはクライアントからみた概念なのです。

何にせよCloseは重要です。
Closeせずに再度接続をすればコネクションは増えます。
もしCloseしたコネクションがあれば再利用します。

Webアプリケーションでは、exeのように明確なアプリケーションの終了というタイミングがありません。
Close処理は、文字通りのClose処理ではなく、再利用可能であるという信号をおくるだけになります。
この点を注意しなくては、IISによる大規模なシステムは構築できません。

補足事項としてもう一点、コネクションはDataReaderにも発します。
コネクションから取得したデータをDataReaderに持たせるとします。
すると2つのコネクションが発生します。

リソースは閉じるという基本が重要です。
リソースはusingを使用すべし!ともいえるかもしれません。

Gooleアドセンス用336

Gooleアドセンス用336

-DataBase, SQLServer
-

執筆者:

関連記事

mysql

SQLで時間の重複をチェックする

同じ期間のデータは事前にチェックしてエラーにするという処理は、 あらゆる場面で想定されそうなことですが、 以外と難しかったのでここに方法をのこしておきます。 他にも素晴らしい方法があると思いますが、 …

mysql

CentOS6.4にMySQL5.6をインストールする

INDEX1 RPMのダウンロード2 tarの解凍3 rpmをyumでインストール4 サービス名が違う?5 mysql_secretにrootの初期パスワードはある6 mysql_secure_ins …

sqlserver

SQLServer テーブル単位のバックアップと復元

INDEX1 方法1.bcpユーティリティーを使用する方法1.0.1 (1)bcpユーティリティーでエクスポート1.0.2 (2)インポートするテーブルを作成します1.0.3 (3)データをインポート …

sqlserver

テーブル変更やインデックス追加時にSELECTできるのか

INDEX1 テーブルの変更は運用に影響するのか?2 テーブルの変更3 インデックスの追加 テーブルの変更は運用に影響するのか? 運用中のテーブルを変更しないといけない場合は多々あります。 運用中のテ …

sqlserver

SQLSERVERのトランザクションログの切り捨て・圧縮

トランザクションログはデータの登録・更新記録です。 INDEX1 復旧モデル2 切り捨て3 圧縮 復旧モデル トランザクションログを扱うには、トランザクションログがどのように使用されるかを知る必要があ …