使用标量函数执行查询花费了太多时间
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
【讨论】:
以上是关于使用标量函数执行查询花费了太多时间的主要内容,如果未能解决你的问题,请参考以下文章
与硬编码值相比,Oracle SQL In Subquery 花费了太多时间