我目前正在Delphi中开发一个应用程序,该应用程序使用SQL进入第三方发票系统的后端,因此我们可以扩展它的报告功能。我认为自己在编程的delphi方面相当精通,但SQL对我来说是新的,所以在这个论坛和其他资源的巨大帮助下,我已经设法自学了比我想象的更多。< / p>
大部分数据都是从几个表中提取的(我没有那个问题,所以我不会用这些细节阻塞帖子),但是我有一个问题是获得成本价格。它存储在跟踪历史成本价格的表格中,因此对于每个产品(16'000 +),可能有数百条记录,但是我只需要每个产品的成本最接近(&lt; =)到日期发票。 这是功能:
CREATE FUNCTION dbo.CostAtDate ( @costdate AS datetime , @product AS int )
RETURNS decimal(18,2)
AS
BEGIN
DECLARE @result decimal(18,2)
SET @result = (
Select Top 1
BASE_InventoryCostLogDetail.AverageCostAfter
From
BASE_InventoryCostLogDetail
Where
CreatedDttm < @costdate And CreatedDttm > DATEADD(month,-1,@costDate) And
ProdId = @product
Order By
CreatedDttm Desc)
RETURN @result
END
这是其中一个查询(有几个不同的查询,但都基于相同的结构):
Select
BASE_Customer.Name,
SO_SalesOrder.OrderNumber,
SO_SalesOrderInvoice_Line.Description,
SO_SalesOrderInvoice_Line.UnitPrice,
Case SO_SalesOrderInvoice_Line.ItemTaxCodeId
When '100' Then (SO_SalesOrderInvoice_Line.UnitPrice / 11) * 10
Else SO_SalesOrderInvoice_Line.UnitPrice End As exgst,
SO_SalesOrderInvoice_Line.QuantityUom,
SO_SalesOrderInvoice_Line.QuantityDisplay,
Case SO_SalesOrderInvoice_Line.QuantityUom
When 'cases.' Then dbo.CostAtDate(SO_SalesOrder.OrderDate,
SO_SalesOrderInvoice_Line.ProdId) * BASE_Product.SoUomRatioStd
Else dbo.CostAtDate(SO_SalesOrder.OrderDate,
SO_SalesOrderInvoice_Line.ProdId) End As cost,
Case SO_SalesOrderInvoice_Line.QuantityUom
When 'cases.' Then ((dbo.CostAtDate(SO_SalesOrder.OrderDate,
SO_SalesOrderInvoice_Line.ProdId) * BASE_Product.SoUomRatioStd) / 11) * 10
Else (dbo.CostAtDate(SO_SalesOrder.OrderDate,
SO_SalesOrderInvoice_Line.ProdId) / 11) * 10 End As exgstcost,
BASE_Product.SoUomRatioStd,
BASE_Product.Name As Name1,
SO_SalesOrder.OrderDate
From
BASE_Customer Inner Join
SO_SalesOrder On SO_SalesOrder.CustomerId = BASE_Customer.CustomerId
Inner Join
SO_SalesOrderInvoice_Line On SO_SalesOrderInvoice_Line.SalesOrderId =
SO_SalesOrder.SalesOrderId Inner Join
BASE_Product On SO_SalesOrderInvoice_Line.ProdId = BASE_Product.ProdId
Where
SO_SalesOrder.OrderDate Between '20131028' And '20131029'
现在,当我在所选范围内只有一些发票时这可以正常工作,但考虑到每个记录至少调用三次该功能,当我在一段时间内生成报告时,性能确实会降低。超过一天(我们经常需要报告两周的报告)。
不幸的是,鉴于它是第三方产品(对于任何好奇的人来说都是inFlow Inventory)我无法改变表结构。
有没有办法使用更高效的连接,派生表(我理解这个概念,但从未做过),甚至重写整个查询,这将大大提高性能?
答案 0 :(得分:0)
看来我已经设法解决了我自己的问题,它只是花了更多的研究,横向思考,许多失败的尝试和诅咒的话语(哦,这么多诅咒的话!)
我想到了在这个程序的delphi端添加额外步骤的想法,这些步骤将根据我需要的日期范围从成本价格表中进行选择,然后重新编写我的原始查询以合并加入的新表。但是,如果你在这个过程中没有学到任何新技能,那么解决问题并不是那么有趣; - )。
答案:TVF-表值函数。 经过大量关于替代方式的研究,我偶然发现了这些TVF。进一步的调查似乎表明,由于优化器处理标量函数而不是TVF的方式,它们在某些应用程序中的速度非常快,因此我决定重新编写我的函数:
CREATE FUNCTION dbo.CostAtDate ( @costdate AS datetime , @product AS int )
RETURNS table
AS
Return (
Select Top 1
BASE_InventoryCostLogDetail.AverageCostAfter
From
BASE_InventoryCostLogDetail
Where
CreatedDttm < @costdate And CreatedDttm > DATEADD(month,-1,@costDate) And
ProdId = @product
Order By
CreatedDttm Desc)
而不是以传统的方式称呼它
dbo.CostAtDate(SO_SalesOrder.OrderDate, SO_SalesOrderInvoice_Line.ProdId)
我在查询中重新编写了对它的所有引用:
(Select * from dbo.CostAtDate(SO_SalesOrder.OrderDate,
SO_SalesOrderInvoice_Line.ProdId))
测试它我发现性能显着提高(65k +记录为4秒,而前一个功能通常会在几分钟后超时,即使预期的结果集是~10k记录。)
我相信你们中有很多人知道一种更好的方式,但目前这种方法运作得很好......而且我自己找到了这一切:对我赞不绝口!