Share via


Penghitung Performa di ADO.NET

ADO.NET 2.0 memperkenalkan dukungan yang diperluas untuk penghitung kinerja yang mencakup dukungan untuk System.Data.SqlClient dan System.Data.OracleClient. Penghitung performa System.Data.SqlClient yang tersedia di versi ADO.NET sebelumnya telah ditolak dan diganti dengan penghitung kinerja baru yang dibahas dalam topik ini. Anda dapat menggunakan penghitung kinerja ADO.NET untuk memantau status aplikasi Anda dan sumber daya koneksi yang digunakannya. Penghitung kinerja dapat dipantau dengan menggunakan Windows Performance Monitor atau dapat diakses secara terprogram menggunakan kelas PerformanceCounter di namespace layanan System.Diagnostics.

Penghitung Performa yang Tersedia

Saat ini ada 14 penghitung performa berbeda yang tersedia untuk System.Data.SqlClient dan System.Data.OracleClient seperti yang dijelaskan dalam tabel berikut. Perhatikan bahwa nama untuk penghitung individual tidak dilokalkan di seluruh versi regional Microsoft .NET Framework.

Penghitung kinerja Deskripsi
HardConnectsPerSecond Jumlah koneksi per detik yang sedang dibuat ke server database.
HardDisconnectsPerSecond Jumlah pemutusan sambungan per detik yang sedang dibuat ke server database.
NumberOfActiveConnectionPoolGroups Jumlah grup kumpulan koneksi unik yang aktif. Penghitung ini dikendalikan oleh jumlah string koneksi unik yang ditemukan di AppDomain.
NumberOfActiveConnectionPools Jumlah total kumpulan koneksi.
NumberOfActiveConnections Jumlah koneksi aktif yang saat ini sedang digunakan. Catatan: Penghitung performa ini tidak diaktifkan secara default. Untuk mengaktifkan penghitung performa ini, lihat Mengaktifkan Penghitung Nonaktif Secara Default.
NumberOfFreeConnections Jumlah koneksi yang tersedia untuk digunakan dalam kumpulan koneksi. Catatan: Penghitung performa ini tidak diaktifkan secara default. Untuk mengaktifkan penghitung performa ini, lihat Mengaktifkan Penghitung Nonaktif Secara Default.
NumberOfInactiveConnectionPoolGroups Jumlah grup kumpulan koneksi unik yang ditandai untuk pemangkasan. Penghitung ini dikendalikan oleh jumlah string koneksi unik yang ditemukan di AppDomain.
NumberOfInactiveConnectionPools Jumlah kumpulan koneksi tidak aktif yang belum memiliki aktivitas terbaru dan menunggu untuk dibuang.
NumberOfNonPooledConnections Jumlah koneksi aktif yang tidak dikumpulkan.
NumberOfPooledConnections Jumlah koneksi aktif yang dikelola oleh infrastruktur pengumpulan koneksi.
NumberOfReclaimedConnections Jumlah koneksi yang telah diperoleh kembali melalui pengumpulan sampah di mana Close atau Dispose tidak dipanggil oleh aplikasi. Tidak secara eksplisit menutup atau membuang koneksi merusak performa.
NumberOfStasisConnections Jumlah koneksi yang saat ini menunggu penyelesaian tindakan dan karenanya tidak tersedia untuk digunakan oleh aplikasi Anda.
SoftConnectsPerSecond Jumlah koneksi aktif yang ditarik dari kumpulan koneksi. Catatan: Penghitung performa ini tidak diaktifkan secara default. Untuk mengaktifkan penghitung performa ini, lihat Mengaktifkan Penghitung Nonaktif Secara Default.
SoftDisconnectsPerSecond Jumlah koneksi aktif yang dikembalikan ke kumpulan koneksi. Catatan: Penghitung performa ini tidak diaktifkan secara default. Untuk mengaktifkan penghitung performa ini, lihat Mengaktifkan Penghitung Nonaktif Secara Default.

Grup Kumpulan Koneksi dan Kumpulan Koneksi

Saat menggunakan Autentikasi Windows (keamanan terintegrasi), Anda harus memantau penghitung performa NumberOfActiveConnectionPoolGroups dan NumberOfActiveConnectionPools. Alasannya adalah bahwa kumpulan koneksi mengelompokkan peta ke string koneksi unik. Saat keamanan terintegrasi digunakan, kumpulan koneksi memetakan ke string koneksi dan juga membuat kumpulan terpisah untuk identitas Windows individual. Misalnya, jika Fred dan Julie, masing-masing dalam AppDomain yang sama, keduanya menggunakan string koneksi "Data Source=MySqlServer;Integrated Security=true", grup kumpulan koneksi dibuat untuk string koneksi, dan dua kumpulan tambahan dibuat, satu untuk Fred dan satu untuk Julie. Jika John dan Martha menggunakan string koneksi dengan login SQL Server yang identik, "Data Source=MySqlServer;User Id=lowPrivUser;Password=[PLACEHOLDER]", maka hanya satu kumpulan yang dibuat untuk identitas lowPrivUser.

Mengaktifkan Penghitung Off-By-Default

Penghitung performa NumberOfFreeConnections, NumberOfActiveConnections, SoftDisconnectsPerSecond, dan SoftConnectsPerSecond dinonaktifkan secara default. Tambahkan informasi berikut ke file konfigurasi aplikasi untuk mengaktifkannya:

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

Mengambil Nilai Penghitung Performa

Aplikasi konsol berikut menunjukkan cara mengambil nilai penghitung kinerja di aplikasi Anda. Koneksi harus terbuka dan aktif agar informasi dikembalikan untuk semua penghitung kinerja ADO.NET.

Catatan

Contoh ini menggunakan contoh database AdventureWorks yang disertakan dengan SQL Server. String koneksi yang disediakan dalam kode sampel mengasumsikan bahwa database diinstal dan tersedia di komputer lokal dengan nama instans SqlExpress, dan bahwa Anda telah membuat SQL Server login yang cocok dengan yang disediakan dalam string koneksi. Anda mungkin perlu mengaktifkan SQL Server masuk jika server Anda dikonfigurasi menggunakan pengaturan keamanan default yang hanya mengizinkan Autentikasi Windows. Ubah string koneksi seperlunya agar sesuai dengan lingkungan Anda.

Contoh

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];";
    }
}

Lihat juga