Ho due tavoli in cui conservo:
- un intervallo IP - tabella di ricerca per paese
- un elenco di richieste provenienti da IP diversi
Gli IP sono stati archiviati come bigints per migliorare le prestazioni di ricerca.
Questa è la struttura della tabella:
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
)
Voglio ottenere la suddivisione della richiesta per paese, quindi eseguo la seguente query:
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
Ho molti record nelle tabelle: circa 200.000 in IP2Countrye pochi milioni in Request, quindi la query richiede un po 'di tempo.
Guardando il piano di esecuzione, la parte più costosa è una ricerca dell'indice cluster sull'indice PK_IP2Country, che viene eseguita più volte (il numero di righe nella richiesta).
Inoltre, qualcosa di cui mi sento un po 'strano è la left join ip2country ic on r.IP between ic.begin_num and ic.end_numparte (non so se c'è un modo migliore per eseguire la ricerca).
La struttura della tabella, alcuni dati di esempio e query sono disponibili in SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (purtroppo non penso di poter inserire molti record per riprodurre il problema, ma questo spero che abbia un'idea).
Non sono (ovviamente) un esperto di prestazioni / ottimizzazioni SQL, quindi la mia domanda è: ci sono modi ovvi in cui questa struttura / query può essere migliorata dal punto di vista delle prestazioni e che mi manca?
begin_ipe il end_ippersistere di colonne calcolate, per evitare in qualche modo la possibilità che il testo e i numeri si discostino.
ip2country (begin_num, end_num)?
give me the first record that has a begin_num < ip in asc order of begin_num(correggimi se sbaglio) potrebbe essere valida e migliorare le prestazioni.
begin_num, quindi scansiona end_numall'interno di quel set e trova solo un record.
begin_num. Devo anche unirmiA BETWEEN B AND Cabbastanza spesso e sono curioso di sapere se esiste un modo per raggiungere questo obiettivo senza noiosi join RBAR.