Tsql 分区优化上的行数()

Tsql 分区优化上的行数(),tsql,sql-server-2012,query-performance,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行 我在(代码、价格)列上有一个索引,包含语句中的所有其他列 查询运行2分钟

我有以下疑问:

SELECT *
FROM
(
    SELECT *,
        ROW_NUMBER() OVER(PARTITION BY Code ORDER BY Price ASC) as RowNum
    from Offers) r
where RowNum = 1
提供的表包含大约1000万条记录。但是那里只有大约4000个不同的代码。所以我需要得到每个代码价格最低的行,结果中只有4000行

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

查询运行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
列):

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


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

在尝试了多种不同的解决方案后,我发现了使用交叉应用语句的最快查询:

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秒。

子查询本身是否包含表扫描?@AaronDietz是的,它包含。它需要为每一行设置排名,这似乎是合乎逻辑的。也许我想让MSSQL优化器做所有事情,这是“为什么MSSQL做整个索引扫描?”问题的答案。这似乎需要2分钟。我会寻找其他正在发生的事情。尝试使用nolock-通常不是一个好的解决方案,但会指出锁是否是问题所在。对索引进行碎片整理。@Papazzi我尝试了(NOLOCK)和(RECOMPILE)选项,但没有帮助您需要从“提供”表中选择哪些字段。?为什么不对代码和价格进行分组查询,然后将代码和价格返回到offers表呢?第一种解决方案的速度要慢得多。你的第二次猜测是什么意思?问题是以组中最小的价格获取记录的Id。我尝试使用分区和行数来实现这一点,但速度很慢。其目的是鼓励查询优化器以最佳方式使用索引。如果它在
代码
值上搜索
(代码,价格)
上的索引,则第一个匹配也将为
价格
提供最小值。然后,它可以访问整行并返回所需的数据。没有包含列的索引是否会提高原始查询的性能?(检查执行计划以查看是否正在使用索引。)另一种方法是使用触发器来维护唯一
code
值的表,以避免
distinct
的开销。在您的情况下,您需要前1行,在我的情况下,我需要前8行。。。所以我需要一个外部连接,而不是交叉应用。
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