保罗·怀特(Paul White)指出了一个类似问题的答案,其中包含与Itzik Ben Gan的一篇有趣文章的链接。这描述了“静态关系间隔树”模型,该模型可以有效地完成此任务。
总而言之,该方法涉及基于行中的间隔值存储计算的(“ 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.
和计划
注意:源使用多语句TVF而不是递归CTE来使节点加入,但是出于使我的答案自成一体的目的,我选择了后者。对于生产用途,我可能会使用TVF。