Paul White apontou uma resposta para uma pergunta semelhante contendo um link para um artigo interessante de Itzik Ben Gan . Isso descreve o modelo "Árvore de intervalo relacional estático" que permite que isso seja feito com eficiência.
Em resumo, essa abordagem envolve o armazenamento de um valor calculado ("forknode") com base nos valores de intervalo na linha. Ao pesquisar intervalos que cruzam outro intervalo, é possível pré-calcular os possíveis valores de código de código que as linhas correspondentes devem ter e usá-lo para encontrar os resultados com um máximo de 31 operações de busca (o abaixo suporta números inteiros no intervalo de 0 a o máximo assinado 32 bit int)
Com base nisso, reestruturei a tabela como abaixo.
CREATE TABLE dbo.MyTable3
(
Id INT IDENTITY PRIMARY KEY,
RangeFrom INT NOT NULL,
RangeTo INT NOT NULL,
node AS RangeTo - RangeTo % POWER(2, FLOOR(LOG((RangeFrom - 1) ^ RangeTo, 2))) PERSISTED NOT NULL,
CHECK (RangeTo > RangeFrom)
);
CREATE INDEX ix1 ON dbo.MyTable3 (node, RangeFrom) INCLUDE (RangeTo);
CREATE INDEX ix2 ON dbo.MyTable3 (node, RangeTo) INCLUDE (RangeFrom);
SET IDENTITY_INSERT MyTable3 ON
INSERT INTO MyTable3
(Id,
RangeFrom,
RangeTo)
SELECT Id,
RangeFrom,
RangeTo
FROM MyTable
SET IDENTITY_INSERT MyTable3 OFF
E, em seguida, usou a seguinte consulta (o artigo está procurando intervalos de interseção, portanto, encontrar um intervalo contendo um ponto é um caso degenerado disso)
DECLARE @value INT = 50000000;
;WITH N AS
(
SELECT 30 AS Level,
CASE WHEN @value > POWER(2,30) THEN POWER(2,30) END AS selected_left_node,
CASE WHEN @value < POWER(2,30) THEN POWER(2,30) END AS selected_right_node,
(SIGN(@value - POWER(2,30)) * POWER(2,29)) + POWER(2,30) AS node
UNION ALL
SELECT N.Level-1,
CASE WHEN @value > node THEN node END AS selected_left_node,
CASE WHEN @value < node THEN node END AS selected_right_node,
(SIGN(@value - node) * POWER(2,N.Level-2)) + node AS node
FROM N
WHERE N.Level > 0
)
SELECT I.id, I.RangeFrom, I.RangeTo
FROM dbo.MyTable3 AS I
JOIN N AS L
ON I.node = L.selected_left_node
AND I.RangeTo >= @value
AND L.selected_left_node IS NOT NULL
UNION ALL
SELECT I.id, I.RangeFrom, I.RangeTo
FROM dbo.MyTable3 AS I
JOIN N AS R
ON I.node = R.selected_right_node
AND I.RangeFrom <= @value
AND R.selected_right_node IS NOT NULL
UNION ALL
SELECT I.id, I.RangeFrom, I.RangeTo
FROM dbo.MyTable3 AS I
WHERE node = @value;
Isso normalmente é executado na 1ms
minha máquina quando todas as páginas estão em cache - com estatísticas de E / S.
Table 'MyTable3'. Scan count 24, logical reads 72, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 4, logical reads 374, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
e planejar
NB: A fonte usa TVFs com várias instruções em vez de uma CTE recursiva para obter a adesão dos nós, mas no interesse de tornar minha resposta independente, eu optei pela última. Para uso em produção, eu provavelmente usaria os TVFs.