为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕盖茨4494581 2019-12-10 13:08:19
举例说明,以防万一:内联表值CREATE FUNCTION MyNS.GetUnshippedOrders()RETURNS TABLEAS 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 NULLGO多语句表值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)ASBEGIN    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    RETURNENDGO使用一种类型(内联或多语句)比另一种类型有优势吗?在某些情况下,一个人比另一个人好吗?或者差异纯粹是句法上的?我意识到这两个示例查询在做不同的事情,但是我有理由以这种方式编写它们吗?关于它们及其优势/差异的阅读并没有真正得到解释。
查看完整描述

3 回答

?
jeck猫

TA贡献1909条经验 获得超7个赞

在研究Matt的评论时,我修改了原始声明。他是正确的,即使直接执行SELECT语句,内联表值函数(ITVF)和多语句表值函数(MSTVF)的性能也会有所不同。SQL Server会将ITVF视为VIEW因为它将使用有关表的最新统计信息来计算执行计划。MSTVF等效于将SELECT语句的全部内容填充到一个表变量中,然后再加入该变量中。因此,编译器不能在MSTVF中的表上使用任何表统计信息。因此,在所有条件都相同的情况下(很少有),ITVF的性能将比MSTVF好。在我的测试中,完成时间的性能差异可以忽略不计,但是从统计角度来看,这是显而易见的。


就您而言,这两个功能在功能上并不相同。每次调用时,MSTV函数都会执行一个额外的查询,最重要的是,对客户ID进行过滤。在大型查询中,优化器将无法利用其他类型的联接,因为它需要为传递的每个customerId调用函数。但是,如果您重新编写MSTV功能,如下所示:


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

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


在可行的情况下,应首选ITVF而不是MSTVF,因为表中各列的数据类型,可为空性和排序规则,而在多语句表值函数中声明这些属性,重要的是,您将从ITVF获得更好的执行计划。根据我的经验,我没有发现很多情况下ITVF比VIEW更好,但是里程可能会有所不同。



查看完整回答
反对 回复 2019-12-11
?
Helenr

TA贡献1780条经验 获得超3个赞

在内部,SQL Server像对待视图一样对待内联表值函数,并像对待存储过程一样对待多语句表值函数。

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

对于多语句表值函数,将为函数本身创建执行计划,并将其存储在执行计划缓存中(一旦第一次执行该功能)。如果将多语句表值函数用作较大查询的一部分,则优化器不知道该函数返回什么,因此做出一些标准假设-实际上,它假设该函数将返回一行,并且该函数的返回通过对具有一行的表进行表扫描来访问该功能。

多语句表值函数的性能较差的地方是它们返回大量行并在外部查询中联接时。性能问题主要归结于以下事实:优化器将假设返回一行而生成一个计划,这不一定是最合适的计划。

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




查看完整回答
反对 回复 2019-12-11
?
月关宝盒

TA贡献1772条经验 获得超5个赞

我认为您的示例很好地回答了这个问题。第一个功能可以单选完成,这是使用内联样式的一个很好的理由。第二个可能是作为单个语句完成的(使用子查询来获取最大日期),但是某些编码人员可能会发现您更容易阅读或更自然地在多个语句中执行此操作。某些简单的功能无法在一个语句中完成,因此需要多语句版本。

我建议尽可能使用最简单的(内联)语句,必要时(显然)或在个人喜好/可读性使其成为多余打字内容时使用多语句。



查看完整回答
反对 回复 2019-12-11
  • 3 回答
  • 0 关注
  • 461 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信