2017-10-26 14 views
1

Bei meiner Arbeit haben wir derzeit eine Tabelle mit 50 Millionen Zeilen, die einen Index für zwei Varbinary (16) Säulen, die ip_start und ip_end sind.SQL Server varbinary gruppierten Index-Lookups langsam für bestimmte Bereiche

PRIMARY KEY CLUSTERED 
(
    [ip_end] ASC, 
    [ip_start] ASC 
) 

Die ersten paar Zeilen in der Tabelle sind wie folgt aus:

ip_start ip_end  id 
0x00000000 0x00000000 0 
0x00000001 0x000000FF 1 
0x00000100 0x00FFFFFF 2 
0x01000000 0x010000FF 3 

Die Abfrage verwenden wir Übereinstimmungen zu finden ist:

SELECT TOP 1 id 
FROM dbo.ip_ranges WITH (NOLOCK) 
WHERE @lookup <= ip_end AND @lookup >= ip_start 

Wenn ich eine IP-Lookup wie 0x00000002 es gibt id 1 sofort, aber wenn ich für einen Bereich zu suchen, die zwischen einem Bereich wie 0x000000000000001 es einige Sekunden dauert NULL zurück. Sollte SQL Server nicht verstehen, dass der varbinary-Index geordnet ist, und daher schnell zurückkehren, wenn keine Übereinstimmungen vorhanden sind?

Gibt es einen besseren Weg, dies mit der Erwartung, abzufragen, dass einige IP-Adressen zwischen den Bereichen oder einem besseren Weg zum Indizieren der Tabelle sein wird, so dass Fehlschläge nicht einen so großen Erfolg führen?

Antwort

4

Sollte SQL Server nicht verstehen, dass der varbinary-Index geordnet ist und daher schnell zurückkehrt, wenn keine Übereinstimmungen vorhanden sind?

SQL Server versteht, dass der Index bestellt ist, aber es nicht verstehen, dass sich die Bereiche nicht überlappen. Diese Bedingung @lookup >= ip_start ist für eine Reihe von IP-Bereichen (etwa der Hälfte im Durchschnitt) wahr, und das ist die Leistung, die Sie für ein nicht-Spiel zu sehen. Der B-Tree-Index verwendet den zweiten Schlüssel nicht für eine Indexsuche, wenn der erste Schlüssel eine Ungleichung aufweist.

Leider sind Standard-B-Tree-Indizes für diese Art der Suche nicht optimal (Ungleichungen in zwei Dimensionen). Eine R-tree (die ich ursprünglich als RD-Tree gelernt habe) ist besser geeignet. Diese werden hauptsächlich für räumliche Indizes verwendet.

Ich glaube, ich Erfolg mit einer Abfrage wie diese gehabt haben:

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 sollte einen Index für die Unterabfrage verwenden, schnell die erste passende Zeile zu finden. Sie können dann separat prüfen, ob das Ende des Bereichs in dieser Zeile ist. Dies funktioniert, da sich die IP-Adressbereiche nicht überschneiden.

Verwandte Themen