多语句表值函数与内联表值函数

几个例子显示,只是incase:

内联表值

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 

使用一种types(内联或多语句)比另一种types有优势吗? 有一种情况比另一种情况好,或者纯粹是句法上的区别? 我意识到这两个示例查询是做不同的事情,但是我有写这些的理由吗?

阅读他们和优势/差异并没有真正解释。

在研究马特的评论时,我修改了我原来的陈述。 他是正确的,在内联表值函数(ITVF)和多语句表值函数(MSTVF)之间,即使它们都只是简单地执行SELECT语句,性能也会有所不同。 SQL Server将把ITVF视为像VIEW一样,它将使用相关表中的最新统计信息来计算执行计划。 MSTVF等同于将SELECT语句的全部内容填充到表variables中,然后join到表variables中。 因此,编译器不能使用MSTVF中的表上的任何表统计信息。 所以,所有事情都是平等的(他们很less),ITVF的performance会比MSTVF好。 在我的testing中,完成时间的性能差异可以忽略不计,但从统计angular度来看,这是显而易见的。

在你的情况下,这两个function在function上并不相同。 MSTVfunction会在每次调用时执行额外的查询,最重要的是,会过滤客户ID。 在一个大的查询中,优化器将无法利用其他types的连接,因为它需要为每个传递的customerId调用该函数。 但是,如果您重新编写您的MSTVfunction,如下所示:

 CREATE FUNCTION MyNS.GetLastShipped() RETURNS @CustomerOrder TABLE ( SaleOrderID INT NOT NULL, CustomerID INT NOT NULL, OrderDate DATETIME NOT NULL, OrderQty INT NOT NULL ) AS BEGIN 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 = ( Select Max(SH1.OrderDate) FROM Sales.SalesOrderHeader As SH1 WHERE SH1.CustomerID = A.CustomerId ) RETURN END GO 

在查询中,优化器将能够调用该函数一次,并构build一个更好的执行计划,但它仍然不会比等效的非参数化ITVS或VIEW更好。

在可行的情况下,ITVF应优于MSTVF,因为数据types,表的列的可空性和sorting规则是可以理解的,而您将这些属性声明为多语句表值函数,重要的是,ITVF将获得更好的执行计划。 根据我的经验,我没有发现ITVF比VIEW更好的select,但里程可能有所不同。

感谢Matt。

加成

由于我最近看到了这个问题,Wayne Sheffield对Inline Table Valued函数和Multi-Statement函数的性能差异进行了比较。

他原来的博客文章。

在SQL Server Central上复制

在内部,SQL Server将像处理视图一样处理内联表值函数,并将类似于存储过程的多语句表值函数处理。

将内联表值函数用作外部查询的一部分时,查询处理器扩展UDF定义,并使用这些对象上的索引生成访问基础对象的执行计划。

对于多语句表值函数,为函数本身创build一个执行计划并存储在执行计划caching中(一次函数执行完成后)。 如果多语句表值函数被用作较大查询的一部分,那么优化器不知道该函数返回什么,所以做出一些标准的假设 – 实际上它假设该函数将返回一行,并且返回该函数将通过对具有单行的表进行表扫描来访问。

在多语句表值函数可以执行较差的情况是当它们返回大量的行并在外部查询中联合使用时。 性能问题主要是由于优化器会产生一个计划,假设返回一行,这不一定是最合适的计划。

作为一般的经验法则,我们已经发现,由于这些潜在的性能问题,在可能的情况下应该使用内联表值函数而不是多语句函数(当UDF将被用作外部查询的一部分时)。

还有另一个区别。 内联表值函数可以插入,更新和删除 – 就像一个视图。 类似的限制适用 – 无法使用聚合更新函数,无法更新计算的列等等。

我想你的例子很好地回答了这个问题。 第一个function可以作为单个select来完成,并且是使用内联样式的一个很好的理由。 第二个可能可以作为单个语句来完成(使用子查询来获取最大date),但是一些编码人员可能会发现在多个语句中更容易阅读或更自然地完成它。 有些函数只是简单的,不能在一个语句中完成,因此需要多语句版本。

我build议尽可能使用最简单的(内联),并在必要时使用多语句(显然),或者当个人偏好/可读性使得额外的打字成为可能时。

看比较内联和多语句表值函数,你可以find很好的描述和性能基准

如果你打算做一个查询,你可以join你的内联表值函数,如:

 SELECT a.*,b.* FROM AAAA a INNER JOIN MyNS.GetUnshippedOrders() b ON az=bz 

它会产生小的开销,运行良好。

如果您尝试使用类似查询中的多语句表格值,则会出现性能问题:

 SELECT xa,xb,xc,(SELECT OrderQty FROM MyNS.GetLastShipped(x.CustomerID)) AS Qty FROM xxxx x 

因为你将为返回的每一行执行一次函数,因为结果集变大,它将会运行得越来越慢。