ROW_NUMBER() OVER PARTITION 优化

ROW_NUMBER() OVER PARTITION optimization

我有以下查询:

SELECT *
FROM
(
    SELECT *,
        ROW_NUMBER() OVER(PARTITION BY Code ORDER BY Price ASC) as RowNum
    from Offers) r
where RowNum = 1

Offers table 包含大约 1000 万条记录。但是那里只有大约 4000 个不同的代码。所以我需要为每个代码获取价格最低的行,结果中只有 4000 行。

我在(代码、价格)列和 INCLUDE 语句中的所有其他列上有一个索引。

查询运行了 2 分钟。如果我查看执行计划,我会看到索引扫描有 10M 实际行。所以,我猜它会扫描整个索引以获取所需的值。

为什么 MSSQL 进行全索引扫描?是因为子查询需要整个数据吗?如何避免这种扫描?是否有 SQL 提示仅处理分区中的第一行?

还有其他方法可以优化此类查询吗?

不确定您是否会获得任何显着的性能提升,但您可能想尝试 WITH TIES 子句

例子

Select Top 1 with Ties *
 From  Offers
 Order By Row_Number() over (Partition By Code Order By Price)

尝试在 ( 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

对较小索引进行索引扫描应该会有所帮助。

第二个猜测是明确地为每个 Code 获取具有最低 Price 的行的 Id:获取 distinct Code 值,获取 Idtop 1(以避免出现重复价格问题)Min( Price )Code,加入 Offers 以获得完整的行。同样,更紧凑的索引应该有所帮助。

在尝试了多种不同的解决方案后,我找到了使用 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 秒。