提高表值函数性能

Posted

技术标签:

【中文标题】提高表值函数性能【英文标题】:Improve Table Value Function Performance 【发布时间】:2016-11-17 08:44:38 【问题描述】:

你能帮我改进一下表值函数吗:

    Create Function [dbo].[xxx](@InvoiceId numeric(18 ,0) ,@InvoiceType int ,@ReceiptAccOwner int)
    Returns Table
    As
    Return(


    Select * From(

            Select N'InvoiceReceiptNo' + Cast(ROW_NUMBER() over(order by ir.ReceiptRecID) as nvarchar(10)) As row

                ,ir.StockHoldingInvoiceID As InvoiceId

                ,ir.ReceiptNo As ReceiptValue
                ,ir.ReceiptAccOwner
            from InvoiceReceipt As ir       
            Where  ir.ReceiptAccOwner = @ReceiptAccOwner
            And (
                   (ir.StockHoldingInvoiceID = @InvoiceId And @InvoiceType in(1 ,6 ,8) )
                 or(ir.THCInvoiceID = @InvoiceId And @InvoiceType = 2)
                 or(ir.EvaluatInvoiceID = @InvoiceId And @InvoiceType = 3)
                 or(ir.StripInvoiceID = @InvoiceId And @InvoiceType = 4)
                 or(ir.EvaluationExportInvoiceID = @InvoiceId And @InvoiceType = 5)
                 or(ir.ServiceInvoiceID = @InvoiceId And @InvoiceType = 7)
                 or(ir.MovementInvoiceId = @InvoiceId And @InvoiceType = 10)
                 or(ir.InterchangeReplicaInvoice = @InvoiceId And @InvoiceType = 11)
                 or(ir.MovementInvoiceId = @InvoiceId And @InvoiceType = 12)
                 or(ir.BLConsigneeChangeRequestInvoiceID = @InvoiceId And @InvoiceType = 15)
                 )

            UNION All

            Select N'InvoiceReceiptPrice' + Cast(ROW_NUMBER() over(order by ir.ReceiptRecID) as nvarchar(10)) As row

                ,ir.StockHoldingInvoiceID

                ,Cast(IsNull(ir.ReceiptPrice ,0) as nvarchar(20)) As ReceiptValue
                ,ir.ReceiptAccOwner
            from InvoiceReceipt As ir
            Where  ir.ReceiptAccOwner = @ReceiptAccOwner
            And (
                   (ir.StockHoldingInvoiceID = @InvoiceId And @InvoiceType in(1 ,6 ,8) )
                 or(ir.THCInvoiceID = @InvoiceId And @InvoiceType = 2)
                 or(ir.EvaluatInvoiceID = @InvoiceId And @InvoiceType = 3)
                 or(ir.StripInvoiceID = @InvoiceId And @InvoiceType = 4)
                 or(ir.EvaluationExportInvoiceID = @InvoiceId And @InvoiceType = 5)
                 or(ir.ServiceInvoiceID = @InvoiceId And @InvoiceType = 7)
                 or(ir.MovementInvoiceId = @InvoiceId And @InvoiceType = 10)
                 or(ir.InterchangeReplicaInvoice = @InvoiceId And @InvoiceType = 11)
                 or(ir.MovementInvoiceId = @InvoiceId And @InvoiceType = 12)
                 or(ir.BLConsigneeChangeRequestInvoiceID = @InvoiceId And @InvoiceType = 15)
                 )

    ) As tb
    pivot(
             Max(ReceiptValue) --,Sum(ReceiptPrice)
             For row in ([InvoiceReceiptNo1] ,[InvoiceReceiptNo2] ,[InvoiceReceiptNo3] ,[InvoiceReceiptNo4] ,[InvoiceReceiptNo5] ,[InvoiceReceiptNo6] 
                        ,[InvoiceReceiptPrice1] ,[InvoiceReceiptPrice2] ,[InvoiceReceiptPrice3] ,[InvoiceReceiptPrice4] ,[InvoiceReceiptPrice5] ,[InvoiceReceiptPrice6])
         )   piv


    )

我在存储过程中使用这个函数,在 select 语句中使用 Outer apply, 此函数应为每张发票仅返回一条记录。

XML 执行计划: 选择 * 从 [dbo].[fn_GetInvoiceReceiptInfo](149735 , 1 ,1) https://anotepad.com/notes/wh34ey

【问题讨论】:

你能把执行计划放在pastetheplan.com上,给我们一个链接吗?这将帮助我们了解正在发生的事情。 @RichBenner pastetheplan.com 没有为我打开。 试试这个链接brentozar.com/pastetheplan @RichBenner 很遗憾没有打开 好吧,我想这是你的防火墙的事情,对我来说很好。获取执行计划的 XML,如果可以的话,将其作为编辑添加到您的问题中。 【参考方案1】:

答案取决于您拥有的索引。除非您特别详细说明您拥有哪些索引以及使用哪些索引,否则很难提出更好的解决方案。

例如,您有一个聚合窗口函数,可以通过更改聚簇索引或为您的特定查询添加覆盖索引来使其更快。但是,只有当这确实是瓶颈时才有意义。

执行计划是怎么说的?

您可能想尝试的另一件事是在WHERE 子句中重写所有不带OR 的查询,并对所有查询使用UNION ALL。这将允许数据库并行化您的查询。

同样,您可以尝试这些方法,但它们是否有效取决于索引和查询计划瓶颈。

【讨论】:

【参考方案2】:

好的,看看您提供的执行计划,您正在执行Key Lookups,这意味着您可以调整索引以减少此处的执行时间。

目前,您正在使用表 InvoiceReceipt 上的索引 Relationship_82_FK 来返回两个值 ReceiptRecIDStockHoldingInvoiceID。现在,由于该索引不包含您需要的所有信息,SQL 必须返回并查找您的聚集索引以返回附加信息。尝试更改索引 Relationship_82_FK 以将 ReceiptAccHolderReceiptPrice 作为包含字段。

【讨论】:

以上是关于提高表值函数性能的主要内容,如果未能解决你的问题,请参考以下文章

基于函数的索引没有提高查询性能

使用匿名函数提高性能? [关闭]

使用匿名函数瓶颈提高 matlab 代码的性能

PostgreSQL 提高 PL/pgSQL 函数的性能

使用 Inline 表值函数封装 SQL 代码的性能

EF 和表值函数性能