Ich habe zwei Tabellen, in denen ich speichere:
- eine IP-Bereich - Länder-Nachschlagetabelle
- Eine Liste der Anforderungen, die von verschiedenen IPs stammen
Die IPs wurden als bigint
s gespeichert , um die Suchleistung zu verbessern.
Dies ist die Tabellenstruktur:
create table [dbo].[ip2country](
[begin_ip] [varchar](15) NOT NULL,
[end_ip] [varchar](15) NOT NULL,
[begin_num] [bigint] NOT NULL,
[end_num] [bigint] NOT NULL,
[IDCountry] [int] NULL,
constraint [PK_ip2country] PRIMARY KEY CLUSTERED
(
[begin_num] ASC,
[end_num] ASC
)
)
create table Request(
Id int identity primary key,
[Date] datetime,
IP bigint,
CategoryId int
)
Ich möchte die Aufschlüsselung der Anfragen nach Ländern erhalten, daher führe ich die folgende Abfrage durch:
select
ic.IDCountry,
count(r.Id) as CountryCount
from Request r
left join ip2country ic
on r.IP between ic.begin_num and ic.end_num
where r.CategoryId = 1
group by ic.IDCountry
Ich habe viele Datensätze in den Tabellen: ungefähr 200.000 Zoll IP2Country
und einige Millionen Zoll Request
, daher dauert die Abfrage eine Weile.
Mit Blick auf den Ausführungsplan ist der teuerste Teil ein Clustered Index Seek für den Index PK_IP2Country, der viele Male ausgeführt wird (die Anzahl der Zeilen in Request).
Außerdem ist etwas, bei dem ich mich etwas seltsam fühle, der left join ip2country ic on r.IP between ic.begin_num and ic.end_num
Teil (ich weiß nicht, ob es einen besseren Weg gibt, die Suche durchzuführen).
Die Tabellenstruktur, einige Beispieldaten und die Abfrage sind in SQLFiddle verfügbar: http://www.sqlfiddle.com/#!3/a463e/3 (leider glaube ich nicht, dass ich viele Datensätze einfügen kann, um das Problem zu reproduzieren, aber dies hoffentlich gibt eine Idee).
Ich bin (offensichtlich) kein Experte für SQL-Leistung / -Optimierungen, daher lautet meine Frage: Gibt es offensichtliche Möglichkeiten, wie diese Struktur / Abfrage in Bezug auf die Leistung verbessert werden kann, die mir fehlen?
quelle
begin_num
. Ich muss auchA BETWEEN B AND C
ziemlich oft mitmachen , und ich bin gespannt, ob es einen Weg gibt, dies ohne langwierige RBAR-Beitritte zu erreichen.begin_ip
undend_ip
beizubehalten, um zu verhindern, dass Text und Zahlen irgendwie nicht mehr synchron sind.ip2country (begin_num, end_num)
?give me the first record that has a begin_num < ip in asc order of begin_num
(korrigieren Sie mich, wenn ich falsch liege ) gültig sein und die Leistung verbessern könnte.begin_num
nachend_num
diesem Satz scannt , dann innerhalb dieses Satzes nach ihm scannt und nur einen Datensatz findet.Antworten:
Sie benötigen einen zusätzlichen Index. In Ihrem Geigenbeispiel habe ich hinzugefügt:
CREATE UNIQUE INDEX ix_IP ON Request(CategoryID, IP)
Was Sie für die Anforderungstabelle abdeckt und eine Indexsuche anstelle eines Clustered-Index-Scans erhält.
Sehen Sie, wie sich das verbessert, und lassen Sie es mich wissen. Ich vermute, es wird ziemlich viel helfen, da der Scan dieses Index sicher nicht billig ist.
quelle
Es gibt immer den Brute-Force-Ansatz: Sie könnten Ihre IP-Karte explodieren lassen. Verbinden Sie eine Zahlentabelle mit Ihrer vorhandenen Karte, um einen Datensatz pro IP-Adresse zu erstellen. Das sind nur 267.000 Datensätze basierend auf Ihren Fiddle-Daten, überhaupt kein Problem.
Dies würde die Suche einfacher und hoffentlich schneller machen. Dies ist
ip2country
natürlich nur dann sinnvoll, wenn Sie relativ wenige Updates vornehmen .Ich hoffe jemand anderes hat eine bessere Lösung!
quelle
Versuche dies:
quelle