在 Fabric Data Warehouse 中使用使用者資料功能(預覽)

適用於:Microsoft Fabric 中的✅ 資料庫

Important

這項功能目前處於預覽階段。

在Fabric Data Warehouse中,T-SQL 開發者可以從 T-SQL 查詢中呼叫Fabric使用者資料函式。 倉庫中的 T-SQL 代理函式會呼叫已發佈的使用者資料函數項目中所引用的 Python 函式。

利用此整合來擴充可重用 Python 邏輯的 T-SQL,適用於以下情境:

  • 使用專門的 PyPI 套件處理空間、數值或資料科學工作負載。
  • 用 Python 實作自訂商業邏輯。
  • 呼叫外部 API。
  • 與其他 Fabric 項目及 Azure 服務互動,例如倉庫、湖屋、SQL 資料庫或 Cosmos 資料庫。

倉庫與 Fabric 使用者資料函式互動的示意圖,透過倉庫代理函式呼叫 U D F。

本文說明如何參考 Fabric Data Warehouse 已發佈的使用者資料函式,並在 T-SQL 查詢中使用。

先決條件

要使用 Fabric Data Warehouse 的使用者資料函式,你需要:

建立並發布使用者資料函式

在你能從倉庫呼叫使用者資料函式之前,先建立並發佈該函式在使用者資料函數項目中。 完整步驟及範例 Python 函式,請參閱 Fabric 中建立使用者資料函式項目。

你可以建立的 Python 使用者資料函式如下範例所示:

import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function()
def hello_fabric(name: str) -> str:
    # Your function logic here
    return name

你可以用使用者資料函式的項目名稱來綁定 T-SQL 代理函式到 Python 函式。

建立一個 T-SQL 代理函式

在你的倉庫建立一個 T-SQL 函式,並用 clause AS EXTERNAL FUNCTION 綁定到 已發佈的 Python 函式。

CREATE OR ALTER FUNCTION dbo.hello_fabric
AS EXTERNAL FUNCTION FunctionSetName.hello_fabric;

請將 FunctionSetName 替換為您的 user data functions 項目名稱,並將 hello_fabric 替換為已發佈的 Python 函式名稱。

小提示

你可以從使用者資料函式的經驗中產生調用碼,並以此作為倉庫代理函式的起點。

預設情況下,CREATE FUNCTION 陳述式會根據遠端 Fabric 使用者資料函式(UDF)的定義推導參數清單與回傳類型。 你可以在函式定義中明確指定推斷回傳類型來覆寫它。 提供回傳類型在你想揭露比遠端函式元資料推斷出的更精確的回傳類型時非常有用。

CREATE OR ALTER FUNCTION dbo.hello_fabric
RETURNS VARCHAR(100)
AS EXTERNAL FUNCTION FunctionSetName.hello_fabric;

例如,Python str 回傳值通常推斷為 VARCHAR(MAX),但若函式總是回傳已知最大長度的值,您可以明確定義回傳類型為 或其他VARCHAR(100)適當長度,以提供更準確的元資料與類型資訊。

在 T-SQL 查詢中使用代理函式

建立代理函式後,像其他使用者自訂函式一樣從 T-SQL 呼叫它。

在查詢表達式中使用代理函數,例如:

  • SELECT 清單。
  • WHERE 條款。
  • GROUP BY 條款。
  • UPDATE 和 INSERT 陳述式中的運算式。

以下模式展示如何從查詢呼叫代理函式:

SELECT dbo.<proxy_function_name>(<arguments>) AS function_result;

關於進階的 Python 模式、支援型別、連線及上下文物件,請參閱 Fabric 使用者資料函式程式設計模型概述。

配置批次模式執行

Fabric Data Warehouse 可以以批次模式執行外部使用者資料函式。

批次模式執行會在一次請求中向遠端 Fabric 使用者資料函數(UDF)服務發送多個函式呼叫,降低網路負擔與請求延遲。 一個批次最多可包含 900 個函式呼叫。

批次模式通常用於同一函式對一個或多個資料表欄位的值,讓查詢處理器能在單一遠端呼叫中評估多個列,而不必為每個列發出獨立請求。 此方法能顯著提升查詢效能,特別是在大型資料集及高延遲外部函式呼叫時。

例如,當查詢對欄位中的每個值套用使用者資料函式時,Fabric Data Warehouse可以將輸入值分成批次,並一起提交以供遠端處理。 遠端服務會回傳對應的結果批次,這些結果隨後會整合進查詢執行管線中。

