我有两个表存储在其中:
- IP范围-国家/地区查询表
- 来自不同IP的请求列表
IP存储为,bigint
以提高查找性能。
这是表结构:
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 in IP2Country
和数百万in Request
,因此查询需要一段时间。
从执行计划来看,最昂贵的部分是对索引PK_IP2Country的聚集索引寻求,该索引被执行多次(Request中的行数)。
另外,我对此感到有些奇怪的是该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加入,是否有办法实现这一目标。