J'ai deux tables dans lesquelles je stocke:
- une plage d'adresses IP - table de recherche par pays
- une liste de requêtes provenant de différentes IP
Les adresses IP ont été stockées sous forme de bigint
s pour améliorer les performances de recherche.
Voici la structure du tableau:
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
)
Je souhaite obtenir la répartition des demandes par pays, j'exécute donc la requête suivante:
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
J'ai beaucoup d'enregistrements dans les tableaux: environ 200 000 IP2Country
et quelques millions Request
, la requête prend donc un certain temps.
En regardant le plan d'exécution, la partie la plus coûteuse est une recherche d'index cluster sur l'index PK_IP2Country, qui est exécutée plusieurs fois (le nombre de lignes dans la demande).
En outre, quelque chose qui me semble un peu étrange est la left join ip2country ic on r.IP between ic.begin_num and ic.end_num
partie (je ne sais pas s'il existe une meilleure façon d'effectuer la recherche).
La structure de la table, des exemples de données et des requêtes sont disponibles dans SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (malheureusement, je ne pense pas pouvoir insérer de nombreux enregistrements pour reproduire le problème, mais cela donne, espérons-le, une idée).
Je ne suis (évidemment) pas un expert en performances / optimisations SQL, donc ma question est la suivante: y a-t-il des façons évidentes d'améliorer cette structure / requête en termes de performances qui me manquent?
begin_ip
et end_ip
persistantes, pour éviter que le texte et les chiffres ne se désynchronisent d'une manière ou d'une autre.
ip2country (begin_num, end_num)
?
give me the first record that has a begin_num < ip in asc order of begin_num
(corrigez-moi si je me trompe) pourrait être valide et améliorer les performances.
begin_num
, puis analyse end_num
dans cet ensemble et ne trouve qu'un seul enregistrement.
begin_num
. Je dois également participerA BETWEEN B AND C
assez souvent, et je suis curieux de savoir s'il existe un moyen d'y parvenir sans les fastidieuses jointures RBAR.