У меня есть две таблицы, в которых я храню:
- диапазон IP - таблица соответствия стран
- список запросов с разных IP
IP-адреса были сохранены как bigint
s для улучшения производительности поиска.
Это структура таблицы:
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
)
Я хочу получить разбивку запросов по странам, поэтому я выполняю следующий запрос:
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
У меня есть много записей в таблицах: около 200 000 IP2Country
и несколько миллионов Request
, поэтому запрос занимает некоторое время.
Глядя на план выполнения, самая дорогая часть - это поиск кластерного индекса по индексу PK_IP2Country, который выполняется многократно (количество строк в запросе).
Кроме того, кое-что, что я чувствую немного странно, это left join ip2country ic on r.IP between ic.begin_num and ic.end_num
часть (не знаю, есть ли лучший способ выполнить поиск).
Структура таблицы, некоторые примеры данных и запросы доступны в SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (к сожалению, я не думаю, что могу вставить много записей, чтобы воспроизвести проблему, но это надеюсь дает представление).
Я (очевидно) не являюсь экспертом в производительности / оптимизации SQL, поэтому мой вопрос: есть ли очевидные способы, которыми эта структура / запрос может быть улучшена с точки зрения производительности, которую мне не хватает?
begin_ip
и end_ip
сохранении вычисляемых столбцов, чтобы не допустить какой-либо синхронизации текста и чисел.
ip2country (begin_num, end_num)
?
give me the first record that has a begin_num < ip in asc order of begin_num
(поправьте меня, если я ошибаюсь) могла бы быть правильной и повысить производительность.
begin_num
, а затем просматривает end_num
внутри этого набора и находит только одну запись.
begin_num
. Мне также приходится присоединятьсяA BETWEEN B AND C
довольно часто, и мне любопытно узнать, есть ли способ добиться этого без утомительных присоединений RBAR.