從 13.4 版本開始,Microsoft JDBC SQL Server 驅動程式提供一個效能指標框架,用以追蹤關鍵驅動程式操作的時序。 你可以利用這個框架觀察並分析連線與語句執行行為,幫助找出應用程式與 SQL Server 互動時的延遲瓶頸。
指標可透過兩種機制獨立使用或共同使用:
-
程式化回撥 - 註冊
PerformanceLogCallback來在您的應用程式碼中接收指標。 -
Java 日誌 - 訂閱專用
java.util.logging日誌以擷取日誌輸出中的指標。
追蹤活動
驅動程式在兩個層面追蹤活動:連線與語句。
連結層級活動
| Activity | 說明 |
|---|---|
CONNECTION |
建立連結的總時間,包括所有子活動。 |
PRELOGIN |
是時候和伺服器進行 TDS 預登入協商了。 |
LOGIN |
是時候進行 TDS 登入和認證握手了。 |
TOKEN_ACQUISITION |
使用 Microsoft Entra 認證時,是時候取得聯邦認證憑證了。 |
語句層級活動
| Activity | 說明 |
|---|---|
STATEMENT_REQUEST_BUILD |
客戶端建立 TDS 請求的時間(參數綁定、SQL 處理、封包建構)。 僅做計時,不追蹤例外。 |
STATEMENT_FIRST_SERVER_RESPONSE |
從發送請求到收到第一個伺服器回應的時間。 僅做計時,不追蹤例外。 |
STATEMENT_PREPARE |
當sp_prepare時的prepareMethod=prepare時間。 |
STATEMENT_PREPEXEC |
綜合準備與執行的時間,透過 sp_prepexec。 |
STATEMENT_EXECUTE |
用於執行陳述式的時間(sp_executesql、sp_execute、直接 SQL 或批次)。 |
啟用效能指標
選項一:註冊回撥
註冊 a PerformanceLogCallback 以程式化接收效能資料:
SQLServerDriver.registerPerformanceLogCallback(new PerformanceLogCallback() {
@Override
public void publish(PerformanceActivity activity, int connectionId,
long durationMs, Exception exception) {
// Connection-level metrics
System.out.printf("Activity: %s, Connection: %d, Duration: %d ms%n",
activity, connectionId, durationMs);
}
@Override
public void publish(PerformanceActivity activity, int connectionId,
int statementId, long durationMs, Exception exception) {
// Statement-level metrics
System.out.printf("Activity: %s, Connection: %d, Statement: %d, Duration: %d ms%n",
activity, connectionId, statementId, durationMs);
}
});
使用奈秒級計時與敘述脈絡
從 13.6 版本開始,回調可透過覆寫 useNanoseconds()來選擇奈秒計時。 回調也可以呼叫 getCurrentUserSql() 並 getCurrentStatementType() 將語句層級事件與應用程式提交的 SQL 文字及執行的語句類型做關聯。
getCurrentStatementType() 返回 STATEMENT, PREPARED_STATEMENT或 CALLABLE_STATEMENT。 用 getCurrentApplicationName() 來根據連接 applicationName 屬性識別產生事件的連線或池。 如果 applicationName 沒有設定,該方法會回傳驅動程式的預設應用程式名稱。
SQLServerDriver.registerPerformanceLogCallback(new PerformanceLogCallback() {
@Override
public boolean useNanoseconds() {
return true;
}
@Override
public void publish(PerformanceActivity activity, int connectionId,
long durationNs, Exception exception) {
// Connection-level metrics don't have SQL statement context.
System.out.printf("Application: %s, Activity: %s, Connection: %d, Duration: %d ns%n",
getCurrentApplicationName(), activity, connectionId, durationNs);
}
@Override
public void publish(PerformanceActivity activity, int connectionId,
int statementId, long durationNs, Exception exception) {
String applicationName = getCurrentApplicationName();
String userSql = getCurrentUserSql();
StatementType statementType = getCurrentStatementType();
System.out.printf("Application: %s, Type: %s, Activity: %s, SQL: %s, Duration: %d ns%n",
applicationName, statementType, activity, userSql, durationNs);
}
});
奈秒計時需由使用者選擇啟用。 未覆蓋 useNanoseconds() 的回撥仍以毫秒計時。 當註冊回撥選擇加入時,專用的效能記錄器輸出也會使用奈秒,並標示持續時間為 ns;否則則使用 毫秒和 ms。 在某些平台上,呼叫 System.nanoTime() 的額外負擔可能比呼叫 System.currentTimeMillis() 更高。
回調上下文僅在相應 publish() 的呼叫時可用。
getCurrentApplicationName()可用於連線層級和陳述式層級事件,並會在 publish() 之外傳回 null。 當連接屬性尚未解析時,例如連接失敗且應用程式名稱尚未解決,該系統也可能回傳 null 。 SQL 上下文方法對於連線層級的事件、沒有 SQL 上下文的陳述式子活動指標,以及在 publish() 外部進行的呼叫,會回傳 null。
注意事項
SQL 文字可能包含敏感資料,無論是字面值還是註解。 在寫入日誌或遙測資料前,先將其淨化並套用組織的資料處理要求。
選項二:設定 Java 日誌
將效能指標記錄器 java.util.logging 配置為 FINE 層級。
在檔案 logging.properties 中:
com.microsoft.sqlserver.jdbc.PerformanceMetrics.Connection.level = FINE
com.microsoft.sqlserver.jdbc.PerformanceMetrics.Statement.level = FINE
handlers = java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = FINE
或者程式化地說:
Logger.getLogger("com.microsoft.sqlserver.jdbc.PerformanceMetrics.Connection")
.setLevel(Level.FINE);
Logger.getLogger("com.microsoft.sqlserver.jdbc.PerformanceMetrics.Statement")
.setLevel(Level.FINE);
準備方法對陳述活動的影響
追蹤的 PreparedStatement 活動取決於 prepareMethod 的連線屬性。 欲了解更多相關 prepareMethod資訊,請參見 設定連線屬性。
prepareMethod 設定 |
第一次處決 | 第二次處決 | 第三+執行 |
|---|---|---|---|
prepexec (預設值) |
STATEMENT_EXECUTE (sp_executesql) |
STATEMENT_PREPEXEC (sp_prepexec) |
STATEMENT_EXECUTE (sp_execute) |
prepare |
STATEMENT_PREPARE + STATEMENT_EXECUTE |
STATEMENT_EXECUTE |
STATEMENT_EXECUTE |
none |
STATEMENT_EXECUTE (直接 SQL) |
STATEMENT_EXECUTE (直接 SQL) |
STATEMENT_EXECUTE (直接 SQL) |
備註
在預設 prepexec 設定下,驅動程式會推遲準備,假設為單次使用。 第二次執行使用 sp_prepexec (結合準備與執行)。 從第三次執行開始,快取的控制代碼會透過 sp_execute 重複使用。 要強制 sp_prepexec 執行第一次呼叫,請將連接屬性 enablePrepareOnFirstPreparedStatementCall 設為 true。
樣本日誌輸出
以下輸出顯示了在預設PreparedStatement設定下,prepexec連續執行三次的活動:
ConnectionID:1, StatementID:1 Request build time, duration: 8ms
ConnectionID:1, StatementID:1 First server response, duration: 17ms
ConnectionID:1, StatementID:1 Statement execute, duration: 75ms ← 1st call: sp_executesql
ConnectionID:1, StatementID:1 Request build time, duration: 9ms
ConnectionID:1, StatementID:1 First server response, duration: 0ms
ConnectionID:1, StatementID:1 Statement prepexec, duration: 0ms ← 2nd call: sp_prepexec
ConnectionID:1, StatementID:1 Request build time, duration: 0ms
ConnectionID:1, StatementID:1 First server response, duration: 0ms
ConnectionID:1, StatementID:1 Statement execute, duration: 0ms ← 3rd call: sp_execute