要啟用使用者資料功能的批次模式:

  1. 打開 使用者資料功能 項目。
  2. 請前往 圖書館管理>設定。
  3. 開啟 預覽功能。

在 max_batch_size=900 裝飾器中將 @udf.function() 設為,讓倉儲在每次呼叫中最多可傳送 900 筆輸入資料列:

備註

max_batch_size該參數僅在啟用批次模式預覽時可用。

import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function(max_batch_size=900)
def normalizeText(value: str) -> str:
    return value.strip().lower()

當你建立一個參照批次啟用使用者資料函數(UDF)的 T-SQL 代理函式後,Fabric Data Warehouse 會自動偵測批次配置,包括遠端函式定義的最大批次大小。 當查詢模式支援批次處理時,查詢處理器會將多個函式調用分組成批次,並送交遠端服務執行,而非為每列發出個別請求。

列出資料倉儲中的使用者資料功能

您以 AS EXTERNAL FUNCTION 建立的使用者資料函式會以 sys.objects 物件類型顯示在 XF 中。

若要列出倉庫中的使用者資料函式,請依 type = 'XF' 篩選 sys.objects。

SELECT SCHEMA_NAME(schema_id) AS schema_name, name, object_id, type, type_desc
FROM sys.objects
WHERE type = 'XF';

若要列出一般純量函數(FN)與使用者資料函數(XF),以及它們的參數與回傳類型簽名,請使用 sys.parameters 和 sys.types:

WITH metadata AS
(
    SELECT o.schema_id, o.object_id, o.name, p.parameter_id, p.name AS parameter_name, t.name AS type_name
    FROM sys.objects AS o
    INNER JOIN sys.parameters AS p
        ON p.object_id = o.object_id
    INNER JOIN sys.types AS t
        ON t.user_type_id = p.user_type_id
    WHERE o.type IN ('FN', 'XF')
),
signature AS
(
    SELECT SCHEMA_NAME(schema_id) AS schema_name,
           name,
           ANY_VALUE(
               CASE WHEN parameter_id = 0 THEN type_name END
           ) AS return_type,
           CONCAT(
               SCHEMA_NAME(schema_id),
               '.',
               name,
               '(',
               STRING_AGG(
                   CASE
                       WHEN parameter_id > 0
                       THEN CONCAT(parameter_name, ' ', type_name)
                   END,
                   ', '
               ) WITHIN GROUP (ORDER BY parameter_id),
               ') -> ',
               MAX(CASE WHEN parameter_id = 0 THEN type_name END)
           ) AS signature
    FROM metadata
    GROUP BY schema_id, object_id, name
)
SELECT *
FROM signature;

備註

  • T-SQL 代理函式依賴於已發佈的使用者資料函式項目及函式名稱。 如果你重新命名或刪除 Python 函式,請相應更新倉庫代理函式。
  • 使用者資料函數程式設計模型定義了支援的輸入與輸出類型。 確認 Python 參數和回傳註解是否支援你的 T-SQL 查詢通過的值。
  • 使用者資料函式對請求有效載荷大小、執行逾時、回應大小、函式庫大小及日誌保留有服務限制。 關於目前的限制,請參見服務細節及 Fabric 使用者資料功能的限制。
  • 參數名稱必須使用 camelCase 格式,並包含型別註記。 以 裝飾的 @udf.function() 函式也必須指定回傳類型。 完整的語法規則,請參閱 Fabric 使用者資料函式程式設計模型概述。
  • 關於不需要自訂 Python 程式碼的內建文字轉換函數,請參見「使用 AI 函數(預覽)」。
  • 使用者資料函式對請求有效載荷大小、執行逾時、回應大小、函式庫大小及日誌保留有服務限制。 關於目前的限制,請參見服務細節及 Fabric 使用者資料功能的限制。
  • 參數名稱必須採用 camelCase,並包含型別註解。 以 裝飾的 @udf.function() 函式也必須指定回傳類型。 完整的語法規則,請參閱 Fabric 使用者資料函式程式設計模型概述。
  • 關於不需要自訂 Python 程式碼的內建文字轉換函數,請參見「使用 AI 函數(預覽)」。

範例

以下情境展示了利用使用者資料函式擴展Fabric Data Warehouse的常見方法。

答: 擴充 T-SQL 與 IP 位址解析

