Liczniki wydajności w ADO.NET

ADO.NET 2.0 wprowadzono rozszerzoną obsługę liczników wydajności, które obejmują obsługę systemów i System.Data.SqlClientSystem.Data.OracleClient. Liczniki System.Data.SqlClient wydajności dostępne w poprzednich wersjach ADO.NET zostały przestarzałe i zastąpione nowymi licznikami wydajności omówionymi w tym temacie. Liczniki wydajności ADO.NET umożliwiają monitorowanie stanu aplikacji i używanych zasobów połączenia. Liczniki wydajności można monitorować przy użyciu monitor wydajności systemu Windows lub można uzyskać do tego dostępu programowo przy użyciu PerformanceCounter klasy w System.Diagnostics przestrzeni nazw.

Dostępne liczniki wydajności

Obecnie dostępnych jest 14 różnych liczników System.Data.SqlClient wydajności i System.Data.OracleClient zgodnie z opisem w poniższej tabeli. Należy pamiętać, że nazwy poszczególnych liczników nie są zlokalizowane w regionalnych wersjach programu Microsoft .NET Framework.

Licznik wydajności opis
HardConnectsPerSecond Liczba połączeń na sekundę, które są wykonywane na serwerze bazy danych.
HardDisconnectsPerSecond Liczba rozłączeń na sekundę, które są wykonywane na serwerze bazy danych.
NumberOfActiveConnectionPoolGroups Liczba unikatowych grup puli połączeń, które są aktywne. Ten licznik jest kontrolowany przez liczbę unikatowych parametry połączenia znalezionych w domenie aplikacji.
NumberOfActiveConnectionPools Łączna liczba pul połączeń.
NumberOfActiveConnections Liczba aktywnych połączeń, które są obecnie używane. Uwaga: ten licznik wydajności nie jest domyślnie włączony. Aby włączyć ten licznik wydajności, zobacz Aktywowanie liczników poza domyślne.
NumberOfFreeConnections Liczba połączeń dostępnych do użycia w pulach połączeń. Uwaga: ten licznik wydajności nie jest domyślnie włączony. Aby włączyć ten licznik wydajności, zobacz Aktywowanie liczników poza domyślne.
NumberOfInactiveConnectionPoolGroups Liczba unikatowych grup puli połączeń oznaczonych do oczyszczania. Ten licznik jest kontrolowany przez liczbę unikatowych parametry połączenia znalezionych w domenie aplikacji.
NumberOfInactiveConnectionPools Liczba nieaktywnych pul połączeń, które nie miały żadnych ostatnich działań i oczekują na likwidację.
NumberOfNonPooledConnections Liczba aktywnych połączeń, które nie są w puli.
NumberOfPooledConnections Liczba aktywnych połączeń zarządzanych przez infrastrukturę buforowania połączeń.
NumberOfReclaimedConnections Liczba połączeń, które zostały odzyskane za pośrednictwem odzyskiwania pamięci, gdzie Close lub Dispose nie została wywołana przez aplikację. Nie jawne zamykanie lub usuwanie połączeń nie boli wydajności.
NumberOfStasisConnections Liczba połączeń oczekujących na ukończenie akcji i dlatego jest niedostępna do użycia przez aplikację.
SoftConnectsPerSecond Liczba aktywnych połączeń pobieranych z puli połączeń. Uwaga: ten licznik wydajności nie jest domyślnie włączony. Aby włączyć ten licznik wydajności, zobacz Aktywowanie liczników poza domyślne.
SoftDisconnectsPerSecond Liczba aktywnych połączeń zwracanych do puli połączeń. Uwaga: ten licznik wydajności nie jest domyślnie włączony. Aby włączyć ten licznik wydajności, zobacz Aktywowanie liczników poza domyślne.

Grupy puli Połączenie ion i pule Połączenie ion

