背景
在Review同事代碼時(shí),發(fā)現(xiàn)同事將 IP 以varchar類(lèi)型存入數(shù)據(jù)庫(kù)。但是,覺(jué)得這樣存儲(chǔ)不夠節(jié)省空間药蜻。
因?yàn)槭褂胿archar類(lèi)型存儲(chǔ) IPv4類(lèi)型的地址,需要15字符進(jìn)行儲(chǔ)存替饿。且varchar類(lèi)型语泽,需要額外使用一個(gè)字節(jié)記錄字符串長(zhǎng)度信息。如果改用無(wú)符號(hào)整形(int unsigned)盛垦,只需要4個(gè)字節(jié)就可以保存IP信息湿弦。非常節(jié)省空間。
問(wèn)題描述
在MySQL中腾夯,如何合理儲(chǔ)存IP信息颊埃?
解決辦法
IP寫(xiě)入數(shù)據(jù)庫(kù)
- 使用
inet_aton()
命令將IP字符串轉(zhuǎn)化為數(shù)字類(lèi)型 - 將字段設(shè)置為 int unsigned 類(lèi)型,儲(chǔ)存IP信息
SELECT inet_aton('255.255.255.255');
-> 4294967295
inet_aton
命令的計(jì)算方式是這樣的蝶俱,假設(shè)IP為 10.0.5.9
班利,其值為:10×256^3 + 0×256^2 + 5×256^1 + 9 = 167773449。
IP 為 'a.b.c.d' 時(shí)榨呆,
inet_aton
計(jì)算值為: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
的縮寫(xiě)积蜻。后者闯割,可以理解成 IP address into number
,地址轉(zhuǎn)數(shù)字竿拆。正好宙拉,inet_aton
的功能,就是將字符串類(lèi)型的IP轉(zhuǎn)化成整形丙笋。
同理谢澈,inet_ntoa
中的 ntoa
,可以理解成 number into IP address
御板。
使用 int 類(lèi)型儲(chǔ)存IP的優(yōu)點(diǎn)與缺點(diǎn)
優(yōu)點(diǎn):
- 節(jié)省空間锥忿。(只占4個(gè)字節(jié))
- 便于范圍查詢(xún)。(例如怠肋,需要對(duì)某個(gè)網(wǎng)段進(jìn)行檢索)
缺點(diǎn):
- 不便于閱讀
- 需要進(jìn)行轉(zhuǎn)換儲(chǔ)存和查詢(xún)
如何處理 IPv6 的儲(chǔ)存
我們可以使用 INET6_ATON
對(duì) IPv6地址進(jìn)行轉(zhuǎn)化處理敬鬓,然后使用 VARBINARY(4)
類(lèi)型進(jìn)行儲(chǔ)存。讀取值笙各,使用 INET6_NTOA
命令钉答。
若 IP 不是有效地址,在使用 INET6_ATON
進(jìn)行轉(zhuǎn)化時(shí)酪惭,會(huì)返回 NULL 值希痴。
總結(jié)
通過(guò)將IP地址轉(zhuǎn)化為整形,然后使用無(wú)符號(hào)整形類(lèi)型進(jìn)行儲(chǔ)存春感,可以節(jié)省儲(chǔ)存空間砌创。而且對(duì)于存在IP范圍查詢(xún)的場(chǎng)景,可以非常方便進(jìn)行查詢(xún)鲫懒。
雖然嫩实,使用 varchar
類(lèi)型也能滿足基本需求,但是做技術(shù)還是要有點(diǎn)追求窥岩。在條件允許的情況下甲献,盡可能地節(jié)省資源,優(yōu)化性能颂翼。