當你的倉儲查詢需要內建 T-SQL 函式無法提供的功能時,可以使用 Python 的使用者資料函式。 例如,你可以使用 IP 位址套件來回傳某個 IP 位址所屬的子網路。 當查詢處理多列的 IP 位址時,你可以分批套用這個功能。 關於設定步驟,請參見 配置批次模式。

備註

如果函式使用的套件不屬於 Python 標準函式庫,請先在函式庫管理中加入該套件,再發佈使用者資料函式項目。 這個例子使用了這個 netaddr 套件。

在使用者資料函數項目中定義並發布 Python 函式:

from netaddr import IPNetwork
import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function(max_batch_size=900)
def ipSubnet(ipAddress: str, prefixLength: int = 24) -> str:
    return str(IPNetwork(f"{ipAddress}/{prefixLength}").cidr)

在倉庫中建立一個 T-SQL 代理函式,參考已發佈的 Python 函式:

CREATE OR ALTER FUNCTION dbo.ip_subnet
AS EXTERNAL FUNCTION inet.ipSubnet;

從倉庫查詢中呼叫代理函式:

SELECT dbo.ip_subnet('192.168.1.25', 24) AS subnet;

預期結果:192.168.1.0/24

B. 呼叫外部公開 API

當倉庫查詢需要呼叫外部 API 作為資料豐富工作流程的一部分時,可以使用使用者資料函式。

在 Fabric 的 SQL 資料庫中,Azure SQL Database 和 Azure SQL 受控執行個體 sys.sp_invoke_external_rest_endpoint 會呼叫 HTTPS REST 端點。 在Fabric Data Warehouse中,使用者資料函式可以透過將 HTTPS 呼叫包裝在 Python,並透過代理函式暴露給 T-SQL 來提供替代模式。

Caution

呼叫外部端點可以將資料傳輸到倉庫外。 使用核准端點,避免未經授權傳送敏感資料,並遵守組織的安全與合規要求。

備註

在函式發佈前,先在函式庫管理中新增必要的第三方函式庫,例如 requests。

在使用者資料函數項目中定義並發布 Python 函式。 此範例使用類似的 sys.sp_invoke_external_rest_endpoint參數名稱:

import json
import requests
import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function()
def invokeExternalRestEndpoint(
    url: str,
    method: str = "GET",
    payload: str | None = None,
    headers: str | None = None,
    timeout: int = 30
) -> str:
    requestHeaders = json.loads(headers) if headers else None
    requestPayload = payload if payload else None

    response = requests.request(
        method=method,
        url=url,
        data=requestPayload,
        headers=requestHeaders,
        timeout=timeout
    )
    response.raise_for_status()
    return response.text

在倉庫中建立一個 T-SQL 代理函式:

CREATE OR ALTER FUNCTION dbo.invoke_external_rest_endpoint
AS EXTERNAL FUNCTION api.invokeExternalRestEndpoint;

從倉庫查詢中呼叫代理函式:

SELECT dbo.invoke_external_rest_endpoint(
    'https://ipapi.co/8.8.8.8/country_name/',
    'GET',
    NULL,
    NULL,
    30
) AS response;

C. 使用可設定的保留期

當倉儲查詢需要集中管理的 Fabric 變數函式庫的設定值時,可以使用使用者資料函式。 例如,將保留期存於變數函式庫中,透過代理函式檢索,並用作 T-SQL 函式的DATEADD數字參數。

在發佈函式之前,先將使用者資料函數項目中的連線加入變數庫,並注意連線別名。 此範例中的變數庫包含 RETENTION_DAYS 一個值,例如 90。

在使用者資料函數項目中定義並發布 Python 函式:

import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.connection(argName="varLib", alias="WarehouseConfig")
@udf.function()
def getRetentionDays(varLib: fn.FabricVariablesClient) -> int:
    variables = varLib.getVariables()
    return int(variables["RETENTION_DAYS"])

用你變數函式庫連線的別名來替換 WarehouseConfig 。

在倉庫中建立一個 T-SQL 代理函式:

CREATE OR ALTER FUNCTION dbo.get_retention_days
AS EXTERNAL FUNCTION config.getRetentionDays;

在持久的 T-SQL 連線中,取出一次設定值並用 sp_set_session_context以下方式儲存:

DECLARE @retention_days int = dbo.get_retention_days();

EXECUTE sys.sp_set_session_context
    @key = N'retention_days',
    @value = @retention_days,
    @read_only = 1;

此值在整個工作階段存續期間都可供使用。 使用 SESSION_CONTEXT 取回它,並在搭配 sql_variant 和 int 使用之前,先將它從 DATEADD 轉換為 GETDATE。 例如,計算一個保留截止線:

