저장하는 두 개의 테이블이 있습니다.
- IP 범위-국가 조회 테이블
- 다른 IP에서 온 요청 목록
bigint
조회 성능을 향상시키기 위해 IP를 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에서 Clustered Index Seek로 여러 번 실행됩니다 (요청의 행 수).
또한, 내가 조금 이상하게 생각하는 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 조인없이이를 달성 할 수있는 방법이 있는지 궁금합니다.