私が保存している2つのテーブルがあります。
- 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
テーブルには多くのレコードがあります。で約20万件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
そのセット内をスキャンして1つのレコードしか見つからないため、このような場合、サーバーは基本的にこれを実行しているようです。
begin_num
。私もA BETWEEN B AND C
かなり頻繁に参加する必要があり、面倒なRBAR参加なしでこれを達成する方法があるかどうか知りたいです。