SqlClient 中的事件計數器
適用於: .NET Framework .NET Core .NET Standard
重要
以 .NET Core 3.1 和更高版本以及 .NET Standard 2.1 和更高版本為目標時,可使用事件計數器。 Microsoft.Data.SqlClient
版本 3.0.0 開始提供此功能。
您可以使用 Microsoft.Data.SqlClient 事件計數器來監視應用程式的狀態,以及其所使用的連線資源。 您可以透過 .NET CLI global tools
和 perfView
來監視事件計數器,或透過 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 的回收連線數 | 透過記憶體回收作業回收的連線數,其中 Close 或 Dispose 並非由應用程式呼叫。 注意 未明確關閉或處置連線會影響效能。 |
擷取事件計數器值
取用 EventCounters 有兩種主要方式,無論是同處理序或跨處理序皆適用。 如需詳細資訊,請參閱取用 EventCounters。
跨處理序取用
在 Windows 中,您可以使用 PerfView 和 Xperf 來收集事件計數器資料。 如需詳細資訊,請參閱在 SqlClient 中啟用事件追蹤。 您可以使用 dotnet-counters 和 dotnet-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
...