效能記錄器與回撥

下載 JDBC 驅動程式

從 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_executesqlsp_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() 返回 STATEMENTPREPARED_STATEMENTCALLABLE_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_EXECUTEsp_executesql STATEMENT_PREPEXECsp_prepexec STATEMENT_EXECUTEsp_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