【问题标题】:ROW_NUMBER() OVER PARTITION optimizationROW_NUMBER() OVER PARTITION 优化
【发布时间】:2018-07-25 09:45:16
【问题描述】:

我有以下疑问:

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

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

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

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

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

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

【问题讨论】:

  • 子查询本身是否包含表扫描?
  • @AaronDietz 是的,确实如此。它需要为每一行设置排名,这似乎是合乎逻辑的。也许我希望 MSSQL 优化器做所有事情,这就是“为什么 MSSQL 进行整个索引扫描?”的答案。问题。
  • 看来关闭需要 2 分钟。我会寻找其他正在发生的事情。尝试使用 nolock - 通常不是一个好的解决方案,但会指出锁是否是问题所在。对索引进行碎片整理。
  • @Paparazzi 我试过 WITH (NOLOCK) 和 OPTION(RECOMPILE) 但没有帮助
  • offers 表中需要哪些字段?为什么不通过查询代码和价格进行分组,然后返回到代码和价格的报价表中

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


【解决方案1】:

在尝试了多种不同的解决方案后,我发现使用 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 行,在我的情况下,我需要前 8 行...所以我需要 OUTER JOIN 而不是 CROSS APPLY。
【解决方案2】:

尝试在 ( 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 值,获取top 1Id(以避免重复价格的问题) Min( Price ) 对应 Code 的行,加入 Offers 以获得完整的行。同样,更紧凑的索引应该会有所帮助。

【讨论】:

  • 第一个解决方案要慢得多。你的第二个猜测是什么意思?问题是在组中以最低价格获得记录 ID。我尝试使用分区和行号来实现这一点,但速度很慢。
  • 这个想法是鼓励查询优化器以最佳方式使用索引。如果它在Code 值上查找( Code, Price ) 上的索引,则第一个匹配项还将提供Price 的最小值。然后它可以访问整行并返回所需的数据。不包含列的索引是否会提高原始查询的性能? (检查执行计划以查看是否正在使用索引。)另一种方法是使用触发器来维护唯一的Code 值表,以避免distinct 的开销。
【解决方案3】:

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

示例

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

【讨论】:

    猜你喜欢
    • 2020-01-14
    • 1970-01-01
    • 2018-10-16
    • 2013-02-24
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多