2015-11-03 49 views
2

我有一個表,包含IP地址範圍(作爲整數值)和相應的國家,地區和城市分配到該範圍。它看起來如下:如何有效搜索IP地址範圍?

CREATE TABLE [dbo].[IpToRegion] 
(
    [BeginRange] [bigint] NOT NULL, 
    [EndRange] [bigint] NOT NULL, 
    [CountryCode] [varchar](10) NOT NULL, 
    [Country] [varchar](50) NOT NULL, 
    [Region] [varchar](100) NOT NULL, 
    [City] [varchar](100) NOT NULL 
) ON [PRIMARY] 

CREATE UNIQUE CLUSTERED INDEX [ClusteredIndex-20151031-193911] ON [dbo].[IpToRegion] 
(
    [BeginRange] ASC, 
    [EndRange] ASC 
) 
GO 

此表中有9.1M行。爲了找到一個單一的IP地址的位置,我先將其轉換爲一個大的INT,然後執行以下查詢:

DECLARE @IPNumber BIGINT 
DECLARE @IPAddress varchar(20) 

Set @IPNumber = (CONVERT(bigint, PARSENAME(@IPAddress,1)) + CONVERT(bigint, PARSENAME(@IPAddress,2)) * 256 + CONVERT(bigint, PARSENAME(@IPAddress,3)) * 65536 + CONVERT(bigint, PARSENAME(@IPAddress,4)) * 16777216) 

Select City + ', ' + Region + ', ' + Country 
From IpToRegion 
Where @IPNumber Between BeginRange And EndRange 

問題是這樣的查詢可以從5到20秒到執行。下面是查詢計劃:

enter image description here

當然,我的問題是如何將這些查詢需要很長時間來執行?它正在聚集索引上查找並返回一行。我可以嘗試一些不同的索引策略。但是,在這一點上,我更好奇爲什麼這個查詢可以執行得如此糟糕。

+0

這是一個很好的問題。我可以檢查。這張表剛剛創建並且是靜態的。我只是創建了表格並加載了數據。行以BeginRange順序添加,但我會嘗試重建索引。 –

+0

我不知道爲什麼有人會低估,但試着將問題的標題改爲更具描述性的內容。就像「如何在IP地址範圍內高效搜索」一樣...... –

回答

0

事實證明,我在BeginRange + EndRange上的聚集索引效率不高,因爲弗拉基米爾巴拉諾夫在他的回答中表示。我所做的是在BeginRange上創建一個PK /聚集索引,並在EndRange上創建一個單獨的索引。現在查詢立即執行。

5

這種搜索不能用您擁有的索引高效地完成。

如果您在計劃中查看Index Seek運算符的詳細信息,您會看到兩個謂詞。

@IPNumber >= BeginRange 
@IPNumber <= EndRange 

指數有助於快速O(log(n))查找範圍的開始(或結束),但隨後必須檢查第二個謂詞的行表中的其餘部分。

檢出計劃中讀取的實際行數。它會很大。

如果我沒有弄錯,有些類似(更復雜)question之前。即使它被要求提供Postgres,該方法也可以在SQL Server中使用。在這個問題上,這種搜索沒有一次完成,而是完成了60萬次。


「如何使搜索有效」這個問題的答案取決於幾件事情。首先:你能保證表中的IP範圍不重疊嗎?換句話說,你能保證任何搜索將返回0或1行嗎?

如果是,則向查詢添加一個簡單的TOP(1)就足夠了。