共用方式為


SqlClient 中的事件計數器

適用於:Not supported. .NET Framework .NET Core .NET Standard

下載 ADO.NET

重要

.NET Core 3.1 和更高版本以及 .NET Standard 2.1 和更高版本為目標時,可使用事件計數器。 Microsoft.Data.SqlClient版本 3.0.0 開始提供此功能。

您可以使用 Microsoft.Data.SqlClient 事件計數器來監視應用程式的狀態,以及其所使用的連線資源。 您可以透過 .NET CLI global toolsperfView 來監視事件計數器,或透過 System.Diagnostics.Tracing 命名空間中的 EventListener 類別,以程式設計的方式加以存取。

可用的事件計數器

目前有 16 個不同的事件計數器可供 Microsoft.Data.SqlClient 使用,如下表所述:

名稱 顯示名稱 Description
active-hard-connections 目前連至伺服器的實際作用中連線 目前對資料庫伺服器開啟的連線數。
hard-connects 伺服器的實際連線速率 每秒對資料庫伺服器開啟的連線數。
hard-disconnects 伺服器的實際中斷連線速率 每秒鐘對資料庫伺服器中斷的連線數。
active-soft-connects 從連線集區擷取的作用中連線 從連線集區取用的已開啟連線數。
soft-connects 從連線集區擷取的連線速率 每秒從連線集區取用的連線數。
soft-disconnects 傳回至連線集區的連線速率 每秒傳回連線集區的連線數。
number-of-non-pooled-connections 未使用連線集區的連線數 尚未列入集區的作用中連線數。
number-of-pooled-connections 連線集區所管理的連線數 正由連接共用基礎結構所管理的現用連接的數目。
number-of-active-connection-pool-groups 作用中唯一連接字串數 使用中的唯一連接集區群組的數目。 這個計數器是由 AppDomain 中找到的唯一連接字串數目所控制。
number-of-inactive-connection-pool-groups 等待剪除的唯一連接字串數 標示為清除的唯一連接集區群組的數目。 這個計數器是由 AppDomain 中找到的唯一連接字串數目所控制。
number-of-active-connection-pools 作用中連線集區數 連接集區的總數。
number-of-inactive-connection-pools 非作用中連線集區數 最近沒有任何活動且正等待處置的非作用中連線集區數。
number-of-active-connections 使用中連線的數目 目前使用中的現用連接的數目。
number-of-free-connections 連線集區中就緒的連線數 連線集區中可用的開啟連線數。
number-of-stasis-connections 目前等待就緒的連線數 目前正等待動作完成且無法供應用程式使用的連線數。
number-of-reclaimed-connections 來自 GC 的回收連線數 透過記憶體回收作業回收的連線數,其中 CloseDispose 並非由應用程式呼叫。 注意 未明確關閉或處置連線會影響效能。

擷取事件計數器值

取用 EventCounters 有兩種主要方式,無論是同處理序或跨處理序皆適用。 如需詳細資訊,請參閱取用 EventCounters

跨處理序取用

在 Windows 中,您可以使用 PerfViewXperf 來收集事件計數器資料。 如需詳細資訊,請參閱在 SqlClient 中啟用事件追蹤。 您可以使用 dotnet-countersdotnet-trace,這些是可監視和收集事件計數器資料的 .NET 工具。

跨處理序範例

下列命令會每秒執行並收集一次 SqlClient 事件計數器的值。 將 EventCounterIntervalSec=1 取代為較高的值,可在計數器資料中以較低的細微性收集較小的追蹤。

PerfView /onlyProviders=*Microsoft.Data.SqlClient.EventSource:EventCounterIntervalSec=1 run "<application-Path>"

下列命令會每秒收集一次 SqlClient 事件計數器的值。

dotnet-trace collect --process-id <pid> --providers Microsoft.Data.SqlClient.EventSource:0:1:EventCounterIntervalSec=1

下列命令會每三秒監視一次 SqlClient 事件計數器的值。

dotnet-counters monitor Microsoft.Data.SqlClient.EventSource -p <process-id> --refresh-interval 3

下列命令會每秒監視一次所選 SqlClient 事件計數器的值。

dotnet-counters monitor Microsoft.Data.SqlClient.EventSource[hard-connects,hard-disconnects] -p <process-id>

在同處理序內取用

您可以透過 EventListener API 取用計數器值。 EventListener 是一種同處理序內的方式,可在應用程式內取用由 EventSource 執行個體撰寫的任何事件。 如需詳細資訊,請參閱EventListener

同處理序範例

下列範例程式碼會使用 EventCounterIntervalSec=1 擷取 Microsoft.Data.SqlClient.EventSource 事件, 並會撰寫計數器名稱,以及每次事件計數器更新時的 Mean 值。

注意

啟用此事件時,必須指定 EventCounterIntervalSec 屬性值。

using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;

// This listener class will listen for events from the SqlClientEventSource class.
// SqlClientEventSource is an implementation of the EventSource class which gives 
// it the ability to create events.
public class EventCounterListener : EventListener
{
    protected override void OnEventSourceCreated(EventSource eventSource)
    {
        // Only enable events from SqlClientEventSource.
        if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource"))
        {
            var options = new Dictionary<string, string>();
            // define time interval 1 second
            // without defining this parameter event counters will not enabled
            options.Add("EventCounterIntervalSec", "1");
            // enable for the None keyword
            EnableEvents(eventSource, EventLevel.Informational, EventKeywords.None, options);
        }
    }

    // This callback runs whenever an event is written by SqlClientEventSource.
    // Event data is accessed through the EventWrittenEventArgs parameter.
    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        if (eventData.Payload.FirstOrDefault(p => p is IDictionary<string, object> x && x.ContainsKey("Name")) is IDictionary<string, object> counters)
        {
            if (counters.TryGetValue("DisplayName", out object name) && name is string cntName
                && counters.TryGetValue("Mean", out object value) && value is double cntValue)
            {
                // print event counter's name and mean value
                Console.WriteLine($"{cntName}\t\t{cntValue}");
            }
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create a new event listener
        using (var listener = new EventCounterListener())
        {
            string connectionString = "Data Source=localhost; Integrated Security=true";

            for (int i = 0; i < 50; i++)
            {
                // Open a connection
                SqlConnection cnn = new SqlConnection(connectionString);
                cnn.Open();
                // wait for sampling interval happens
                System.Threading.Thread.Sleep(500);
            }
        }
    }
}
Actual active connections currently made to servers           0
Active connections retrieved from the connection pool         26
Number of connections not using connection pooling            0
Number of connections managed by the connection pool          26
Number of active unique connection strings              1
Number of unique connection strings waiting for pruning       0
Number of active connection pools               1
Number of inactive connection pools             0
Number of active connections            26
Number of ready connections in the connection pool            0
Number of connections currently waiting to be ready           0
...

另請參閱