Supponendo che la colonna sia indicizzata, quanto segue dovrebbe essere ragionevolmente efficiente.
Con due ricerche di 10 righe e quindi una sorta di (fino a) 20 restituiti.
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
(ovvero potenzialmente qualcosa di simile al seguente)
O un'altra possibilità (che riduce il numero di righe ordinate a max 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
NB: il piano di esecuzione sopra era per la semplice definizione della tabella
CREATE TABLE [dbo].[YourTable](
[YourCol] [int] NOT NULL CONSTRAINT [SomeIndex] PRIMARY KEY CLUSTERED
)
Tecnicamente, l'ordinamento sul ramo inferiore non dovrebbe essere necessario, poiché anche quello è ordinato da Diff e sarebbe possibile unire i due risultati ordinati. Ma non sono stato in grado di ottenere quel piano.
La query ha ORDER BY Diff ASC, YourCol ASC
e non solo ORDER BY YourCol ASC
, perché è quello che ha funzionato per sbarazzarsi dell'ordinamento nel ramo superiore del piano. Avevo bisogno di aggiungere la colonna secondaria (anche se non cambierà mai il risultato poiché YourCol
sarà lo stesso per tutti i valori con lo stesso Diff) in modo da passare attraverso l'unione di unione (concatenazione) senza aggiungere un ordinamento.
SQL Server sembra in grado di dedurre che un indice su X cercato in ordine crescente recapiterà le righe ordinate da X + Y e non è necessario alcun ordinamento. Ma non è in grado di dedurre che viaggiare l'indice in ordine decrescente recapiterà le righe nello stesso ordine di YX (o anche solo unario meno X). Entrambi i rami del piano utilizzano un indice per evitare un ordinamento ma i TOP 10
rami in basso vengono quindi ordinati per Diff
(anche se sono già in quell'ordine) per farli nell'ordine desiderato per l'unione.
Per altre definizioni di query / tabelle potrebbe essere più complicato o meno possibile ottenere il piano di unione con una sorta di ramo - poiché si basa sulla ricerca di un'espressione di ordinamento che SQL Server:
- Accetta che l'indice cerca fornirà l'ordine specificato, quindi non è necessario alcun ordinamento prima dell'inizio .
- È felice di utilizzare l'operazione di unione, quindi non richiede alcun ordinamento dopo il
TOP
SELECT TOP 10 * FROM YourTable ORDER BY ABS(YourCol - 32) ;
ancora più semplice. Neanche efficiente.