背景
在Review同事代碼時,發(fā)現(xiàn)同事將 IP 以varchar類型存入數(shù)據(jù)庫。但是,覺得這樣存儲不夠節(jié)省空間。
因為使用varchar類型存儲 IPv4類型的地址,需要15字符進行儲存。且varchar類型,需要額外使用一個字節(jié)記錄字符串長度信息。如果改用無符號整形(int unsigned),只需要4個字節(jié)就可以保存IP信息。非常節(jié)省空間。
問題描述
在MySQL中,如何合理儲存IP信息?
解決辦法
IP寫入數(shù)據(jù)庫
- 使用
inet_aton()命令將IP字符串轉(zhuǎn)化為數(shù)字類型 - 將字段設置為 int unsigned 類型,儲存IP信息
SELECT inet_aton('255.255.255.255');
-> 4294967295
inet_aton 命令的計算方式是這樣的,假設IP為 10.0.5.9,其值為:10×256^3 + 0×256^2 + 5×256^1 + 9 = 167773449。
IP 為 'a.b.c.d' 時,
inet_aton計算值為:a×256^3 + b×256^2 + c×256^1 + d×256^0
讀取 IP 信息
使用 inet_ntoa 命令將數(shù)字轉(zhuǎn)化為字符串IP
SELECT inet_ntoa(4294967295);
-> 255.255.255.255
如何記憶 inet_aton 和 inet_ntoa 命令
以 inet_aton 為例,將其拆成 inet 和 aton 兩部分。前者可以看成是 internet 的縮寫。后者,可以理解成 IP address into number,地址轉(zhuǎn)數(shù)字。正好,inet_aton的功能,就是將字符串類型的IP轉(zhuǎn)化成整形。
同理,inet_ntoa中的 ntoa,可以理解成 number into IP address。
使用 int 類型儲存IP的優(yōu)點與缺點
優(yōu)點:
- 節(jié)省空間。(只占4個字節(jié))
- 便于范圍查詢。(例如,需要對某個網(wǎng)段進行檢索)
缺點:
- 不便于閱讀
- 需要進行轉(zhuǎn)換儲存和查詢
如何處理 IPv6 的儲存
我們可以使用 INET6_ATON 對 IPv6地址進行轉(zhuǎn)化處理,然后使用 VARBINARY(4) 類型進行儲存。讀取值,使用 INET6_NTOA命令。
若 IP 不是有效地址,在使用 INET6_ATON 進行轉(zhuǎn)化時,會返回 NULL 值。
總結(jié)
通過將IP地址轉(zhuǎn)化為整形,然后使用無符號整形類型進行儲存,可以節(jié)省儲存空間。而且對于存在IP范圍查詢的場景,可以非常方便進行查詢。
雖然,使用 varchar類型也能滿足基本需求,但是做技術還是要有點追求。在條件允許的情況下,盡可能地節(jié)省資源,優(yōu)化性能。