2013-03-23 27 views
9

當前爲了保存IP地址,我將它轉換爲數字並將其存儲在集合中。基本上我是這樣做的日誌目的。這意味着我很關心以儘可能快的速度和最小的空間存儲信息。保存mongoDB中的IP地址

我很少將它用於查詢。

我的想法,

  • 存儲爲字符串是肯定的低效。
  • 存儲爲4位數字會更慢,需要更多空間。

儘管如此,我認爲這是一個適當的方法,但對我的目的有沒有更好的方法呢?

+2

4個整數將不適用於IPv6地址。 4位數字*不會佔用比字符串更多的空間。說實話,你必須決定從源字符串轉換還是空間損失更重要,並基於此決定。 – Joe 2013-03-23 19:40:54

+1

你需要查詢生成的結構嗎?如果與其他數據庫寫操作競爭,MongoDB可能不是記錄日誌的最佳選擇。嘗試選項並查看它們的表現。查看該集合的「統計信息」(http://docs.mongodb.org/manual/reference/collection-statistics/),查看平均文檔的大小。你可能也想在內存緩衝中做一些工作,而不是寫很多小的單個文檔。 – WiredPrairie 2013-03-23 21:39:22

+0

你應該轉換爲字符串並存儲它。 – Abhishek 2013-08-17 06:58:51

回答

10

絕對IP地址保存爲數字,如果你不介意的話,它需要工作的額外位,特別是如果你需要做的查詢上的地址,你有大的表/集合。

這裏的原因:

存儲

  • IPv4地址是4個字節,如果存儲爲無符號整數。
  • 當以虛線形式寫出字符串時,IPv4地址在10字節和18字節之間變化。 (假設平均是14個字節。)

即7-15字節字符,再加上2-3個字節,如果您使用的是可變長度的字符串類型,其變化的基礎數據庫,你」上重新使用。如果您有固定長度的字符串表示形式,則必須使用15個字符的固定寬度字段。

磁盤存儲很便宜,所以這在大多數使用情況下都不是問題。然而,內存並不便宜,如果你有一個大的表/集合,並且你想快速查詢,那麼你需要一個索引。字符串編碼的2-3倍存儲懲罰極大地減少了您可以索引的記錄數量,同時仍將索引駐留在內存中。

  • 如果存儲爲無符號整數,則IPv6地址爲16個字節。 (可能爲多個4或8字節整數,具體取決於您的平臺)
  • 當以縮寫的十六進制表示法編碼爲一個字符串時,IPv6地址範圍從6字節到42字節。

在低端,環回地址(:: 1)是3個字節加上可變長度字符串開銷。在高端,像2002:4559:1FE2:1FE2:4559:1FE2:4559:1FE2這樣的地址使用39個字節加上可變長度的字符串開銷。

與IPv4不同,假設平均IPv6字符串長度將是6和42的平均值並不安全,因爲具有大量連續零的地址數量是整個IPv6地址空間的一小部分。只有一些特殊的地址,比如loopback和autoconf地址,可能以這種方式被壓縮。

同樣,對於字符串編碼與整數編碼,這是一個大於2倍的存儲損失。

網絡數學

你認爲路由器店IP地址爲字符串?當然他們不會。

如果您需要對IP地址進行網絡數學計算,則字符串表示形式很麻煩。例如。如果您想編寫一個查詢來搜索特定子網上的所有地址(「返回IP地址爲10.7.200.104/27的所有記錄」,則可以通過屏蔽具有整數子網掩碼的整數地址輕鬆完成此操作。 Mongo不支持這個特定的查詢,但大多數RDBMS都這樣做)。如果你將地址存儲爲字符串,那麼你的查詢將需要將每行轉換爲一個整數,然後對其進行掩碼處理,這會降低幾個數量級。對於IPv4地址,可以在幾個CPU週期內使用2個寄存器完成。將字符串轉換爲整數需要在字符串上循環)

同樣,範圍查詢(「返回所有記錄192.168.1.50和192.168之間的所有記錄.50.100「)與整數地址將能夠使用索引,而字符串地址範圍查詢將不會。

底線

它需要更多一點的工作,但不是很多(有100萬航標()和ntoa()函數在那裏),但如果你正在構建什麼大不了的事情做實您希望將來能夠抵禦未來的需求和大數據集的可能性,您應該將IP地址存儲爲整數,而不是字符串。

如果您正在做一些快速而骯髒的事情,並且不介意將來重塑的可能性,那麼請使用字符串。

對於OP的目的,如果您針對速度和空間進行了優化,並且您不認爲需要經常查詢,那麼爲什麼要使用數據庫呢?只需將IP地址打印到文件。與將其存儲在數據庫中相比,這會更快,存儲效率更高(具有相關的API和存儲開銷)。

0

IPv4是四個字節,因此可以將它存儲到一個32位整數(BSON類型16)中。

http://docs.mongodb.org/manual/reference/bson-types

+1

我想你還沒有看過我的問題。我知道我可以用這種方式儲存它們,而且我已經將它寫在問題中了。我正在尋找一個更詳細的答案,然後只是一個單線,你可以將它們存儲爲一個整數。 – 2013-11-15 17:54:05

+0

我沒看過。你的問題聽起來像'我做到了最好的方式,但還有什麼更好?'。所以基本上我的回答說'是的,我認爲這是最好的方式'。而且沒有必要爲這樣一個簡單的答案寫一本書。 – 2013-11-18 09:28:46

-1

IPv4最簡單的方法是使用提供的有趣數學轉換爲int here

我使用下面的函數(JS)與DB

ipv4Number: function (ip) { 
    iparray = ip.split("."); 
    ipnumber = parseInt(iparray[3]) + 
     parseInt(iparray[2]) * 256 + 
     parseInt(iparray[1]) * Math.pow(256, 2) + 
     parseInt(iparray[0]) * Math.pow(256, 3); 
    if (parseInt(ipnumber) > 0)return ipnumber; 
    return 0; 
} 
+2

這樣做絕對沒有意義,因爲大多數語言都有本地功能,它們的功能非常類似。此外,問題不在於如何將IP轉換爲整數。 – 2014-04-13 05:35:12

1

匹配的有效方式一個IP地址保存爲INT之前轉換。如果你想用cidr過濾器標記一個IP地址,在這裏進行演示:

> db.getCollection('iptag').insert({tags: ['office'], hostmin: 2886991873, hostmax: 2887057406, cidr: '172.20.0.0/16'}) 
> db.getCollection('iptag').insert({tags: ['server'], hostmin: 173867009, hostmax: 173932542, cidr: '10.93.0.0/16'}) 
> db.getCollection('iptag').insert({tags: ['server'], hostmin: 173932545, hostmax: 173998078, cidr: '10.94.0.0/16'}) 

創建標籤索引。

> db.getCollection('iptag').ensureIndex(tags: 1) 

使用cidr範圍過濾ip。 ip2int('10.94.25.32') == 173938976

> db.getCollection('iptag').find({hostmin: {$lte: 173938976}, hostmax: {$gte: 173938976}})