Пол Уайт вказав на відповідь на подібне запитання, що містить посилання на цікаву статтю Іціка Бен Гана . Це описує модель "Статичного реляційного інтервального дерева", яка дозволяє це зробити ефективно.
Підсумовуючи підсумок, цей підхід передбачає збереження обчисленого ("forknode") значення на основі інтервальних значень у рядку. Під час пошуку діапазонів, що перетинають інший діапазон, можна попередньо підрахувати можливі значення forknode, які повинні мати відповідні рядки, і використовувати це для пошуку результатів максимум 31 операцією пошуку (нижче наведено цілі числа в діапазоні від 0 до максимально підписаного 32 біт int)
На основі цього я реструктурував таблицю, як показано нижче.
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
А потім використовується наступний запит (стаття шукає пересічні інтервали, тому пошук інтервалу, що містить точку, є виродженим випадком цього)
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;
Зазвичай це виконується в 1ms
на моїй машині, коли всі сторінки знаходяться в кеші - зі статистикою IO.
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.
і планувати
NB: Джерело використовує багатоступеневі телевізійні канали, а не рекурсивний CTE для отримання вузлів для приєднання, але в інтересах зробити свою відповідь самодостатньою я вибрав останнє. Для виробництва я б, ймовірно, використовував телевізори.