ROW_NUMBER()OVER PARTITION优化

时间:2018-02-14 18:07:36

标签: tsql sql-server-2012 query-performance

我有以下查询:

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提示只处理分区中的第一行?

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

3 个答案:

答案 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)