【问题标题】:select based on calculated value, optimization根据计算值选择,优化
【发布时间】:2015-04-24 15:48:08
【问题描述】:

我需要在其他字段中选择客户在购买特定品牌的某些产品时的年龄等,例如客户的年龄在 30 到 50 岁之间。我写了这个查询(getAge 只是使用 DATEDIFF 返回年龄)

SELECT DISTINCT customers.FirstName, customers.LastName, 
             products.ProductName,
             dbo.getAge(customers.BirthDate,sales.Datekey)
              AS Age_when_buying
FROM sales
 INNER JOIN dates ON sales.Datekey=dates.Datekey
 INNER JOIN customers ON sales.CustomerKey=customers.CustomerKey
 INNER JOIN products ON sales.ProductKey=products.ProductKey
 INNER JOIN stores ON sales.StoreKey=stores.StoreKey

WHERE stores.StoreName = 'DribleCom Europe Online Store' AND
products.BrandName = 'Proseware' AND
dbo.getAge(customers.BirthDate, sales.Datekey) >= 30 AND
dbo.getAge(customers.BirthDate, sales.Datekey) <=50

它有效,但我计算了三次年龄。我试图将 age_when_buying 分配给一个变量,但它不起作用。我的下一个想法是使用光标,但我觉得我缺少一种更简单的方法。问题是:解决这个问题的合适方法是什么,或者我有什么选择?

【问题讨论】:

  • dbo.getAge 是标量 UDF 吗?请考虑使用内联表值函数。
  • 如果我们要优化性能,请向我们展示 dbo.getAge 的函数体
  • @AaronBertrand 但是表值函数会计算所有客户的年龄,对吧?如果不是,性能会有很大差异吗?
  • 视情况而定。如果您有一个通过APPLY 调用的 TVF,它很可能只会针对过滤后的集合运行(但这完全取决于优化器如何分解它)。绝对可以肯定,它与单个标量函数调用一样快,但很可能更快。

标签: sql sql-server database performance


【解决方案1】:

假设您想要应用的过滤器数量有限,您可以使用Common Table Expression 来重组您的查询。

我个人发现在一个地方查看所有连接等更容易,而过滤器在底部类似地分组在一起......

WITH CTE AS(
    select customers.FirstName
         , customers.LastName
         , dbo.getAge(customers.BirthDate,sales.Datekey) AS Age_when_buying
         , sales.StoreName
         , products.BrandName
         , products.ProductName
    from sales
         INNER JOIN customers on sales.CustomerKey=customers.CustomerKey
         INNER JOIN products ON sales.ProductKey = products.ProductKey
         INNER JOIN stores ON sales.StoreKey = stores.StoreKey
)
SELECT DISTINCT FirstName, LastName, ProductName, Age_when_buying
FROM CTE
WHERE StoreName = 'DribleCom Europe Online Store'
  AND BrandName = 'Proseware'
  AND Age_when_buying BETWEEN 30 AND 50

【讨论】:

    【解决方案2】:

    您应该使用交叉应用。

    SELECT DISTINCT customers.FirstName, customers.LastName, 
                 products.ProductName,
                 age.age AS Age_when_buying
    FROM sales
     INNER JOIN dates ON sales.Datekey=dates.Datekey
     INNER JOIN customers ON sales.CustomerKey=customers.CustomerKey
     INNER JOIN products ON sales.ProductKey=products.ProductKey
     INNER JOIN stores ON sales.StoreKey=stores.StoreKey
    CROSS APPLY
    (select dbo.getAge(customers.BirthDate, sales.Datekey) as age) age
    WHERE stores.StoreName = 'DribleCom Europe Online Store' AND
    products.BrandName = 'Proseware' AND
    age.age >= 30 AND
    age.age <=50
    

    【讨论】:

      【解决方案3】:

      您可以使用WITH 子句:

      WITH Customers_Info (CustomerFirstName, CustomerLastName, CustomerKey, AgeWhenBuying)
      AS
      (
          SELECT customers.FirtName,
                 customers.LastName,
                 CustomerKey
                 dbo.getAge(customers.BirthDate, sales.DateKey) As AgeWhenBuying
          FROM customers
          JOIN sale USING(CustomerKey)
      )
      SELECT FirstName,
             LastName,
             products.ProductName,
             Customers_Info.AgeWhenBuying
          FROM Customers_Info
          JOIN sale USING(CustomerKey)
          JOIN products USING(ProductKey)
          JOIN stores USING(StoreKey)
          WHERE stores.StoreName = 'DribleCom Europe Online Store'
            AND products.BrandName = 'Proseware'
            AND Customers_Info.AgeWhenBuying >= 30
            AND Customers_Info.AgeWhenBuying <= 50;
      

      【讨论】:

        猜你喜欢
        • 2023-03-17
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-17
        • 1970-01-01
        • 2021-10-15
        相关资源
        最近更新 更多