2017-10-26 4 views
1

私の仕事では、現在、ip_startとip_endの2つのVarbinary(16)列にインデックスを持つ5,000万行のテーブルがあります。SQL Server varbinaryクラスタリングされたインデックスルックアップが特定の範囲で遅い

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が範囲間にあるか、またはミスがそのような大きなヒットを引き起こさないようにテーブルをインデックスするより良い方法であることを期待してこれをクエリするより良い方法はありますか?

答えて

4

SQL Serverは、varbinaryインデックスが順序付けされていることを理解してはならないため、一致するものがない場合はすぐに戻りますか?

SQL Serverは、インデックスがを命じているが、それは範囲が重ならないことを理解していないことを理解しています。この条件@lookup >= ip_startは、一連のIP範囲(平均で約半分)に当てはまります。これは、不一致の場合に表示されるパフォーマンスです。 Bツリー索引は、最初のキーに不等式がある場合、索引ルックアップに2番目のキーを使用しません。

標準のBツリーインデックスは、このタイプの検索(2つの次元に沿った不等式)には最適ではありません。 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アドレスの範囲が重複しないために機能します。

関連する問題