【问题标题】:SQL Server varbinary clustered index lookups slow for certain rangesSQL Server varbinary 聚集索引查找对于某些范围很慢
【发布时间】:2017-10-26 21:04:23
【问题描述】:

在我的工作中,我们目前有一个包含 5000 万行的表,该表在 ip_start 和 ip_end 两个 Varbinary(16) 列上有一个索引。

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 会在范围之间,或者有更好的方法来索引表,这样未命中就不会造成如此大的命中?

【问题讨论】:

    标签: sql sql-server indexing varbinary


    【解决方案1】:

    SQL Server 不应该理解 varbinary 索引是有序的,因此如果没有匹配项就快速返回?

    SQL Server 理解索引是有序,但它不理解范围不重叠。这个条件@lookup &gt;= ip_start 对一堆 ip 范围(平均大约一半)是正确的,这就是你看到的不匹配的性能。当第一个键不等时,B-Tree 索引不会使用第二个键进行索引查找。

    不幸的是,标准 B-Tree 索引对于这种类型的搜索(二维不等式)并不是最优的。 R-tree(我最初学习为 RD-tree)更适合。这些主要用于空间索引。

    我认为我已经成功完成了这样的查询:

    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 地址范围不重叠。

    【讨论】:

      【解决方案2】:

      在 ip_start 上创建包含列 id 的非聚集索引

      或更新一列 ip_start 上的聚集索引 并在包含列 id 的 ip_end 上创建非集群

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-27
        • 2011-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多