ฉันมีสองตารางที่ฉันเก็บ:
- ช่วง 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
ฉันมีบันทึกจำนวนมากในตาราง: ประมาณ 200,000 ใน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
ภายในชุดนั้นและค้นหาระเบียนเดียวเท่านั้น
begin_num
ได้ ฉันยังต้องเข้าร่วมA BETWEEN B AND C
ค่อนข้างบ่อยและฉันอยากรู้ว่ามีวิธีในการบรรลุโดยไม่ต้อง RBAR เข้าร่วม