我总是检查我在查询中访问了多少数据,并尝试消除不必要的列和行。好吧,这些只是您可能已经检查过的明显点,但只是想指出以防万一。在您的查询中,性能缓慢可能是因为您执行“Select *”。从表中选择所有列不允许有好的执行计划。检查您是否只需要选定的列,并确保您在表 Orders 上有正确的覆盖索引。
因为在 SQL 2008 版本中没有显式的 SKIPP 或 OFFSET 函数,我们需要创建一个,我们可以通过 INNER JOIN 创建。在一个查询中,我们将首先使用 OrderDate 生成 ID,该查询中将没有其他内容。我们在第二个查询中执行相同的操作,但如果您需要 ALL 列,我们还会从表 ORDER 或 ALL 中选择一些其他感兴趣的列。然后我们加入它以按 ID 和 OrderDate 查询结果,并为第一个查询添加 SKIPP 行过滤器,其中数据集处于所需的最小大小。试试这个代码。
SELECT q2.*
FROM
(
SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, OrderDate
FROM Orders
WHERE OrderDate >= '1980-01-01'
)q1
INNER JOIN
(
SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
FROM Orders
WHERE OrderDate >= '1980-01-01'
)q2
ON q1.RowNum=q2.RowNum AND q1.OrderDate=q2.OrderDate AND q1.rownum BETWEEN 30000 AND 30020
为了给你估计,我用以下测试数据尝试了这个,无论你查询哪个窗口,结果都会在不到 2 秒的时间内返回,并注意该表是 HEAP(无索引)表总共有 2M 行。测试选择正在查询从 50,000 到 50,010 的 10 行
下面的插入大约需要 8 分钟。
IF object_id('TestSelect','u') IS NOT NULL
DROP TABLE TestSelect
GO
CREATE TABLE TestSelect
(
OrderDate DATETIME2(2)
)
GO
DECLARE @i bigint=1, @dt DATETIME2(2)='01/01/1700'
WHILE @I<=2000000
BEGIN
IF @i%15 = 0
SELECT @DT = DATEADD(DAY,1,@dt)
INSERT INTO dbo.TestSelect( OrderDate )
SELECT @dt
SELECT @i=@i+1
END
选择窗口 50,000 到 50,010 用时不到 3 秒。
选择最后一行 2,000,000 到 2,000,000 也需要 3 秒。
SELECT q2.*
FROM
(
SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum
,OrderDate
FROM TestSelect
WHERE OrderDate >= '1700-01-01'
)q1
INNER JOIN
(
SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum
,*
FROM TestSelect
WHERE OrderDate >= '1700-01-01'
)q2
ON q1.RowNum=q2.RowNum
AND q1.OrderDate=q2.OrderDate
AND q1.RowNum BETWEEN 50000 AND 50010