語言

ADO.NET 中的效能計數器

在 .NET 框架上,Microsoft.Data.SqlClient 會公開 Windows 效能計數器,用來監控你的應用程式及其連線資源。 安裝 Microsoft.Data.SqlClient NuGet 套件,並使用 Microsoft.Data.SqlClient 命名空間來執行本文中的 SQL 範例。 請透過 Windows 效能監視器 或 PerformanceCounter 讀取這些計數器。

在現代 .NET 上,Microsoft.Data.SqlClient 暴露的是 EventCounters,而非 Windows 效能計數器。 欲了解更多資訊,請參閱 SqlClient 中的事件計數器。

可用的效能計數器

在 .NET Framework 中,下列 14 個效能計數器可用於 System.Data.OracleClient 和 Microsoft.Data.SqlClient。 請注意,個別計數器的名稱並未在 Microsoft .NET Framework 的區域版本中當地語系化。

效能計數器 描述
HardConnectsPerSecond 每秒鐘對資料庫伺服器所建立的連接數目。
HardDisconnectsPerSecond 每秒鐘對資料庫伺服器所進行的中斷連接數目。
NumberOfActiveConnectionPoolGroups 使用中的唯一連線池群組的數目。 這個計數器是由 AppDomain 中找到的唯一連接字串數目所控制。
NumberOfActiveConnectionPools 連接集區的總數。
NumberOfActiveConnections 目前使用中的現用連接的數目。 注意:此效能計數器預設為未啟用。 若要啟用此效能計數器,請參閱啟動依預設關閉的計數器。
NumberOfFreeConnections 連線池中可用的連接數目。 注意:此效能計數器預設為未啟用。 若要啟用此效能計數器,請參閱啟動依預設關閉的計數器。
NumberOfInactiveConnectionPoolGroups 標示為清除的獨特連接池群組的數目。 這個計數器是由 AppDomain 中找到的唯一連接字串數目所控制。
NumberOfInactiveConnectionPools 最近未有任何活動且正等候處置 (Dispose) 的非現用連接集區數目。
NumberOfNonPooledConnections 尚未共用的現用連接的數目。
NumberOfPooledConnections 正由連接共用基礎結構所管理的現用連接的數目。
NumberOfReclaimedConnections 已透過記憶體回收作業回收的連接數目,其中 Close 或 Dispose 並非由應用程式呼叫。 未明確關閉或釋放連接會損及效能。
NumberOfStasisConnections 目前正等候執行完成動作,因此無法供應用程式使用的連接數目。
SoftConnectsPerSecond 正從連接集區提取的現用連接的數目。 注意:此效能計數器預設為未啟用。 若要啟用此效能計數器,請參閱啟動依預設關閉的計數器。
SoftDisconnectsPerSecond 正在被傳回至連接池的主動連線數目。 注意:此效能計數器預設為未啟用。 若要啟用此效能計數器,請參閱啟動依預設關閉的計數器。

連接集區群組和連接集區

在使用「Windows 驗證」(整合式安全性) 時,必須同時監控 NumberOfActiveConnectionPoolGroups 和 NumberOfActiveConnectionPools 效能計數器。 原因是連接集區群組會對應至唯一的連接字串。 使用整合式安全性時,連接集區會對應至連接字串,並針對個別的 Windows 識別 (Identity) 額外建立獨立的集區。 例如,如果 Fred 和 Julie 位於相同的 AppDomain 內,且兩者都使用連接字串 "Data Source=MySqlServer;Integrated Security=true",則會針對連接字串建立連接集區群組,並針對 Fred 和 Julie 建立兩個額外的集區。 如果 John 和 Martha 使用具有相同 SQL Server 登入資訊的連接字串 "Data Source=MySqlServer;User Id=lowPrivUser;Password=[PLACEHOLDER]",那麼只會為該身份創建一個單一池 lowPrivUser。

重要

Microsoft建議您使用可用的最安全驗證流程。 如果您正在連接 Azure SQL,建議使用的驗證方法為 Azure 資源受控識別。

啟動預設關閉的計數器

效能計數器 NumberOfFreeConnections、NumberOfActiveConnections、SoftDisconnectsPerSecond 和 SoftConnectsPerSecond 預設會關閉。 請將下列資訊加入至應用程式的組態檔加以啟用:

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

擷取效能計數器值

下列主控台應用程式顯示如何在應用程式中擷取效能計數器值。 連接必須保持開啟並處於活動狀態,才能傳回所有 ADO.NET 效能計數器的資訊。

注意

此範例使用了 SQL Server 附帶的範例 AdventureWorks 資料庫。 範例程式碼中提供的連接字串假設該資料庫已安裝且可用於具有 SqlExpress 執行個體名稱的本機電腦上,而且您已建立符合連接字串中所提供登入的 SQL Server 登入。 如果伺服器是使用僅允許「Windows 驗證」的預設安全性設定而設定,則可能需要啟用 SQL Server 登入。 請視環境需要修改連接字串。

範例

Option Explicit On
Option Strict On

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