SELECT DATEADD(
    day,
    -CONVERT(int, SESSION_CONTEXT(N'retention_days')),
    GETDATE()
) AS retention_cutoff;

在另一個語句中重複使用相同的會話值來過濾資料表:

SELECT *
FROM dbo.events
WHERE event_timestamp >= DATEADD(
    day,
    -CONVERT(int, SESSION_CONTEXT(N'retention_days')),
    GETDATE()
);

Important

使用來自可維持持續 T-SQL 連線之用戶端的這個模式,例如 SQL Server Management Studio 或 Visual Studio Code 的 MSSQL 擴充功能。 Fabric 入口網站的 SQL 查詢編輯器不支援 sp_set_session_context,且每次執行都使用獨立的會話。 欲了解更多資訊,請參閱 SQL 查詢編輯器的限制。

疑難排解使用者資料功能

Query Insights 提供對 Fabric 函式進行疑難排解所需的執行和效能資訊。 你可以辨識呼叫函式的查詢,判斷該函式是使用批次還是列執行,並調查外部服務延遲、重試、失敗列數及有效載荷大小。 請使用以下兩個視圖,從查詢層級的概覽切換到每個函式的詳細統計:

  • 用queryinsights.exec_requests_history來辨識呼叫 Fabric 或 AI 功能的查詢。 檢視包含查詢文字、狀態、提交時間及總經過時間。
  • 用來 queryinsights.external_api_call_stats 取得查詢所呼叫的每個函式的詳細統計數據。 此檢視包含函式類型、執行模式、呼叫與重試次數、外部服務等待時間、有效載荷大小及列結果。

這些視圖使用 distributed_statement_id 來識別同一次查詢執行。

尋找使用 Fabric 函式的查詢

用queryinsights.exec_requests_history來查找最近啟用 Fabric 或 AI 函數的陳述:

SELECT TOP 100
       h.distributed_statement_id,
       h.submit_time,
       h.status,
       h.total_elapsed_time_ms,
       h.command
FROM queryinsights.exec_requests_history AS h
WHERE h.is_using_external_api = 1
ORDER BY h.submit_time DESC;

複製你想調查之陳述的 distributed_statement_id。 下一個查詢會將詳細統計資料過濾到 Fabric 函式。

在陳述句中查看每個函數的統計資料

將 <distributed_statement_id> 替換為上一個查詢傳回的識別碼。 以下查詢會針對陳述式所叫用的每個不同 Fabric 函式,各傳回一個資料列:

DECLARE @distributed_statement_id uniqueidentifier =
    '<distributed_statement_id>';

SELECT function_name,
       execution_mode,
       call_count,
       batch_call_count,
       row_call_count,
       call_retry_count,
       external_service_wait_time_ms,
       external_service_wait_time_ms
           / call_count AS average_wait_time_ms_per_call,
       rows_total,
       rows_succeeded,
       rows_failed,
       data_sent_bytes,
       data_received_bytes
FROM queryinsights.external_api_call_stats
WHERE distributed_statement_id = @distributed_statement_id
  AND function_type = 'FABRIC_FUNCTION'
ORDER BY external_service_wait_time_ms DESC;

結果類似以下範例:

function_name 執行模式 call_count 批次呼叫次數 row_call_count call_retry_count 外部服務等待時間_ms 每次呼叫的平均等待時間(毫秒) 資料列總數 成功的資料列 失敗資料列數 data_sent_bytes 已接收的資料位元組數
inet.ipSubnet batch 12 12 0 0 840 70 600 600 0 12,000 9,600
api.invokeExternalRestEndpoint row 4 0 4 1 1,920 480 4 4 0 1,024 512

疑難排解秘訣

  • 偏高的 row_call_count 或 execution_mode 值為 row,可能表示該函式未使用批次執行。 如果你預期會有批次處理,請確認批次模式預覽已啟用,且函式是否使用了參數 max_batch_size 。
  • 使用 external_service_wait_time_ms 並 average_wait_time_ms_per_call 識別緩慢的外部反應。 如果這些值偏高,而 data_sent_bytes 和 data_received_bytes 偏低,則外部服務的回應時間很可能是造成延遲的主要原因。
  • 大型 data_sent_bytes 或 data_received_bytes 值也會增加執行時間。 當函數傳輸的資料超過情境所需時,減少輸入或輸出有效載荷。