次のスキーマとサンプルデータの場合
CREATE TABLE T
(
A INT NULL,
B INT NOT NULL IDENTITY,
C CHAR(8000) NULL,
UNIQUE CLUSTERED (A, B)
)
INSERT INTO T
(A)
SELECT NULLIF(( ( ROW_NUMBER() OVER (ORDER BY @@SPID) - 1 ) / 1003 ), 0)
FROM master..spt_values
アプリケーションは、このテーブルの行をクラスター化インデックスの順序で1,000行のチャンクで処理しています。
最初の1,000行は、次のクエリから取得されます。
SELECT TOP 1000 *
FROM T
ORDER BY A, B
そのセットの最後の行は以下です
+------+------+
| A | B |
+------+------+
| NULL | 1000 |
+------+------+
その複合インデックスキーをシークし、それに従って1000行の次のチャンクを取得するクエリを作成する方法はありますか?
/*Pseudo Syntax*/
SELECT TOP 1000 *
FROM T
WHERE (A, B) is_ordered_after (@A, @B)
ORDER BY A, B
これまでに取得できた読み取りの最小数は1020ですが、クエリは複雑すぎます。同等またはそれ以上の効率の簡単な方法はありますか?おそらく、1つの範囲ですべてを実行することができますか?
DECLARE @A INT = NULL, @B INT = 1000
;WITH UnProcessed
AS (SELECT *
FROM T
WHERE ( EXISTS(SELECT A
INTERSECT
SELECT @A)
AND B > @B )
UNION ALL
SELECT *
FROM T
WHERE @A IS NULL AND A IS NOT NULL
UNION ALL
SELECT *
FROM T
WHERE A > @A
)
SELECT TOP 1000 *
FROM UnProcessed
ORDER BY A,
B
FWIW:列A
が作成されNOT NULL
、-1
代わりにセンチネル値が使用される場合、同等の実行プランは確かに単純に見えます
しかし、プラン内の単一のシーク演算子は、単一の連続した範囲に折りたたむのではなく、まだ2つのシークを実行します。
はい、Oracleは違います。
—
マーティンスミス14年
@ypercube-SQL Serverは、残念ながらそのための順序付きスキャンを提供するだけなので、アプリケーションによって既に処理されたすべての行を再読み取りします(論理読み取り2015)。それは最初のキーを追求していません
—
マーティンスミス14年
(NULL, 1000 )
2つの異なる条件で、
—
ypercubeᵀᴹ14年
@A
null であるかどうかで、スキャンを実行しないようです。しかし、計画がクエリよりも優れているかどうかはわかりません。フィドル2
NULL
値が常に最初であることを忘れていました。で補正条件(逆仮定)フィドル