T-SQL函数中的性能问题

时间:2016-02-17 15:57:02

标签: sql sql-server sql-server-2008

我有一张桌子,可以提供每日库存状态。即库存项目X,在特定日期具有Y量的数量。我创建了一个功能,可以根据上次购买的价格获取特定日期的购买价格。

当我在dailyinventorystatus表上运行查询时,它会在3分钟内完成日期> 2014年1月1日。但是,当我将该函数作为子查询添加时,会导致巨大的性能问题。它已超过1.5小时,查询仍在运行。

如何改善这一点?

以下是查询:

SELECT 
    *, 
    RWReports.dbo.FindPurchasePrice(InventoryKey, Date , warehouse) as SalesPurchasePrice
FROM  
    DailyInventoryStatus
WHERE 
    Warehouse IN ('NYC,', 'CHICAGO', 'CHINA', 'ATLANTA')
    AND Date >= '2014-01-01'

这是功能:

CREATE FUNCTION [dbo].[FindPurchasePrice] 
    (@InventoryKey varchar(8), @InDate Date , @Warehouse varchar(30))
RETURNS REAL
AS
BEGIN
    DECLARE @oPurchasePrice AS REAL ;

    SELECT TOP (1) 
        @oPurchasePrice = UnitPurchasePrice 
    FROM 
        PurchaseTransactions 
    WHERE 
        InventoryKey = @InventoryKey 
        AND TransactionDate <= @InDate 
        AND Warehouse = @Warehouse 
    ORDER BY  
        TransactionDate DESC; 

    IF @oPurchasePrice IS NULL 
       SELECT
           @oPurchasePrice = mw.cost 
       FROM 
           Rentalworks.dbo.masterwh mw 
       JOIN 
           Rentalworks.dbo.warehouse w ON w.warehouseid = mw.warehouseid
                                       AND mw.masterid = @InventoryKey 
                                       AND w.warehouse = @Warehouse;

    RETURN @oPurchasePrice;
END;
GO

2 个答案:

答案 0 :(得分:3)

这是你可以将它转换为内联表值函数的方法。

CREATE FUNCTION [dbo].[FindPurchasePrice] 
(
    @InventoryKey varchar(8)
    , @InDate Date 
    , @Warehouse varchar(30)
)
RETURNS TABLE
AS

RETURN
    SELECT ISNULL(pt.UnitPurchasePrice ,mw.cost) AS PurchasePrice
    FROM Rentalworks.dbo.masterwh mw 
    JOIN Rentalworks.dbo.warehouse w on w.warehouseid = mw.warehouseid
        AND mw.masterid = @InventoryKey 
        AND w.warehouse = @Warehouse
    OUTER APPLY
    (
        SELECT TOP (1) UnitPurchasePrice 
        FROM PurchaseTransactions 
        WHERE InventoryKey = @InventoryKey 
        AND TransactionDate <= @InDate 
        AND Warehouse=@Warehouse 
        ORDER BY TransactionDate DESC
    ) pt

我当然无法对此进行测试,但语法检查很好。

现在要在原始的select语句中包含它,你可以这样做。

SELECT dis.*
    , fp.PurchasePrice
FROM DailyInventoryStatus dis
CROSS APPLY dbo.FindPurchasePrice(dis.InventoryKey, dis.Date, dis.warehouse) fp
WHERE Warehouse IN ('NYC,', 'CHICAGO', 'CHINA', 'ATLANTA')
AND Date >= '2014-01-01'

答案 1 :(得分:0)

这是通过将所有逻辑合并到单个查询中而无需函数重写的一种方法:

with data as (
    select
        dis.*, pt.TransactionDate, pt.UnitPurchasePrice,
        row_number() over (
            partition by dis.InventoryKey, dis.Warehouse
            order by TransactionDate desc
        ) as TransNumber
    from
        DailyInventoryStatus dis left outer join
        PurchaseTransactions pt
            on      pt.InventoryKey = dis.InventoryKey
                and pt.Warehouse = dis.Warehouse
                and pt.TransactionDate < dis.Date
        where dis.Date >= ?
)
select
    *,
    coalesce(
        UnitPurchasePrice,
        (
            select mw.cost
            from
                Rentalworks.dbo.masterwh mw inner join
                Rentalworks.dbo.warehouse w
                    on w.warehouseid = mw.warehouseid
            where mw.masterid = data.InventoryKey
                and w.warehouse = data.Warehouse
         )
    ) as PurchasePrice
from data
where TransNumber = 1