有几个例子要展示,以防万一:
内联表值
CREATE FUNCTION MyNS.GetUnshippedOrders()
RETURNS TABLE
AS
RETURN SELECT a.SaleId, a.CustomerID, b.Qty
FROM Sales.Sales a INNER JOIN Sales.SaleDetail b
ON a.SaleId = b.SaleId
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.ShipDate IS NULL
GO
多语句表值
CREATE FUNCTION MyNS.GetLastShipped(@CustomerID INT)
RETURNS @CustomerOrder TABLE
(SaleOrderID INT NOT NULL,
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
OrderQty INT NOT NULL)
AS
BEGIN
DECLARE @MaxDate DATETIME
SELECT @MaxDate = MAX(OrderDate)
FROM Sales.SalesOrderHeader
WHERE CustomerID = @CustomerID
INSERT @CustomerOrder
SELECT a.SalesOrderID, a.CustomerID, a.OrderDate, b.OrderQty
FROM Sales.SalesOrderHeader a INNER JOIN Sales.SalesOrderHeader b
ON a.SalesOrderID = b.SalesOrderID
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.OrderDate = @MaxDate
AND a.CustomerID = @CustomerID
RETURN
END
GO
使用一种类型(内联语句或多语句)比另一种类型有优势吗?当其中一种比另一种更好时,是否存在某种特定的情景,还是仅仅是句法上的差异?我意识到这两个示例查询所做的事情不同,但我是否有理由这样写它们呢?
回答:
在内部,SQLServer处理内联表值函数就像对待视图一样,并且处理多语句表值函数的方式类似于存储过程。
当内联表值函数被用作外部查询的一部分时,查询处理器扩展UDF定义并生成访问底层对象的执行计划,使用这些对象上的索引。
对于多语句表值函数,为函数本身创建执行计划并存储在执行计划缓存中(一旦函数第一次执行)。如果多语句表值函数被用作较大查询的一部分,那么优化器就不知道函数返回了什么,因此做出了一些标准假设--实际上它假设函数将返回一个行。并且,函数的返回将通过对带有一行的表进行表扫描来访问。
当多语句表值函数返回大量行并在外部查询中被连接时,多语句表值函数的性能可能会很差。性能问题主要归因于这样一个事实:如果返回了一行,优化器将生成一个计划,这不一定是最合适的计划。
我们发现,由于这些潜在的性能问题,在可能的情况下,应该优先使用内联表值函数,而不是多语句函数(当UDF将用作外部查询的一部分时)。
参考:
https://cloud.tencent.com/developer/ask/28238