Eu tenho duas tabelas nas quais guardo:
- um intervalo de IP - tabela de pesquisa de país
- uma lista de solicitações provenientes de IPs diferentes
Os IPs foram armazenados como bigint
s para melhorar o desempenho da pesquisa.
Esta é a estrutura da tabela:
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
)
Quero obter o detalhamento da solicitação por país e, portanto, faço a seguinte consulta:
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
Eu tenho muitos registros nas tabelas: cerca de 200.000 IP2Country
e alguns milhões Request
, portanto a consulta demora um pouco.
Observando o plano de execução, a parte mais cara é uma Busca de Índice em Cluster no índice PK_IP2Country, que é executado várias vezes (o número de linhas na Solicitação).
Além disso, algo que me parece um pouco estranho é a left join ip2country ic on r.IP between ic.begin_num and ic.end_num
parte (não sei se há uma maneira melhor de executar a pesquisa).
A estrutura da tabela, alguns dados de amostra e consulta estão disponíveis no SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (infelizmente não acho que posso inserir muitos registros para reproduzir o problema, mas isso espero que dê uma idéia).
Como (obviamente) eu não sou especialista em otimizações / desempenho de SQL, minha pergunta é: existem formas óbvias pelas quais essa estrutura / consulta possa ser aprimorada em termos de desempenho que estou perdendo?
begin_ip
e end_ip
manter colunas calculadas, para evitar a possibilidade de o texto e os números ficarem fora de sincronia de alguma forma.
ip2country (begin_num, end_num)
?
give me the first record that has a begin_num < ip in asc order of begin_num
(corrija-me se estiver errado) pode ser válida e melhorar o desempenho.
begin_num
e depois verifica end_num
dentro desse conjunto e encontra apenas um registro.
begin_num
. Eu também tenho que participar comA BETWEEN B AND C
bastante frequência, e estou curioso para saber se há uma maneira de conseguir isso sem a junção tediosa do RBAR.