クエリでアクセスしているデータの量を常に確認し、不要な列と行を削除しようとします。これらは、すでにチェック済みかもしれないが、まだチェックしていない場合に備えて指摘したかった明らかなポイントです。あなたのクエリでは、「Select *」を実行しているため、パフォーマンスが低下している可能性があります。テーブルからすべての列を選択すると、適切な実行計画が得られません。選択した列のみが必要かどうかを確認し、テーブル Orders に正しいカバリング インデックスがあることを確認します。
明示的な SKIPP または OFFSET 関数は SQL 2008 バージョンでは使用できないため、作成する必要があり、INNER JOIN によって作成できます。1 つのクエリでは、最初に OrderDate で ID を生成し、そのクエリには他に何もありません。2 番目のクエリでも同じことを行いますが、ここではテーブル ORDER または ALL から他の関連する列を選択します (ALL 列が必要な場合)。次に、これを JOIN して ID と OrderDate で結果をクエリし、データ セットが必要な最小サイズである最初のクエリの ADD 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 秒以内に返されます。テーブルはヒープ (インデックスなし) であることに注意してください。テーブルには合計 2M 行があります。test select は、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 秒もかかりませんでした。
最後の 1 行 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