| 類型 | 語法特徵 | 優化器處理 | 效能特性 |
|---|---|---|---|
| 內聯 TVF (Inline TVF) | RETURNS TABLE ... RETURN SELECT ...無 BEGIN/END 區塊 | 視圖化展開,併入外層查詢計畫,支援謂詞下推 | 極佳,等同直接寫 JOIN 子查詢 |
| 多陳述式 TVF (Multi-statement TVF) | RETURNS @TableVar TABLE ... BEGIN ... INSERT ... RETURN END | 視為黑盒,估計固定 100 列 (舊版) 或 1 列 (新版),無法展開 | 差,常導致嚴重誤估、巢狀迴圈過度查找 |
-- 多陳述式 TVF
CREATE FUNCTION dbo.tvf_multi_Test()
RETURNS @SaleDetail TABLE (ProductId INT)
AS BEGIN
INSERT @SaleDetail
SELECT ProductID
FROM Sales.SalesOrderHeader soh
JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID;
RETURN;
END;
-- 內聯 TVF
CREATE FUNCTION dbo.tvf_inline_Test()
RETURNS TABLE
AS RETURN
SELECT ProductID
FROM Sales.SalesOrderHeader soh
JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID;
-- 多陳述式 TVF JOIN
SELECT c.PersonID, p.Name, COUNT(*) AS Cnt
FROM Person.BusinessEntityContact c
JOIN dbo.tvf_multi_Test() t ON c.PersonID = t.ProductId
JOIN Production.Product p ON t.ProductId = p.ProductID
GROUP BY c.PersonID, p.Name;
-- 內聯 TVF JOIN
SELECT c.PersonID, p.Name, COUNT(*) AS Cnt
FROM Person.BusinessEntityContact c
JOIN dbo.tvf_inline_Test() t ON c.PersonID = t.ProductId
JOIN Production.Product p ON t.ProductId = p.ProductID
GROUP BY c.PersonID, p.Name;

BusinessEntityContact 選擇 121,317 次 Key Lookup (Nested Loops),實際 I/O 極大。WHERE / JOIN 條件無法推入 TVF 內部,導致 TVF 全量掃描後再過濾。SELECT 邏輯務必改寫為 Inline。OPTION (RECOMPILE) 或 USE HINT('DISABLE_OPTIMIZER_ROWGOAL') 緩解,但治標不治本。「表值函數好用,但多陳述式 TVF 是效能殺手」。開發審查時,凡見 RETURNS @Table TABLE ... BEGIN ... END 即應要求重構為內聯 TVF 或預存程序。