在单列上使用ORDER BY时ROW_NUMBER()OVER缓慢

时间:2019-05-16 15:07:00

标签: sql sql-server

我在SQL Server 2012中遇到了意外情况。

在尝试为我继承的API实现分页时,我发现带有单个ROW_NUMBER() OVER列的ORDER BY在大型数据集上非常慢。

我首先要说我无权访问执行计划或索引统计信息。

在非生产环境中,我也许可以解决这些问题,但是记录数量却少得多,所以我不确定它是否会有用。

SELECT 
    a.Erp_PK 
FROM
    (SELECT 
         ROW_NUMBER() OVER(ORDER by Erp_RowGUID asc) AS Row#, 
         Erp_PK 
     FROM 
         Erp 
     JOIN 
         Emp ON Emp_PK = Erp_EmpFK 
     WHERE 
         Emp_CompanyFK = 2611) a 
WHERE 
    Row# BETWEEN 399001 AND 400000

Erp表包含超过32,000,000条记录,并且上面的内部where子句返回超过440,000。

我不知道创建API的人为什么决定按GUID进行排序,但是此列确实具有非唯一,非聚集索引。

上面的查询运行大约30秒钟。

尝试了几件事之后,我发现添加Erp_LastModified(也具有非唯一,非聚集索引)作为辅助排序将查询时间减少到1秒。

使用单个ORDER BY中的一个Erp_LastModified,查询时间跳回到了30秒。然后,使用CASTExp_RowGUID as VARCHAR(100))退回到2秒。

我不是在寻找解决方案,而是想了解这里发生的事情。

这一切使我想知道索引的健康状况,而我又无法获得这些索引。

谢谢。

3 个答案:

答案 0 :(得分:2)

您可以尝试使用OFFSET,否则,如果没有改善,请包括查询的执行计划以及带有索引的表的DDL:

SELECT Erp_PK
FROM Erp 
     JOIN Emp ON Emp_PK = Erp_EmpFK 
WHERE Emp_CompanyFK = 2611
ORDER BY Erp_RowGUID ASC
OFFSET 399000 ROWS FETCH NEXT 999 ROWS ONLY;

不幸的是,如果我们不知道对象的DDL并且无法访问执行计划,我们将无法提供更多功能。再加上任何修补程序可能都需要更改的事实,您就无法做,这意味着无法测试任何暗处的刺伤(我建议在生产系统上反对这样做)。

这就像要求汽车工程师向您解释如何修理汽车,因为它加速缓慢,但是您无法向他解释您所看到的一切,也无法对汽车进行任何更改。

如果可以,将数据库置于沙盒环境中,您可以更好地控制它,然后我们可以看到发生了什么事。

答案 1 :(得分:0)

您是否尝试过更改查询以利用Order By子句上的分页?

SELECT Erp_PK 
FROM Erp 
    JOIN Emp ON Emp_PK = Erp_EmpFK 
WHERE Emp_CompanyFK = 2611
Order by a.Erp_PK 
    OFFSET (399000) ROWS FETCH NEXT (1000) ROWS ONLY 

偏移值当然可以是参数

答案 2 :(得分:0)

一种理论是,在emp_pk列的索引中包含order by子句中的第二列(提高性能的列)。您可以通过仅对该列进行排序来进行测试,以查看查询是否需要2秒(索引使用主键进行排序)还是需要30秒(对所有行进行全面扫描以生成排序) )。