Class Program

    Private PerfCounters(9) As PerformanceCounter
    Private connection As SqlConnection = New SqlConnection

    Public Shared Sub Main()
        Dim prog As Program = New Program
        ' Open a connection and create the performance counters.
        prog.connection.ConnectionString = _
           GetIntegratedSecurityConnectionString()
        prog.SetUpPerformanceCounters()
        Console.WriteLine("Available Performance Counters:")

        ' Create the connections and display the results.
        prog.CreateConnections()
        Console.WriteLine("Press Enter to finish.")
        Console.ReadLine()
    End Sub

    Private Sub CreateConnections()
        ' List the Performance counters.
        WritePerformanceCounters()

        ' Create 4 connections and display counter information.
        Dim connection1 As SqlConnection = New SqlConnection( _
           GetIntegratedSecurityConnectionString)
        connection1.Open()
        Console.WriteLine("Opened the 1st Connection:")
        WritePerformanceCounters()

        Dim connection2 As SqlConnection = New SqlConnection( _
           GetSqlConnectionStringDifferent)
        connection2.Open()
        Console.WriteLine("Opened the 2nd Connection:")
        WritePerformanceCounters()

        Console.WriteLine("Opened the 3rd Connection:")
        Dim connection3 As SqlConnection = New SqlConnection( _
           GetSqlConnectionString)
        connection3.Open()
        WritePerformanceCounters()

        Dim connection4 As SqlConnection = New SqlConnection( _
           GetSqlConnectionString)
        connection4.Open()
        Console.WriteLine("Opened the 4th Connection:")
        WritePerformanceCounters()

        connection1.Close()
        Console.WriteLine("Closed the 1st Connection:")
        WritePerformanceCounters()

        connection2.Close()
        Console.WriteLine("Closed the 2nd Connection:")
        WritePerformanceCounters()

        connection3.Close()
        Console.WriteLine("Closed the 3rd Connection:")
        WritePerformanceCounters()

        connection4.Close()
        Console.WriteLine("Closed the 4th Connection:")
        WritePerformanceCounters()
    End Sub

    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

    Private Sub SetUpPerformanceCounters()
        connection.Close()
        Me.PerfCounters(9) = 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
    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

        ' 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:
        'instanceName = 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

    Private Sub WritePerformanceCounters()
        Console.WriteLine("---------------------------")
        For Each p As PerformanceCounter In Me.PerfCounters
            Console.WriteLine("{0} = {1}", p.CounterName, p.NextValue)
        Next
        Console.WriteLine("---------------------------")
    End Sub
End Class
using System;
using Microsoft.Data.SqlClient;
using System.Diagnostics;
using System.Runtime.InteropServices;

class Program
{
    PerformanceCounter[] PerfCounters = new PerformanceCounter[10];
    SqlConnection connection = new SqlConnection();

    static void Main()
    {
        Program prog = new Program();
        // Open a connection and create the performance counters.
        prog.connection.ConnectionString =
           GetIntegratedSecurityConnectionString();
        prog.SetUpPerformanceCounters();
        Console.WriteLine("Available Performance Counters:");

        // Create the connections and display the results.
        prog.CreateConnections();
        Console.WriteLine("Press Enter to finish.");
        Console.ReadLine();
    }

    private void CreateConnections()
    {
        // List the Performance counters.
        WritePerformanceCounters();

        // Create 4 connections and display counter information.
        SqlConnection connection1 = new SqlConnection(
              GetIntegratedSecurityConnectionString());
        connection1.Open();
        Console.WriteLine("Opened the 1st Connection:");
        WritePerformanceCounters();

        SqlConnection connection2 = new SqlConnection(
              GetSqlConnectionStringDifferent());
        connection2.Open();
        Console.WriteLine("Opened the 2nd Connection:");
        WritePerformanceCounters();

        SqlConnection connection3 = new SqlConnection(
              GetSqlConnectionString());
        connection3.Open();
        Console.WriteLine("Opened the 3rd Connection:");
        WritePerformanceCounters();

        SqlConnection connection4 = new SqlConnection(
              GetSqlConnectionString());
        connection4.Open();
        Console.WriteLine("Opened the 4th Connection:");
        WritePerformanceCounters();

        connection1.Close();
        Console.WriteLine("Closed the 1st Connection:");
        WritePerformanceCounters();

        connection2.Close();
        Console.WriteLine("Closed the 2nd Connection:");
        WritePerformanceCounters();

        connection3.Close();
        Console.WriteLine("Closed the 3rd Connection:");
        WritePerformanceCounters();

        connection4.Close();
        Console.WriteLine("Closed the 4th Connection:");
        WritePerformanceCounters();
    }

    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
    }

    private void SetUpPerformanceCounters()
    {
        connection.Close();
        this.PerfCounters = new PerformanceCounter[10];
        string instanceName = GetInstanceName();
        Type apc = typeof(ADO_Net_Performance_Counters);
        int i = 0;
        foreach (string s in Enum.GetNames(apc))
        {
            this.PerfCounters[i] = new PerformanceCounter();
            this.PerfCounters[i].CategoryName = ".NET Data Provider for SqlServer";
            this.PerfCounters[i].CounterName = s;
            this.PerfCounters[i].InstanceName = instanceName;
            i++;
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern int GetCurrentProcessId();

    private string GetInstanceName()
    {
        //This works for Winforms apps.
        string instanceName =
            System.Reflection.Assembly.GetEntryAssembly().GetName().Name;

        // Must replace special characters like (, ), #, /, \\
        string instanceName2 =
            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:
        // instanceName = AppDomain.CurrentDomain.FriendlyName.ToString().Replace('(','[')
        // .Replace(')',']').Replace('#','_').Replace('/','_').Replace('\\','_');

        string pid = GetCurrentProcessId().ToString();
        instanceName = instanceName + "[" + pid + "]";
        Console.WriteLine("Instance Name: {0}", instanceName);
        Console.WriteLine("---------------------------");
        return instanceName;
    }

    private void WritePerformanceCounters()
    {
        Console.WriteLine("---------------------------");
        foreach (PerformanceCounter p in this.PerfCounters)
        {
            Console.WriteLine("{0} = {1}", p.CounterName, p.NextValue());
        }
        Console.WriteLine("---------------------------");
    }
}

另請參閱