我有以下查询:
SELECT *
FROM
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY Code ORDER BY Price ASC) as RowNum
from Offers) r
where RowNum = 1
优惠表包含约1000万条记录。但那里只有大约4000个不同的代码。所以我需要为每个代码获得最低价格的行,结果中只有4000行。
我在(代码,价格)列上有一个索引,包含INCLUDE语句中的所有其他列。
查询运行2分钟。如果我查看执行计划,我会看到具有10M实际行的索引扫描。所以,我猜它会扫描整个索引以获得所需的值。
为什么MSSQL会进行整个索引扫描?是因为子查询需要整个数据吗?如何避免这种扫描?是否有SQL提示只处理分区中的第一行?
还有其他方法可以优化此类查询吗?
答案 0 :(得分:3)
尝试了多种不同的解决方案之后,我发现了使用CROSS APPLY语句的最快查询:
SELECT C.*
FROM (SELECT DISTINCT Code from Offers) A
CROSS APPLY (SELECT TOP 1 *
FROM Offers B
WHERE A.Code = B.Code
ORDER by Price) C
运行需要约1秒钟。
答案 1 :(得分:1)
尝试在( Code, Price )
上创建索引而不包括其他列,然后(假设有一个唯一的Id
列):
select L.*
from Offers as L inner join
( select Id,
Row_Number() over ( partition by Code order by Price ) as RN
from Offers ) as R on R.Id = L.Id and R.RN = 1
对较小索引的索引扫描应该有所帮助。
第二个猜测是明确地为每个Id
获取Price
行的Code
:获取distinct Code
值,获取Id
top 1
(为了避免重复价格问题)Min( Price )
的{{1}}行,请加入Code
以获取完整的行。同样,更紧凑的索引应该有所帮助。
答案 2 :(得分:0)
不确定您是否会获得任何显着的性能提升,但您可能想尝试 WITH TIES 子句
示例强>
Select Top 1 with Ties *
From Offers
Order By Row_Number() over (Partition By Code Order By Price)