Tôi có hai bảng trong đó tôi lưu trữ:
- một dải IP - bảng tra cứu quốc gia
- một danh sách các yêu cầu đến từ các IP khác nhau
Các IP được lưu trữ dưới dạng bigint
s để cải thiện hiệu suất tra cứu.
Đây là cấu trúc bảng:
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
)
Tôi muốn nhận phân tích yêu cầu cho mỗi quốc gia, vì vậy tôi thực hiện truy vấn sau:
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
Tôi có rất nhiều bản ghi trong các bảng: khoảng 200.000 trong IP2Country
và một vài triệu trong Request
, vì vậy truy vấn mất một lúc.
Nhìn vào kế hoạch thực hiện, phần đắt nhất là Tìm kiếm chỉ mục cụm trên chỉ mục PK_IP2Country, được thực hiện nhiều lần (số lượng hàng trong Yêu cầu).
Ngoài ra, một phần mà tôi cảm thấy hơi lạ là left join ip2country ic on r.IP between ic.begin_num and ic.end_num
phần (không biết có cách nào tốt hơn để thực hiện tra cứu không).
Cấu trúc bảng, một số dữ liệu mẫu và truy vấn có sẵn trong SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (tiếc là tôi không nghĩ rằng tôi có thể chèn nhiều bản ghi để tái tạo vấn đề, nhưng điều này hy vọng đưa ra một ý tưởng).
Tôi (rõ ràng) không phải là một chuyên gia về hiệu suất / tối ưu hóa SQL, vì vậy câu hỏi của tôi là: Có cách nào rõ ràng để cấu trúc / truy vấn này có thể được cải thiện hiệu năng khôn ngoan mà tôi đang thiếu không?
begin_ip
và end_ip
duy trì các cột được tính toán, để ngăn khả năng văn bản và các số không đồng bộ bằng cách nào đó.
ip2country (begin_num, end_num)
?
give me the first record that has a begin_num < ip in asc order of begin_num
(sửa tôi nếu tôi sai) có thể hợp lệ và cải thiện hiệu suất.
begin_num
, sau đó quét end_num
trong bộ đó và chỉ tìm thấy một bản ghi.
begin_num
. Tôi cũng phải tham giaA BETWEEN B AND C
khá thường xuyên và tôi tò mò muốn biết liệu có cách nào để đạt được điều này mà không cần tham gia RBAR tẻ nhạt không.