使用标量函数执行查询花费了太多时间

Posted

技术标签:

【中文标题】使用标量函数执行查询花费了太多时间【英文标题】:query executing taking too much time with scalar function 【发布时间】:2016-09-07 09:49:49 【问题描述】:

我有一个标量函数,它根据条件和该函数计算总和,我使用的是存储过程。这需要太多时间来执行。对于 25 条记录,大约需要 4 分钟。有什么想法可以优化我的查询。任何帮助将不胜感激。

这是我的代码。 我调用函数的存储过程动态查询。

select distinct
                        p.ProductID
                        ,p.ProductGUID
                        ,p.[ProductNumber] 
                        ,[ProductName] = isnull(p.[Name],'''')
                        ,[ProductNumberLabel] = isnull(p.[ProductNumberLabel],'''')
                        ,[ProductDescription]=isnull(p.[Description],'''')
                        ,[PrimaryImageID] = isnull(p.[PrimaryImageID],0)
                        ,[UserProductID] = isnull(p.[UserProductID],0) 
                        ,[OrganizationID] = isnull(p.[OrganizationID],0) 
                        ,[BusinessUnitID] = isnull(I.[BusinessUnitID],0)
                        ,[BusinessUnitName] = isnull(bu.[Name],0) 
                        ,[OwnerUserGroupID] = isnull(p.[OwnerUserGroupID],0) 
                        ,[QuantityOnHand]= (select [dbo].[TotalCalculatedSum] (p.ProductID,''QuantityOnHand'', '+@OwnerUserIDstr+', '+@OrganizationIDstr+', I.BusinessUnitID , '+@InventoryIDstr+'))
                        ,[QuantityBooked] = (select [dbo].[TotalCalculatedSum] (p.ProductID,''QuantityBooked'', '+@OwnerUserIDstr+', '+@OrganizationIDstr+', I.BusinessUnitID, '+@InventoryIDstr+'))
  from dbo.Product p
  left join Inventory I on II.InventoryID = I.InventoryID
  left join dbo.BusinessUnit bu on I.BusinessUnitID=bu.[BusinessUnitID] and bu.[ActiveStatus]=1
  where p.ActiveStatus = 1
  and bu.[ActiveStatus]=1 

这是我计算总和的函数

ALTER FUNCTION [dbo].[TotalCalculatedSum] 
  ( 
  @ProductID bigint, 
  @TotalType nvarchar(200), 
  @OwnerUserID bigint, 
  @OrganizationID bigint, 
  @BusinessUnitID bigint, 
  @InventoryID bigint 
  ) 
  RETURNS decimal(32,9) 
  AS 
  BEGIN 
  -- declare the return variable here 
  declare @OutputValue decimal(32,9) 
  Declare @locationValue int =0 

  IF @TotalType = 'QuantityOnHand' 
  BEGIN 
  set @OutputValue = isnull((select sum(ii.[QuantityOnHand]) 
  from dbo.InventoryItems ii, Inventory i 
  where ii.ActiveStatus=1 
  and ii.ProductID = @ProductID 
  and ii.InventoryID = i.InventoryID 
  AND i.OwnerUserGroupID = case @OwnerUserID 
  when 0 then i.OwnerUserGroupID else @OwnerUserID end 
  AND i.OrganizationID = case @OrganizationID 
  when 0 then i.OrganizationID else @OrganizationID end 
  AND i.BusinessUnitID = case @BusinessUnitID 
  when 0 then i.BusinessUnitID else @BusinessUnitID end 
  AND i.InventoryID = case @InventoryID 
  when 0 then i.InventoryID else @InventoryID end), 0.00) 
  END 
  ELSE IF @TotalType = 'QuantityBooked' 
  BEGIN 
  set @OutputValue = isnull((select sum(ii.QuantitySold) 
  from dbo.InventoryItems ii, Inventory i 
  where ii.ActiveStatus=1 
  and ii.ProductID = @ProductID 
  and ii.InventoryID = i.InventoryID 
  AND i.OwnerUserGroupID = case @OwnerUserID 
  when 0 then i.OwnerUserGroupID else @OwnerUserID end 
  AND i.OrganizationID = case @OrganizationID 
  when 0 then i.OrganizationID else @OrganizationID end 
  AND i.BusinessUnitID = case @BusinessUnitID 
  when 0 then i.BusinessUnitID else @BusinessUnitID end 
  AND i.InventoryID = case @InventoryID 
  when 0 then i.InventoryID else @InventoryID end), 0.00) 
  END 
  return @OutputValue 


  END 

【问题讨论】:

我将从使用内部连接语法开始,而不是这种过时的连接方法。从 dbo.InventoryItems ii 内部加入 Inventory i on ii.InventoryID = i.InventoryID where ii.ActiveStatus = 1 and ... 您是否查看了查询执行计划以查看它是否推荐了任何索引?它还可能显示瓶颈在哪里等。 【参考方案1】:

如您所见,在 SELECT 语句中调用标量值函数很慢。首选方法是将标量函数重写为内联表值函数。我没有查看您的特定查询,但这篇文章可能会帮助您找到方法:http://www.databasejournal.com/features/mssql/article.php/3845381/T-SQL-Best-Practices-150-Don146t-Use-Scalar-Value-Functions-in-Column-List-or-WHERE-Clauses.htm

【讨论】:

以上是关于使用标量函数执行查询花费了太多时间的主要内容,如果未能解决你的问题,请参考以下文章

从 Sqlite 游标创建 Pojo 类花费了太多时间

与硬编码值相比,Oracle SQL In Subquery 花费了太多时间

Image magick:在 linux 服务器上花费了太多时间

嵌套的 Foreach 循环花费了太多时间

在 MySQL 中进行排序时查询花费了太多时间

查询花费了太多时间与恼人的性能[关闭]