У мене є дві таблиці, в яких я зберігаю:
- діапазон 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.