Mam dwa stoliki, w których przechowuję:
- zakres adresów IP - tabela przeglądowa kraju
- lista żądań pochodzących z różnych adresów IP
Adresy IP były przechowywane jako bigint
s, aby poprawić wydajność wyszukiwania.
Oto struktura tabeli:
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
)
Chcę uzyskać podział żądań według kraju, dlatego wykonuję następujące zapytanie:
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
Mam wiele rekordów w tabelach: około 200 000 w IP2Country
i kilka milionów w Request
, więc zapytanie zajmuje trochę czasu.
Patrząc na plan wykonania, najdroższą częścią jest Wyszukiwanie klastrowane na indeksie PK_IP2Country, które jest wykonywane wielokrotnie (liczba wierszy w żądaniu).
Poza tym czuję się trochę dziwnie w tej left join ip2country ic on r.IP between ic.begin_num and ic.end_num
części (nie wiem, czy jest lepszy sposób na przeprowadzenie wyszukiwania).
Struktura tabeli, niektóre przykładowe dane i zapytanie są dostępne w SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (niestety nie sądzę, żebym mógł wstawić wiele rekordów w celu odtworzenia problemu, ale to mam nadzieję, że daje pomysł).
Nie jestem (oczywiście) ekspertem od wydajności / optymalizacji SQL, więc moje pytanie brzmi: czy są jakieś oczywiste sposoby na ulepszenie tej struktury / zapytania pod względem wydajności, których mi brakuje?
begin_ip
i end_ip
utrwalenie kolumn obliczeniowych, aby zapobiec możliwości synchronizacji tekstu i liczb.
ip2country (begin_num, end_num)
?
give me the first record that has a begin_num < ip in asc order of begin_num
(popraw mnie, jeśli się mylę) może być poprawny i poprawić wydajność.
begin_num
, a następnie skanuje w end_num
obrębie tego zestawu i znajduje tylko jeden rekord.
begin_num
. Muszę też dołączaćA BETWEEN B AND C
dość często i jestem ciekawy, czy istnieje sposób na osiągnięcie tego bez żmudnych połączeń RBAR.