天天看點

論IP位址在資料庫中應該用何種形式存儲1、感性認識2、理性認識3、查詢效率

在看公司項目代碼時,有涉及到ip位址存儲,

使用的是varbinary(4),但沒有文檔說明

這引發我的思考——緣起

當設計一個資料表時,考慮使用何種列的資料類型對性能有比較大的影響,如存儲空間、查詢開銷等。甚至還影響到一些操作,如ip位址以字元串的形式存儲在資料庫中,就不可以直接比較大小。還有一點需要考慮,那就是可讀性!資料雖然是存儲在資料庫中,但也要考慮到可讀性問題。

本文要探讨的是“ip位址在資料庫中,應該使用何種形式存儲?”,文章将以實驗為基礎介紹使用何種形式比較适合。

家都知道ip位址分為ipv4、ipv6,這裡我以ipv4為例介紹,ipv6原理是一樣的。ipv4的小為32bits(或者說是4bytes),在使

用過程中,我們通常是用點分十進制格式,如192.168.120.65。如何把"192.168.120.65"存儲到資料庫中呢?

我們考慮下面三個因素:

可讀性

存儲效率

查詢效率

把"192.168.120.65"存儲到資料庫中有多少中可行方法呢?見下表所示:

<b>資料類型</b>

<b>大小</b>

<b>注釋</b>

varchar(15)

占7~15位元組

可讀性最好(192.168.120.65),但是最費存儲空間

bigint

8 位元組

可以将ip位址存儲為類似192168120065的格式,這種可讀性稍差,也比較費存儲空間

int

4 位元組

這種可讀性很差,會存儲為1084782657,由192*16777216+168*65536+120*256+65-2147483648計算所得,占用存儲空間少。

tinyint

用4個字段來分開存儲ip位址,可讀性稍差(分别為192, 168, 120, 65),存儲空間占用少

varbinary(4)

可讀性差(0xc0a87841),存儲空間占用少

從大小來看,依次varchar(15)&gt; bigint&gt; int、tinyint、varbinary(4)。

從可讀性來看,依次是varchar(15)&gt; bigint&gt; tinyint&gt; varbinary(4)&gt;int。

從查詢效率來看,

綜合考慮,似乎tinyint比較好,其次是varbinary(4)。但是tinyint需要占多個表字段,而varbinary隻需要占用一個字段即可。正确性還有待下面的實驗檢查!!!

小節通過建立5張表,分别用上述5中資料類型存儲ip位址,每張表插入1,000,000條記錄。說明為了友善消除差異,這些表中插入的都是

192.168.120.65。建表和插入資料的sql語句如下(說明:插入1,000,000條記錄要花挺長時間的,如果你要自己實驗,可以考慮少插入

點資料):

然後我們執行存儲過程sp_spaceused檢視空間效率,執行下面的sql語句:

可以得到下面的結果:

論IP位址在資料庫中應該用何種形式存儲1、感性認識2、理性認識3、查詢效率
說明:上面各個字段的意思如下表所示 列名 資料類型 說明 <b>reserved</b> varchar(18) 由資料庫中對象配置設定的空間總量。 <b>data</b> 資料使用的空間總量。 <b>index_size</b> 索引使用的空間總量。 <b>unused</b> 為資料庫中的對象保留但尚未使用的空間總量。

可以看出,這5張表中的記錄都是1000000,ip_address_varchar占空間最大30792

kb;其次是ip_address_bigint和ip_address_varbinary占用16904

kb;最後是ip_address_int和ip_address_tinyint隻占用16904 kb。

是以從可讀性和空間效率上來看,最理想的是用tinyint的資料類型存儲ip位址。其次應該考慮varbinary(4)和bigint。

理論上bigint肯定要比varbinary占用空間多,可是實驗得出來是一樣的,為什麼呢?我檢視幫助資訊也沒有看出什麼異常,varbinary(4)的确是占用4個位元組、bigint也的确是占用8個位元組,如下圖

論IP位址在資料庫中應該用何種形式存儲1、感性認識2、理性認識3、查詢效率
論IP位址在資料庫中應該用何種形式存儲1、感性認識2、理性認識3、查詢效率

如果有知道的,請告訴我一聲!不過讓我從這兩者之間選(信不過資料結果啊),肯定會選擇使用varbinary(4)而不是bigint。如果能夠證明資料結果沒有錯,應該選擇bigint,因為他的可讀性更好!

本小節比較上述5中存儲ip位址的查詢效率。為了比較查詢效率,這裡重新插入資料,消除每張表中的記錄都相同(192.168.120.65),下面編寫存儲過程像資料表中随機插入1000條記錄(但是保證每張表的資料是一樣的)。存儲過程如下:

考慮查找在範圍192.0.0.0~192.255.255.255之間的ip位址的查詢效率問題。說明我忽略了預處理的開銷,即将

192.0.0.0和192.255.255.255轉換為上述的5種類型的時間,代碼中我直接使用了這些值,沒有給出轉換過程,具體代碼如下:

執行得到的消息如下:

sql server 分析和編譯時間:

   cpu 時間 = 0 毫秒,占用時間 = 1 毫秒。

(5 行受影響)

表 'ip_address_varchar'。掃描計數 1,邏輯讀取 6 次,實體讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 實體讀取 0 次,lob 預讀 0 次。

(3 行受影響)

(1 行受影響)

sql server 執行時間:

   cpu 時間 = 0 毫秒,占用時間 = 113 毫秒。

=============================共115毫秒,ip_address_varchar

表 'ip_address_bigint'。掃描計數 1,邏輯讀取 5 次,實體讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 實體讀取 0 次,lob 預讀 0 次。

(2 行受影響)

===================================共4毫秒,ip_address_bigint

表 'ip_address_int'。掃描計數 1,邏輯讀取 5 次,實體讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 實體讀取 0 次,lob 預讀 0 次。

   cpu 時間 = 0 毫秒,占用時間 = 146 毫秒。

===================================共149毫秒,ip_address_int

表 'ip_address_tinyint'。掃描計數 1,邏輯讀取 5 次,實體讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 實體讀取 0 次,lob 預讀 0 次。

   cpu 時間 = 0 毫秒,占用時間 = 85 毫秒。

=======================================共88毫秒,ip_address_tinyint

表 'ip_address_varbinary'。掃描計數 1,邏輯讀取 5 次,實體讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 實體讀取 0 次,lob 預讀 0 次。

   cpu 時間 = 0 毫秒,占用時間 = 13 毫秒。

===================================共15毫秒,ip_address_varbinary

上述結果隻是初略的估計了效率,可能不太精确,但還是具有一定參考價值的!我隻看ip_address_varbinary(15毫秒)、ip_address_tinyint(88毫秒)、ip_address_bigint(4毫秒)。

效率差距還是挺大的,綜合可讀性、存儲效率、查詢效率,我給這三者排序是:

如果考慮存儲效率,tinyint是最好的!其次是bigint,然後是varbinary(4)

如果更多的是考慮查詢效率,bigint是最好的!其次是varbinary(4),然後是tinyint

如果加我選擇,我會使用varbinary(4)。

——熬夜搞這問題,設計實驗和測試方法,頭腦現在有些不清醒了,不知實驗資料和結論有沒有出問題,有發現的請糾正!