다음 스키마 및 예제 데이터
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이지만 쿼리가 너무 복잡합니다. 동일하거나 더 효율적인 효율성의 방법이 있습니까? 아마도 한 범위에서 모든 것을 수행 할 수있는 사람이 있습니까?
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
대신 사용하면 동등한 실행 계획이 확실히 단순 해 보입니다.
그러나 계획의 단일 탐색 연산자 는 단일 연속 범위로 축소하지 않고 여전히 두 가지 탐색을 수행 하며 논리적 읽기는 거의 동일하므로 아마도 이것이 얻을 수있는만큼 좋을 것으로 의심됩니다.
예, 오라클은 다릅니다.
—
Martin Smith
@ypercube-SQL Server는 불행히도 순서대로 스캔을 수행하므로 응용 프로그램에서 이미 처리 한 모든 행을 다시 읽습니다 (논리적 읽기 2015). 그것은 첫 번째 열쇠를 찾지 않습니다
—
Martin Smith
(NULL, 1000 )
@A
null 여부에 따라 두 가지 조건 이 있으면 스캔을 수행하지 않는 것 같습니다. 그러나 계획이 쿼리보다 낫다면 이해할 수 없습니다. 바이올린 2
NULL
항상 값이 첫 번째 라는 것을 잊었다 . Fiddle