没有一个索引可以满足这个查询。这实际上意味着您最好创建两个索引并运行两个查询,然后合并结果......
1)在 InputBegin 上创建一个索引
2)在 InputEnd 上创建一个单独的索引
3)运行以下查询
SELECT * FROM yourTable WHERE InputEnd < ExclusionPeriodStart
UNION ALL
SELECT * FROM yourTable WHERE InputBegin > ExclusionPeriodEnd
然后,第一个查询可以在 InputEnd 索引上使用范围查找。然后,第二个查询也可以使用范围搜索,但在不同的索引上。
通过保持查询分开,两种不同的需求不会相互干扰,并且可以使用最优化的索引。
您还已经知道(通过了解您的数据)结果中没有重叠(在完成之前没有记录可以开始,因此两个查询中都不会出现记录)。这意味着UNION ALL
可以使用速度较慢的UNION
.
据我所知,没有办法比这更快地执行此查询。(在 500 万条记录上,仅在小型数据集上扫描整个表可能会更快。)
编辑:该答案假定您正在尝试查找未出现在固定范围内的所有记录。如果您想检查每条记录与其他记录,那么您需要一种不同的方法......
检查每个重叠是昂贵的。此外,如果您有这四个范围,则无法确定要删除的范围...
1 -->--> 4
3 -->--> 6
5 -->--> 8
7 -->--> 9
您应该删除范围 1 和 3,还是 2 和 4?
您可以做的是找到与另一个范围重叠的所有范围。
而你不想要的是发现A与B重叠,B与A重叠。
SELECT
*
FROM
yourTable AS first_range
INNER JOIN
yourTable AS second_range
ON second_range.start_date >= first_range.start_date
AND second_range.start_date <= first_range.end_date
这将需要扫描整个表的 first_range。但是因为您只检查第二个范围的 start_date,它将能够在 start_date 索引上使用范围搜索来查找任何冲突。
EDIT2:或者您可能需要与第一个答案相反的答案?
如果您希望所有范围与设定范围发生冲突,则可以修改相同方法。
SELECT * FROM yourTable WHERE InputEnd >= ExclusionPeriodStart
INTERSECT
SELECT * FROM yourTable WHERE InputBegin <= ExclusionPeriodEnd
然而,这可能不是很好。您将在 query1 中获取表的一部分,并将其与表的几乎所有其余部分相交。相反,您可以使用简单的方法,然后添加优化...
SELECT
*
FROM
yourTable
WHERE
InputStart <= ExclusionPeriodEnd
AND InputEnd >= ExclusionPeriodStart
WHERE 子句中的第一个条件可以通过范围查找来解决,然后扫描所有结果记录以测试第二个条件。那么,我们是否可以缩小需要扫描的范围(currently (start of table) -> (ExclusionPeriodEnd))
。
如果我们知道一条额外的信息,我们可以:任何一个范围的最大长度......
SELECT
*
FROM
yourTable
WHERE
InputStart <= ExclusionPeriodEnd
AND InputStart >= ExclusionPeriodStart - (maximumLength)
AND InputEnd >= ExclusionPeriodStart
现在前两个条件形成了范围搜索,并提供了一组更小的数据来扫描最后一个条件。
你怎么知道最大长度?您可以扫描整个表,但这是一种自我挫败的优化尝试。
相反,您可以索引一个计算字段;给出范围最大长度的计算。 SELECT MAX(calculatedField) FROM yourTable
然后避免扫描整个表。或者您可以使用触发器跟踪。这对 INSERTS 来说很好,但是当你有一个 DELETE 时有点混乱(如果你删除最长的范围,你是否再次扫描整个表以找到新的最长范围?可能不是,你可能会想保留旧的最大长度反而)。