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 bigints để 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 IP2Countryvà 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_numphầ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_ipvà end_ipduy 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_numtrong 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 Ckhá 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.