-
Notifications
You must be signed in to change notification settings - Fork 0
Advanced
SQLServerNIO features a built-in diagnostic tool modeled after the SSMS Activity Monitor. It allows you to programmatically monitor server pressure, running processes, and resource waits by querying Dynamic Management Views (DMVs).
Requires
VIEW SERVER STATEpermissions. Available on SQL Server 2008 and newer.
let monitor = SQLServerActivityMonitor(client: client)
// 1. Take a one-shot snapshot of current server health
let snap = try await monitor.snapshot()
print("Total Processes: \(snap.processes.count)")
print("Active Waits: \(snap.waits.count)")
// 2. Kill a problematic session
try await monitor.killSession(sessionId: 55)Because many DMVs log cumulative statistics (e.g., total wait time since server restart), analyzing them requires taking two snapshots and comparing the delta. The streamSnapshots method handles this automatically.
// Stream snapshots every 5 seconds
let stream = monitor.streamSnapshots(every: 5.0, options: .init(includeSqlText: false))
for try await s in stream {
// waitsDelta exposes the resources waited on during the last 5 seconds
if let highestWait = s.waitsDelta?.first {
print("Highest recent wait: \(highestWait.waitType) (\(highestWait.waitTimeMs)ms)")
}
}(Querying includeSqlText: true or includeQueryPlan: true can be extremely heavy on the server; use cautiously).
You can pass SqlServerExecutionOptions to instruct the server on how to handle the execution context of your query.
import SQLServerKit
let options = SqlServerExecutionOptions(
mode: .auto, // Can be forced to .simple or .cursor
rowsetFetchSize: nil, // Reserved for future cursor support
progressThrottleMs: 120 // Throttle cadence
)
let result = try await client.query("SELECT * FROM GiganticTable", options: options)If you are developing inside an older architecture or directly inside SwiftNIO handlers, every async API in SQLServerNIO is mirrored with an EventLoopFuture version.
client.query("SELECT COUNT(*) AS count FROM sys.tables").whenComplete { result in
switch result {
case .success(let rows):
let count = rows.first?.column("count")?.int ?? 0
print("Total tables: \(count)")
case .failure(let error):
print("Query failed: \(error)")
}
}