通过


SqlClient 中的性能计数器

适用于 .NET Framework

下载 ADO.NET

可以使用 Microsoft.Data.SqlClient 性能计数器来监视应用程序的状态及其使用的连接资源。 可以使用 Windows 性能监视器来监视性能计数器,或使用 PerformanceCounter 命名空间中的 System.Diagnostics 类以编程方式访问性能计数器。

重要

PerformanceCounter本文中所述的基于PerformanceCounter的方法需要.NET Framework,并且仅在 Windows上运行。 该 System.Diagnostics.PerformanceCounter 类在 .NET Core、.NET 5+ 或非 Windows 平台中不可用。 对于新式 .NET 应用程序中的跨平台监控,请使用 SqlClient 中的事件计数器

可用的性能计数器

当前有 14 个不同的性能计数器可用于 Microsoft.Data.SqlClient,如下表所述。

性能计数器 说明
HardConnectsPerSecond 每秒与数据库服务器连接的数量。
HardDisconnectsPerSecond 每秒与数据库服务器断开连接的数量。
NumberOfActiveConnectionPoolGroups 处于活动状态的唯一连接池组的数量。 此计数器由 AppDomain 中唯一连接字符串的数量控制。
NumberOfActiveConnectionPools 连接池的总数。
NumberOfActiveConnections 当前正在使用的活动连接的数量。 注意: 默认情况下,此性能计数器未启用。 若要启用此性能计数器,请参见激活默认关闭的计数器
NumberOfFreeConnections 连接池中可用连接的数量。 注意: 默认情况下,此性能计数器未启用。 若要启用此性能计数器,请参见激活默认关闭的计数器
NumberOfInactiveConnectionPoolGroups 用于修剪的独特连接池组的数量。 此计数器由 AppDomain 中唯一连接字符串的数量控制。
NumberOfInactiveConnectionPools 最近未进行任何活动且等待被释放的非活动连接池的数量。
NumberOfNonPooledConnections 未被池化的活动连接的数量。
NumberOfPooledConnections 由连接池基础结构管理的活动连接的数量。
NumberOfReclaimedConnections 已通过垃圾回收回收的连接数,其中应用程序未调用 CloseDispose。 注意:不显式关闭或释放连接会影响性能。
NumberOfStasisConnections 当前正在等待完成某项操作并因此无法供应用程序使用的连接的数量。
SoftConnectsPerSecond 从连接池中被提取的活动连接的数量。 注意: 默认情况下,此性能计数器未启用。 若要启用此性能计数器,请参见激活默认关闭的计数器
SoftDisconnectsPerSecond 被返回连接池的活动连接的数量。 注意: 默认情况下,此性能计数器未启用。 若要启用此性能计数器,请参见激活默认关闭的计数器

激活默认关闭的计数器

性能计数器 NumberOfFreeConnectionsNumberOfActiveConnectionsSoftDisconnectsPerSecondSoftConnectsPerSecond 默认情况下为关。 将下面的信息添加到应用程序配置文件中,以启用这些信息:

<system.diagnostics>  
  <switches>  
    <add name="ConnectionPoolPerformanceCounterDetail" value="4"/>  
    <!-- A value of 4 corresponds to System.Diagnostics.TraceLevel.Verbose -->
  </switches>  
</system.diagnostics>  

检索性能计数器值

下面的控制台应用程序演示如何在应用程序中检索性能计数器的值。 若要传回 Microsoft SqlClient 数据提供程序的 SQL Server 性能计数器的所有信息,连接必须处于打开并活动的状态。

注意

本示例使用 AdventureWorks 示例数据库。 示例代码中提供的连接字符串假定本地计算机已安装数据库且可用,并且你创建的登录名与连接字符串中提供的登录名匹配。 若服务器使用仅允许 Windows 身份验证的默认安全设置进行配置,你可能需要启用 SQL Server 登录。 可以根据您的环境需要修改连接字符串。

示例

using System;
using Microsoft.Data.SqlClient;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace SqlClient_PerformanceCounter
{
    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=.;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=.;User Id=<myUserID>;Password=<myPassword>;" +
              "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=.;" +
              "User Id=<myUserID>;Password=<myPassword>;";
        }
    }
}