Saya memiliki dua meja tempat saya menyimpan:
- tabel rentang IP - negara pencarian
- daftar permintaan yang berasal dari IP yang berbeda
IP disimpan sebagai bigint
untuk meningkatkan kinerja pencarian.
Ini adalah struktur tabel:
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
)
Saya ingin mendapatkan rincian permintaan per negara, jadi saya melakukan permintaan berikut:
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
Saya memiliki banyak catatan di tabel: sekitar 200.000 IP2Country
dan beberapa juta Request
, sehingga permintaan membutuhkan waktu.
Melihat rencana eksekusi, bagian yang paling mahal adalah Pencarian Indeks Clustered pada indeks PK_IP2Country, yang dieksekusi berkali-kali (jumlah baris dalam Permintaan).
Juga, sesuatu yang saya merasa sedikit aneh adalah left join ip2country ic on r.IP between ic.begin_num and ic.end_num
bagian (tidak tahu apakah ada cara yang lebih baik untuk melakukan pencarian).
Struktur tabel, beberapa sampel data, dan kueri tersedia dalam SQLFiddle: http://www.sqlfiddle.com/#!3/a463e/3 (sayangnya saya tidak berpikir saya bisa memasukkan banyak catatan untuk mereproduksi masalah, tapi ini semoga memberi ide).
Saya (jelas) bukan ahli dalam kinerja / optimasi SQL, jadi pertanyaan saya adalah: Apakah ada cara yang jelas di mana struktur / kueri ini dapat ditingkatkan berdasarkan kinerja yang saya lewatkan?
sumber
begin_num
. Saya juga harusA BETWEEN B AND C
sering bergabung , dan saya ingin tahu apakah ada cara untuk mencapai ini tanpa bergabung dengan RBAR yang membosankan.begin_ip
danend_ip
bertahan kolom terhitung, untuk mencegah kemungkinan teks dan angka keluar dari sinkronisasi entah bagaimana.ip2country (begin_num, end_num)
?give me the first record that has a begin_num < ip in asc order of begin_num
(koreksi saya jika saya salah) dapat menjadi valid dan meningkatkan kinerja.begin_num
, kemudian memindaiend_num
dalam set itu dan hanya menemukan satu catatan.Jawaban:
Anda memerlukan indeks tambahan. Dalam contoh Fiddle Anda, saya menambahkan:
CREATE UNIQUE INDEX ix_IP ON Request(CategoryID, IP)
Yang mencakup Anda untuk tabel permintaan dan mendapatkan pencarian indeks alih-alih pemindaian indeks berkerumun.
Lihat bagaimana meningkatkannya dan beri tahu saya. Saya kira itu akan membantu sedikit karena pemindaian pada indeks itu saya yakin tidak murah.
sumber
Selalu ada pendekatan brute-force: Anda bisa meledak peta IP Anda. Gabung tabel angka dengan peta Anda yang ada untuk membuat satu catatan per alamat IP. Itu hanya catatan 267K berdasarkan data Fiddle Anda, tidak ada masalah sama sekali.
Ini akan membuat pencarian menjadi lebih sederhana, dan semoga lebih cepat. Ini hanya masuk akal jika Anda membuat pembaruan relatif sedikit
ip2country
, tentu saja.Saya harap orang lain memiliki solusi yang lebih baik!
sumber
Coba ini:
sumber