【问题标题】:ROW_NUMBER returning the same value for all rows (+ query performance)ROW_NUMBER 为所有行返回相同的值(+ 查询性能)
【发布时间】:2019-09-14 00:14:27
【问题描述】:

我有以下查询(用于展示问题)

WITH
    CategoryPromotions
    AS
    (
        SELECT CategoryId = 7, Price = 10
             UNION ALL
        SELECT CategoryId = 3, Price = 15
             UNION ALL
        SELECT CategoryId = 1, Price = 5
    )
,
       Products
       AS
       (
             SELECT Id = 1, Price = 20
       )
,
       ProductsCategories
       AS
       (
             SELECT ProductId = 1, CategoryId = 2
             UNION ALL
             SELECT ProductId = 1, CategoryId = 8
             UNION ALL
             SELECT ProductId = 1, CategoryId = 6
       )
,
       Tally
       AS
       (
             SELECT N = 1
             UNION ALL
             SELECT N = 2
             UNION ALL
             SELECT N = 3
             UNION ALL
             SELECT N = 4
             UNION ALL
             SELECT N = 5
       )
,
       Hierarchy
       AS
       (
             SELECT Id = 2, SortPath = 0x00000001000000070000000400000002
             UNION ALL
             SELECT Id = 8, SortPath = 0x00000001000000070000000400000008
             UNION ALL
             SELECT Id = 6, SortPath = 0x0000000300000006
       )
SELECT ProductsCategories.*, xD.*
FROM Products
       RIGHT JOIN ProductsCategories
             ON Products.Id = ProductsCategories.ProductId
       CROSS APPLY
       (
             SELECT TOP (1) promos.CategoryId
                    , Products.Price AS BasePrice
                    , promos.Price
                    , (
                        CASE
                            WHEN promos.Price IS NOT NULL THEN
                                (Products.Price - promos.Price)
                            ELSE
                                Products.Price
                        END
                    ) AS DiscountedPrice
                    , ROW_NUMBER() OVER
                    (
                           ORDER BY CASE
                                  WHEN promos.Price IS NOT NULL THEN
                                        (Products.Price - promos.Price)
                                  ELSE
                                        Products.Price
                                  END
                           ASC
                    ) AS PriceRank
             FROM (SELECT ProductsCategories.ProductId, ProductsCategories.CategoryId) bpc
                    CROSS APPLY
                    (
                           SELECT TOP (1) categories.CategoryId
                                  , catpromo.Price
                           FROM
                                  (
                                        SELECT CategoryId = CAST(SUBSTRING(Hierarchy.SortPath,Tally.N,4) AS INT)
                                               , Tally.N
                                        FROM Hierarchy
                                               INNER JOIN Tally
                                                      ON Tally.N BETWEEN 1
                                                      AND DATALENGTH(Hierarchy.SortPath)
                                        WHERE Hierarchy.Id = bpc.CategoryId
                                        GROUP BY SUBSTRING(Hierarchy.SortPath,tally.N,4)
                                               , tally.n
                                  ) AS categories
                                  INNER JOIN CategoryPromotions catpromo
                                        ON categories.CategoryId = catpromo.CategoryId
                           ORDER BY categories.N DESC
                    ) AS promos
             WHERE bpc.ProductId = 1
             ORDER BY PriceRank
       ) AS XD
WHERE products.Id = 1;

这是查询结果:

为什么 ROW_NUMBER 不起作用?为了提高查询性能,我能做些什么吗?这将应用于每个单独产品的一百万行结果查询。我试图伪造 +/- 它将用于的结构。

所需的结果是具有最低 DiscountedPrice 的 1 行。 (不能使用 MIN,因为我需要所有列)

编辑:没有 TOP (1)

【问题讨论】:

  • 因为你select TOP(1)你期待什么结果?
  • 如果我删除 TOP(1) 它不会改变最终结果(见编辑)而且我期待我在帖子中所说的(并且需要帮助来实现它)最终结果将是在这种情况下,自 DiscountedPrice 以来的最后一行是最低的

标签: sql-server tsql row-number


【解决方案1】:

ROW_NUMBER 工作正常。问题是您正在为 ProductCategories 表中的每一行计算它。这是您的查询的较轻版本。

WITH cteProductsCategoriesDiscounts AS(
    SELECT 
          ProductsCategories.ProductId
        , ProductsCategories.CategoryId
        , promos.CategoryId AS promoCategoryId
        , Products.Price AS BasePrice
        , promos.Price
        , ISNULL(Products.Price - promos.Price, Products.Price) AS DiscountedPrice
        , ROW_NUMBER() OVER ( PARTITION BY ProductsCategories.ProductId ORDER BY ISNULL(Products.Price - promos.Price, Products.Price) ) AS PriceRank
    FROM Products
    RIGHT JOIN ProductsCategories ON Products.Id = ProductsCategories.ProductId
    CROSS APPLY (
                SELECT  TOP (1)
                          CAST(SUBSTRING(Hierarchy.SortPath,N*4-3,4) AS INT) AS CategoryId
                        , catpromo.Price
                FROM Hierarchy
                INNER JOIN Tally t ON t.N BETWEEN t.n AND DATALENGTH(Hierarchy.SortPath)/4
                INNER JOIN CategoryPromotions catpromo ON CAST(SUBSTRING(Hierarchy.SortPath,N*4-3,4) AS INT) = catpromo.CategoryId
                WHERE Hierarchy.Id = ProductsCategories.CategoryId
                ORDER BY t.N
        ) AS promos
    WHERE ProductsCategories.ProductId = 1
)
SELECT *
FROM cteProductsCategoriesDiscounts
WHERE PriceRank = 1;

编辑:进行了调整以允许多个产品。

【讨论】:

  • 您好,感谢您的快速响应。我最担心的是这一行: RIGHT JOIN ProductsCategories ON Products.Id = ProductsCategories.ProductId 实际的查询非常大,而且有很多事情要做。引入此计算后,它(使用我使用的版本)从 10 秒到 1 分:05 秒。当我可以访问带有数据的实际数据库时,我将在明天使用您的版本进行尝试。这就是为什么我试图使用已经连接的表而不是正确的连接,但明天会用这个版本再试一次。提前谢谢你。
  • RIGHT JOIN 是否必要?不是所有产品都应该在 Products 表中吗?
  • 实际的数据库有一个 ProductTable -> ProductCategories -> Category (with self reference parentCategory) -> CategoryPromotions。我必须列出一个类别中的所有产品,然后爬上阶梯,直到找到促销,请参阅相关问题:stackoverflow.com/questions/57896495/…,然后是其他税收、国际化表格。它发生了很多事情。最大的考验是用一只猫。返回 999992 条记录,我必须计算everyhting(需要 10 秒)加上这个问题,将其提高到 1m+
  • 顺便说一句,您忘记了(我想)多个产品的 ROW_NUMBER 中的 PARTITION BY ProductsCategories.ProductId
  • 是的,我忘了包括它,因为它不在您的查询中,而且我没有添加其他产品的测试日期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 2014-12-18
  • 2019-11-05
  • 2015-04-13
相关资源
最近更新 更多