답변:
열이 색인화되었다고 가정하면 다음이 합리적으로 효율적이어야합니다.
10 개의 행을 두 번 찾은 다음 일종의 (최대) 20이 리턴되었습니다.
WITH CTE
AS ((SELECT TOP 10 *
FROM YourTable
WHERE YourCol > 32
ORDER BY YourCol ASC)
UNION ALL
(SELECT TOP 10 *
FROM YourTable
WHERE YourCol <= 32
ORDER BY YourCol DESC))
SELECT TOP 10 *
FROM CTE
ORDER BY ABS(YourCol - 32) ASC
(즉, 잠재적으로 아래와 같은 것)
또는 다른 가능성 (최대 10으로 정렬 된 행 수를 줄임)
WITH A
AS (SELECT TOP 10 *,
YourCol - 32 AS Diff
FROM YourTable
WHERE YourCol > 32
ORDER BY Diff ASC, YourCol ASC),
B
AS (SELECT TOP 10 *,
32 - YourCol AS Diff
FROM YourTable
WHERE YourCol <= 32
ORDER BY YourCol DESC),
AB
AS (SELECT *
FROM A
UNION ALL
SELECT *
FROM B)
SELECT TOP 10 *
FROM AB
ORDER BY Diff ASC
주의 : 위의 실행 계획은 간단한 테이블 정의를위한 것이 었습니다.
CREATE TABLE [dbo].[YourTable](
[YourCol] [int] NOT NULL CONSTRAINT [SomeIndex] PRIMARY KEY CLUSTERED
)
기술적으로 아래쪽 분기의 정렬은 Diff에서도 정렬 할 필요가 없으며 두 개의 정렬 된 결과를 병합 할 수 있습니다. 그러나 나는 그 계획을 얻을 수 없었다.
이 쿼리는 계획의 최상위 분기에서 정렬을 제거하기 위해 결국 작동했기 때문에 ORDER BY Diff ASC, YourCol ASC
이뿐 만 아니라 ORDER BY YourCol ASC
그 결과는 아닙니다 . 보조 열을 추가해야했지만 ( YourCol
같은 Diff를 가진 모든 값에 대해 동일한 결과를 변경하지는 않지만 ) 정렬을 추가하지 않고 병합 조인 (연결)을 거칩니다.
SQL Server는 오름차순으로 검색 한 X의 인덱스가 X + Y로 정렬 된 행을 전달하므로 정렬이 필요하지 않다고 추측 할 수 있습니다. 그러나 인덱스를 내림차순으로 이동하면 YX와 동일한 순서로 행을 전달한다고 가정 할 수 없습니다 (또는 단항 마이너스 X). 계획의 두 브랜치는 정렬을 피하기 위해 인덱스를 사용하지만 TOP 10
맨 아래 브랜치의 정렬 Diff
은 원하는 순서대로 정렬하기 위해 정렬됩니다 (이미 이미 순서대로 정렬되어 있음).
다른 쿼리 / 테이블 정의의 경우 SQL Server에서 정렬 식을 찾는 데 의존하기 때문에 하나의 분기만으로 병합 계획을 얻는 것이 까다 롭거나 불가능할 수 있습니다.
TOP
우리는이 경우 유니온을해야한다는 것에 약간 당황하고 놀랐습니다. 다음은 간단하고 효율적입니다
SELECT TOP (@top) *
FROM @YourTable
ORDER BY ABS(YourCol-@x)
다음은 두 쿼리를 비교하는 완전한 코드 및 실행 계획입니다.
DECLARE @YourTable TABLE (YourCol INT)
INSERT @YourTable (YourCol)
VALUES (32),(11),(15),(123),(55),(54),(23),(43),(44),(44),(56),(23)
DECLARE @x INT = 100, @top INT = 5
--SELECT TOP 100 * FROM @YourTable
SELECT TOP (@top) *
FROM @YourTable
ORDER BY ABS(YourCol-@x)
;WITH CTE
AS ((SELECT TOP 10 *
FROM @YourTable
WHERE YourCol > 32
ORDER BY YourCol ASC)
UNION ALL
(SELECT TOP 10 *
FROM @YourTable
WHERE YourCol <= 32
ORDER BY YourCol DESC))
SELECT TOP 10 *
FROM CTE
ORDER BY ABS(YourCol - 32) ASC
SELECT TOP 10 * FROM YourTable ORDER BY ABS(YourCol - 32) ;
더 간단하게 사용할 수도 있습니다 . 효율적이지 않습니다.