在计算字段上过滤大型结果集

时间:2014-01-14 22:24:04

标签: sql-server tsql

我有一个搜索程序需要使用特定的价格类型返回结果。此类价格类型(取决于授予搜索者访问权限的客户)是计算价格。我们使用UDF来计算这个价格。因此,根据提交的搜索,可能会有许多不同的价格回来。除了搜索的价格类型之外,我们还需要按FROM和TO价格以及销售保证金范围过滤结果。

这是简化的,但基本上搜索看起来像这样......

SELECT Name, Model, f_GetPrices(modelID, @userID, priceType)
FROM products
WHERE  f_GetPrices(modelID, @userID priceType) Between @from and @to
     AND (RetailPrice-f_GetPrices(modelID, @userID, priceType) / Retail Price * 100) Between @fromMargin and @toMargin

问题是我每条记录都要调用这个UDF 4次。

这是一个简化版本,通常我将所有结果都插入临时表中。然后我使用@pageSize和@pageNumber拉出我想要的页面,在第二个结果中,我返回返回的总行数。这允许我们的UI进行分页并显示总记录数。

我已经考虑将计算出的价格转储到临时表中,然后在从那里拉出的SELECT中执行我的WHERE子句。但是,由于我已经在进行分页,我实际上需要将所有具有计算价格的记录转储到临时表中,然后只提取价格范围内的那些记录,然后拉出最后一次分页和总记录,这样两个临时结果表。

我正试图找出最佳方法。

如果我在select中调用UDF 4次,那么SQL引擎是运行4次还是仅计算一次并使用它会导致每个记录的所有4个位置?

如果我选择了10,000条记录,其中只有100条符合价格标准(From,To,FromMargin,ToMargin),那么这些10k记录只能抓住100就好了。这就是为什么我试图申请价格范围为初始选择。但后来我认为SQL需要对所有10k记录进行计算才能应用WHERE子句。计算价格范围是否与计算价格范围相同,转储到临时表中,然后再次选择它?

2 个答案:

答案 0 :(得分:0)

只需使用子查询:

select *
from (SELECT Name, Model, f_GetPrices(modelID, @userID, priceType) as fgp
      FROM products
     ) p
WHERE fgp Between @from and @to and
      (RetailPrice-fgp) / RetailPrice * 100) Between @fromMargin and @toMargin;

我还略微修改了最后一个条件的逻辑,因此差异除以RetailPrice

答案 1 :(得分:0)

如果您在此处优化性能,请尝试将f_GetPrices()重写为内联表值函数而不是标量函数。标量函数通常是RBAR

http://sqlmag.com/sql-server/inline-scalar-functions

http://dataeducation.com/scalar-functions-inlining-and-performance-an-entertaining-title-for-a-boring-post/

您修改后的查询将如下所示:

  SELECT
    Name, Model, Price
  FROM products
  CROSS APPLY tvf_GetPrices(modelID, @userID, priceType) f
  WHERE Price Between @from and @to
    AND (RetailPrice - Price) / Retail Price * 100 Between @fromMargin and @toMargin

您的函数定义如下所示:

  CREATE FUNCTION [dbo].[tvf_GetPrices](
    @modelId   int,
    @userID    int,
    @priceType int
  )
  RETURNS TABLE
  RETURN (
    SELECT foo AS Price
    FROM bar
    WHERE @modelId
    etc
  )