Tenho duas tabelas nas quais armazeno:
- um intervalo de IP - tabela de pesquisa de país
- uma lista de solicitações provenientes de diferentes IPs
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
)
Desejo obter o detalhamento da solicitação por país, para isso realizo 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
Tenho muitos registros nas tabelas: cerca de 200.000 em IP2Country
e alguns milhões em Request
, então a consulta demora um pouco.
Observando o plano de execução, a parte mais cara é uma busca de índice clusterizado 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 existe uma maneira melhor de realizar a pesquisa).
A estrutura da tabela, alguns dados de exemplo e consulta estão disponíveis no SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (infelizmente acho que não consigo inserir muitos registros para reproduzir o problema, mas isso espero que dê uma ideia).
Eu (obviamente) não sou um especialista em desempenho/otimizações de SQL, então minha pergunta é: há alguma maneira óbvia de melhorar o desempenho dessa estrutura/consulta que estou perdendo?
Você precisa de um índice adicional. No seu exemplo do Fiddle, adicionei:
CREATE UNIQUE INDEX ix_IP ON Request(CategoryID, IP)
Que cobre você para a tabela de solicitação e obtém uma busca de índice em vez de uma varredura de índice clusterizado.
Veja como isso melhora e me avise. Acho que vai ajudar um pouco, já que a varredura nesse índice não é barata.
Há sempre a abordagem de força bruta: você pode explodir seu mapa de IP. Junte-se a uma tabela de números em seu mapa existente para criar um registro por endereço IP. São apenas 267 mil registros com base nos dados do Fiddle, sem nenhum problema.
Isso tornaria as buscas mais simples e, com sorte, mais rápidas. Isso só faz sentido se você fizer relativamente poucas atualizações no
ip2country
, é claro.Espero que alguém tenha uma solução melhor!
Tente isto: