ROW_NUMBER 为所有行返回相同的值(+ 查询性能)
ROW_NUMBER returning the same value for all rows (+ query performance)
我有以下查询(用于展示问题)
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 不起作用?我可以做些什么来提高查询性能吗?这将应用于每个产品的百万行结果查询。我试图伪造 +/- 将在其中使用的结构。
期望的结果是具有最低折扣价格的第 1 行。 (不能使用 MIN,因为我需要所有列)
编辑:没有 TOP (1)
ROW_NUMBER 工作正常。问题是您正在为 ProductCategories table 中的每一行计算它。这是您的查询的简化版本。
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;
编辑:进行了调整以允许使用多个产品。
我有以下查询(用于展示问题)
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 不起作用?我可以做些什么来提高查询性能吗?这将应用于每个产品的百万行结果查询。我试图伪造 +/- 将在其中使用的结构。
期望的结果是具有最低折扣价格的第 1 行。 (不能使用 MIN,因为我需要所有列)
编辑:没有 TOP (1)
ROW_NUMBER 工作正常。问题是您正在为 ProductCategories table 中的每一行计算它。这是您的查询的简化版本。
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;
编辑:进行了调整以允许使用多个产品。