我在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秒。然后,使用CAST
(Exp_RowGUID as VARCHAR(100)
)退回到2秒。
我不是在寻找解决方案,而是想了解这里发生的事情。
这一切使我想知道索引的健康状况,而我又无法获得这些索引。
谢谢。
答案 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秒(对所有行进行全面扫描以生成排序) )。