Tengo dos mesas en las que almaceno:
- un rango de IP - tabla de búsqueda de países
- una lista de solicitudes provenientes de diferentes IP
Las IP se almacenaron como bigint
s para mejorar el rendimiento de búsqueda.
Esta es la estructura de la tabla:
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
)
Quiero obtener el desglose de la solicitud por país, por lo que realizo la siguiente 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
Tengo muchos registros en las tablas: alrededor de 200,000 IP2Country
y algunos millones Request
, por lo que la consulta lleva un tiempo.
Mirando el plan de ejecución, la parte más costosa es una Búsqueda de índice agrupado en el índice PK_IP2Country, que se ejecuta muchas veces (el número de filas en Solicitud).
Además, algo de lo que me siento un poco extraño es la left join ip2country ic on r.IP between ic.begin_num and ic.end_num
parte (no sé si hay una mejor manera de realizar la búsqueda).
La estructura de la tabla, algunos datos de muestra y consultas están disponibles en SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (desafortunadamente no creo que pueda insertar muchos registros para reproducir el problema, pero esto con suerte da una idea).
No soy (obviamente) un experto en rendimiento / optimizaciones de SQL, así que mi pregunta es: ¿hay alguna forma obvia de mejorar esta estructura / consulta en cuanto al rendimiento que me falta?
begin_ip
y end_ip
persistentes, para evitar la posibilidad de que el texto y los números se desincronicen de alguna manera.
ip2country (begin_num, end_num)
?
give me the first record that has a begin_num < ip in asc order of begin_num
(corríjame si me equivoco) podría ser válida y mejorar el rendimiento.
begin_num
, luego escanea end_num
dentro de ese conjunto y solo encuentra un registro.
begin_num
. También tengo que unirme conA BETWEEN B AND C
bastante frecuencia, y tengo curiosidad por saber si hay una manera de lograr esto sin tediosas uniones RBAR.