在我的工作中,我们目前有一个包含5000万行的表,它有两个Varbinary(16)列的索引,分别是ip_start和ip_end。
PRIMARY KEY CLUSTERED
(
[ip_end] ASC,
[ip_start] ASC
)
表格中的前几行是这样的:
ip_start ip_end id
0x00000000 0x00000000 0
0x00000001 0x000000FF 1
0x00000100 0x00FFFFFF 2
0x01000000 0x010000FF 3
我们用于查找匹配项的查询是:
SELECT TOP 1 id
FROM dbo.ip_ranges WITH (NOLOCK)
WHERE @lookup <= ip_end AND @lookup >= ip_start
当我查找类似0x00000002
的ip时,它会立即返回id 1,但如果我搜索范围介于0x000000000000001
之间的范围,则需要几秒钟才能返回NULL。 SQL Server是否应该理解varbinary索引是否有序,因此如果没有匹配则快速返回?
有没有更好的方法来查询这个,期望一些ip将在范围之间或更好的方式来索引表,以便错过不会造成如此大的打击?
答案 0 :(得分:4)
SQL Server是否应该理解varbinary索引是否有序,因此如果没有匹配则会快速返回?
SQL Server了解索引是 ordered ,但它不理解范围不重叠。这个条件@lookup >= ip_start
对于一堆ip范围(大约平均一半)是正确的,这就是你看到的不匹配的性能。当第一个键具有不等式时,B-Tree索引不使用第二个键进行索引查找。
不幸的是,标准B树索引对于这种类型的搜索并不是最佳的(沿着两个维度的不等式)。 R-tree(我最初学习的是RD树)更适合。这些主要用于空间索引。
我认为我已经成功完成了这样的查询:
SELECT ir.*
FROM (SELECT TOP 1 ir.*
FROM dbo.ip_ranges ir
WHERE @lookup >= ip_start
ORDER BY ip_start
) ir
WHERE @lookup <= ir.ip_end ;
SQL Server应该使用子查询的索引,快速找到第一个匹配的行。然后,您可以单独检查范围的结尾是否在此行上。这是有效的,因为IP地址范围不重叠。
答案 1 :(得分:0)
使用包含列ID在ip_start上创建非聚集索引
或在一列ip_start上更新聚集索引 并在IP_end上使用包含列ID创建非集群