En supposant que la colonne est indexée, les éléments suivants devraient être raisonnablement efficaces.
Avec deux recherches de 10 lignes, puis une sorte de (jusqu'à) 20 retournés.
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
(c'est-à-dire potentiellement quelque chose comme ci-dessous)
Ou une autre possibilité (qui réduit le nombre de lignes triées à 10 au maximum)
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
NB: Le plan d'exécution ci-dessus était pour la définition de table simple
CREATE TABLE [dbo].[YourTable](
[YourCol] [int] NOT NULL CONSTRAINT [SomeIndex] PRIMARY KEY CLUSTERED
)
Techniquement, le tri sur la branche inférieure ne devrait pas non plus être nécessaire car cela est également ordonné par Diff, et il serait possible de fusionner les deux résultats ordonnés. Mais je n'ai pas pu obtenir ce plan.
La requête a ORDER BY Diff ASC, YourCol ASC
et pas seulement ORDER BY YourCol ASC
, car c'est ce qui a fini par fonctionner pour se débarrasser du tri dans la branche supérieure du plan. J'avais besoin d'ajouter la colonne secondaire (même si elle ne changera jamais le résultat car ce YourCol
sera le même pour toutes les valeurs avec le même Diff) afin qu'elle passe par la jointure de fusion (concaténation) sans ajouter de tri.
SQL Server semble capable de déduire qu'un index sur X recherché dans l'ordre croissant fournira des lignes ordonnées par X + Y et aucun tri n'est nécessaire. Mais il n'est pas en mesure de déduire que le déplacement de l'index dans l'ordre décroissant fournira des lignes dans le même ordre que YX (ou même simplement unaire moins X). Les deux branches du plan utilisent un index pour éviter un tri, mais les TOP 10
dans la branche inférieure sont ensuite triées par Diff
(même si elles sont déjà dans cet ordre) pour les obtenir dans l'ordre souhaité pour la fusion.
Pour d'autres requêtes / définitions de table, il peut être plus difficile ou impossible d'obtenir le plan de fusion avec juste une sorte de branche - car il repose sur la recherche d'une expression de classement que SQL Server:
- Accepte que la recherche d'index fournira l'ordre spécifié afin qu'aucun tri ne soit nécessaire avant le sommet.
- Est heureux d'utiliser dans l'opération de fusion et ne nécessite donc aucun tri après la
TOP
SELECT TOP 10 * FROM YourTable ORDER BY ABS(YourCol - 32) ;
Encore plus simple. Pas efficace non plus.