W przypadku korzystania z uwierzytelniania systemu Windows (zintegrowane zabezpieczenia) należy monitorować zarówno liczniki wydajności, jak NumberOfActiveConnectionPoolGroups i NumberOfActiveConnectionPools . Przyczyną jest mapowanie grup puli połączeń na unikatowe parametry połączenia. W przypadku użycia zintegrowanych zabezpieczeń pule połączeń są mapowane na parametry połączenia i dodatkowo tworzą oddzielne pule dla poszczególnych tożsamości systemu Windows. Jeśli na przykład Fred i Julie, każdy w ramach tej samej domeny AppDomain, użyj parametry połączenia "Data Source=MySqlServer;Integrated Security=true", dla parametry połączenia zostanie utworzona grupa puli połączeń, a dwie dodatkowe pule zostaną utworzone, jedna dla Freda i jedna dla Julie. Jeśli Jan i Martha używają parametry połączenia z identycznym identyfikatorem logowania programu SQL Server, "Data Source=MySqlServer;User Id=lowPrivUser;Password=[PLACEHOLDER]"dla tożsamości lowPrivUser zostanie utworzona tylko jedna pula.

Aktywowanie liczników poza domyślnymi

Liczniki NumberOfFreeConnectionswydajności , NumberOfActiveConnections, SoftDisconnectsPerSecondi SoftConnectsPerSecond są domyślnie wyłączone. Dodaj następujące informacje do pliku konfiguracji aplikacji, aby je włączyć:

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

Pobieranie wartości licznika wydajności

Poniższa aplikacja konsolowa pokazuje, jak pobrać wartości liczników wydajności w aplikacji. Połączenie ions muszą być otwarte i aktywne, aby informacje zostały zwrócone dla wszystkich liczników wydajności ADO.NET.

Uwaga

W tym przykładzie użyto przykładowej bazy danych AdventureWorks dołączonej do programu SQL Server. Parametry połączenia podane w przykładowym kodzie zakładają, że baza danych jest zainstalowana i dostępna na komputerze lokalnym o nazwie wystąpienia SqlExpress oraz że utworzono identyfikatory logowania programu SQL Server zgodne z danymi podanymi w parametry połączenia. Może być konieczne włączenie identyfikatorów logowania programu SQL Server, jeśli serwer jest skonfigurowany przy użyciu domyślnych ustawień zabezpieczeń, które zezwalają tylko na uwierzytelnianie systemu Windows. Zmodyfikuj parametry połączenia zgodnie z potrzebami w twoim środowisku.

Przykład

Option Explicit On
Option Strict On

Imports System.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

    Private Shared Function GetIntegratedSecurityConnectionString() As String
        ' To avoid storing the connection string in your code,
        ' you can retrieve it from a configuration file.
        Return ("Data Source=.\SqlExpress;Integrated Security=True;" &
          "Initial Catalog=AdventureWorks")
    End Function

    Private Shared Function GetSqlConnectionString() As String
        ' To avoid storing the connection string in your code,
        ' you can retrieve it from a configuration file.
        Return ("Data Source=.\SqlExpress;User Id=LowPriv;Password=[PLACEHOLDER];" &
          "Initial Catalog=AdventureWorks")
    End Function

    Private Shared Function GetSqlConnectionStringDifferent() As String
        ' To avoid storing the connection string in your code,
        ' you can retrieve it from a configuration file.
        Return ("Initial Catalog=AdventureWorks;Data Source=.\SqlExpress;" & _
          "User Id=LowPriv;Password=[PLACEHOLDER];")
    End Function
End Class
using System;
using System.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("---------------------------");
    }

    private static string GetIntegratedSecurityConnectionString()
    {
        // To avoid storing the connection string in your code,
        // you can retrieve it from a configuration file.
        return @"Data Source=.\SqlExpress;Integrated Security=True;" +
          "Initial Catalog=AdventureWorks";
    }
    private static string GetSqlConnectionString()
    {
        // To avoid storing the connection string in your code,
        // you can retrieve it from a configuration file.
        return @"Data Source=.\SqlExpress;User Id=LowPriv;Password=[PLACEHOLDER];" +
          "Initial Catalog=AdventureWorks";
    }

    private static string GetSqlConnectionStringDifferent()
    {
        // To avoid storing the connection string in your code,
        // you can retrieve it from a configuration file.
        return @"Initial Catalog=AdventureWorks;Data Source=.\SqlExpress;" +
          "User Id=LowPriv;Password=[PLACEHOLDER];";
    }
}

Zobacz też