İçinde depoladığım iki tablo var:
- IP aralığı - ülke arama tablosu
- farklı IP'lerden gelen isteklerin bir listesi
IP'ler, bigint
arama performansını artırmak için s olarak saklandı .
Bu tablo yapı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
)
Ülke başına istek dökümü almak istiyorum, bu yüzden aşağıdaki sorguyu gerçekleştirmek:
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
Tablolarda kayıtları bir sürü var: yaklaşık 200.000 inç IP2Country
ve birkaç milyon Request
, bu yüzden sorgu biraz zaman alır.
Yürütme planına bakıldığında, en pahalı kısım, PK_IP2Country dizininde, birçok kez yürütülen (İstek'teki satır sayısı) bir Kümelenmiş Dizin Aramasıdır.
Ayrıca, biraz garip hissettiğim bir şey left join ip2country ic on r.IP between ic.begin_num and ic.end_num
kısmı (aramayı gerçekleştirmenin daha iyi bir yolu olup olmadığını bilmiyorum).
Tablo yapısı, bazı örnek veriler ve sorgu SQLFiddle'da mevcuttur: http://www.sqlfiddle.com/#!3/a463e/3 (ne yazık ki sorunu yeniden oluşturmak için birçok kayıt ekleyebileceğimi sanmıyorum, ancak bu umarım bir fikir verir).
Ben (açıkçası) SQL performans / optimizasyon konusunda uzman değilim, bu yüzden sorum şu: Bu yapı / sorgunun eksik olduğum performans açısından akıllıca geliştirilebileceği herhangi bir belirgin yol var mı?
begin_ip
ve end_ip
devam ettirmeyi düşünürdüm .
ip2country (begin_num, end_num)
mı?
give me the first record that has a begin_num < ip in asc order of begin_num
(yanlışsam beni düzelt) gibi bir sorgu fikriniz geçerli olabilir ve performansı artırabilir.
begin_num
, sonra end_num
bu kümenin içinde tarar ve sadece bir kayıt bulur.
begin_num
. AyrıcaA BETWEEN B AND C
oldukça sık katılmalıyım ve bunu sıkıcı RBAR birleşmeleri olmadan başarmanın bir yolu olup olmadığını merak ediyorum.