PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Optimaler Datentyp zum Speichern von IPs


MaSie
30.07.2003, 21:42
Hallo zusammen, habe mal wieder eine Performancefrage.
Für einen Counter (auch zum Einbinden auf andere Webseiten)möchte ich mir die IPs der User merken (in einer mysql-DB) und da ich nur 5 MB für meine DB habe und die natürlich auch noch für andere Sachen hernehmen möchte, muß das Speicherformat natürlich optimal sein.

Daher die Frage:
um wieviel besser ist es, wenn ich anstatt eines Char(15) (also: xxx.xxx.xxx.xxx) das in 4 Spalten trenne, also IP1, IP2, IP3, IP4 mit jeweils nem tinyint (der geht wenn ich mich nicht irre von 0-255, was ja auch der Range der unterIPs entspricht).

Bitte korrigieren, wenn ich mit dem tinyint falsch liege, und ob ich signed oder unsigned nehmen sollte.

Die DB soll nur inserten, keine updates oder selects, daher ist der zeitliche Nachteil akzeptabel.

Bitte keine Vorschläge zum Auslagern in ein Textfile, die Idee hatte ich auch schon, aber ist nicht gerade sehr performant und sicher bei mehreren gleichzeitigen Zugriffen.

Vielen Dank schonmal im Vorraus :)
Martin a.k.a. MaSie


Jan Krüger
30.07.2003, 23:15
TINYINT UNSIGNED stimmt. Aber es ist eigentlich noch viel praktischer, die IP direkt in einem INT-Feld zu speichern (ip1 << 24 + ip2 << 16 + ip3 << 8 + ip4). Beim Auslesen muss man dann zwar die Werte wieder auseinandernehmen, aber das ist auch nicht weiter wild (while($int_ip) { array_unshift($ipx, $int_ip & 255); $int_ip >>= 8; } $ip = implode(".", $ipx); ).

MaSie
30.07.2003, 23:51
Es ist zwar praktischer, diese als einen Int zu speichern, aber am praktischsten wäre es ja im Char :)

Jedoch glaube ich, wenn ich einen normalen (Big)Int hernehme, ist dieser wahrscheinlich in der DB größer als 4 kleine tinyints, da diese ja wirklich komplett in der Range liegen und daher optimaler zu verschlüsseln sein sollten, oder irre ich da?

Wie macht mysql das denn, verschlüsseln die das normal binär:
4*2^9==>36 Bit/Datensatz in der 4 tinyint-version
1*2^39==>39 Bit/Datensatz in der Int-version

Da bei der int-version die 2-stelligen und 1-stelligen mit einfliessen, was aber nur bei der 1. Zahl von links was ausmacht, die anderen bekommen null(en) davor, könnte man da bestenfalls auf 31 Bit kommen(1.060.000.000) (habe die Zahlen schnell nur überschlagen können) um auf max. 36 Bit zu kommen, kann ich max. 34.000.000.000 verschlüsseln (Wahrscheinlichkeit ist geringer), jedoch wäre der Aufwand zum trennen mehrerer DS in der dynamischen Speicherung höher als in der statischen.

Habe ich jetzt was falsch gerechnet, oder ist meine Variante doch günstiger?
Habe noch überlegt, anders zu stückeln, das bringt aber nichts (2*2^19 oder 2^29+2^9), war schon optimal mit 4*2^9.

Jan Krüger
31.07.2003, 15:20
Ich verstehe irgendwie nicht ganz, was du meinst... wie kommst du auf das ^9 bzw. das ^39?

Eine IP-Adresse hat eine Breite von 32 bit (8 Bit für jeden Teil: Werte von 0-255). Das ist genau die Breite von einem Int oder von 4 Tinyints.
Da allerdings die Aufteilung in vier separate Felder mehr Speicherungsaufwand seitens MySQL erfordert, müsste meines Erachtens die Tinyint-Lösung kleiner sein.

MaSie
31.07.2003, 16:02
ok, hatte mich vertan: 2^8 (anstatt ^9) für einen tinyint, da es ja nur bis 255 geht.

Aber ich kann die IP doch nicht als int mit 2^32 verschlüsseln. meine IP ist doch zusammengesetzt mindestens als Wert 1.000.000.000, wobei es wahrscheinlicher ist, daß diese meist länger ist und bis max. 255.255.255.255 geht.

Wenn ich aber 2^32 nehme habe ich (diesmal mit Taschenrechner) 4.294.967.300, was bei weitem nicht ausreicht. Als 4er-tinyint-Variante würde ich mit 32 Bit auskommen, aber als int bräuchte ich für 255.255.255.255 39Bit (=>274,87791 Mrd. mögliche Zahlen).

Ich verstehe irgendwie nicht die Äußerung:
Eine IP-Adresse hat eine Breite von 32 bit (8 Bit für jeden Teil: Werte von 0-255). //Soweit ist das klar, wenn man 8 Bit für jeden Teil ansetzt.
Das ist genau die Breite von einem Int oder von 4 Tinyints.








Wobei jetzt habe ich glaub ich verstanden, was Du meinst: Du willst die einfach zusammenschmeissen mit deinem Codeschnipsel, aber die Bitweise Verschiebung habe ich noch nie so ganz verstanden, da nie gebraucht.
wenn möglich nochmal kurz erklären, wie das geht ("<<" ">>= ")?
Danke im vorraus:)

Schaf
31.07.2003, 17:01
also ... eine ip-adresse:
jedes "feld" geht bis max. 255. aber eigentlich braucht man keine vier felder, das ist nur zur optischen aufteilung, denn jede max. 255 steht für eine max. FFh. und die kann man beliebig hintereinanderweg schreiben (geht nicht mit dez., weil sonst was anderes rauskommt, da es sich nicht um das dez. zahlensystemhandelt, sondern das bin. bzw. hex.) ... also FFFFFFFF ist das selbe wie FF.FF.FF.FF (alles in hex). und FFFFFFFF ist 2^32, also ein int-feld ... passt also ... kompliziert erklärt, aber eigentlich ganz einfach ;-)

Jan Krüger
01.08.2003, 00:09
Anschauungsbeispiel:

IP: 213.133.99.5
Hex: D5.85.63.05
x1 x2 x3 x4
32-Bit-Wert = (x1 << 24) + (x2 << 16) + (x3 << 8) + x4
32-Bit-Hex: D5 85 63 05
32-Bit-Dez: 3582288645
2^32: 4294967296
wie du siehst, passt diese IP-Adresse problemlos in einen 32-Bit-Wert (Int-Datentyp von MySQL), und das gleiche gilt für die IP-Adresse 255.255.255.255 (Hex-Wert: 0xFFFFFFFF, Dez-Wert: 4294967295).

MaSie
31.08.2003, 15:34
Als Ergänzung (habs letztens noch rausgefunden):

in einem mysql-statement kann man das ent- und verschlüsseln von IPs in Integer automatisch erledigen lassen.

mit
"insert into meineTable set ip=INET_ATON($meine_normale_IP)....."
kann man eine IP als INT in die DB speichern und mit
"select INET_NTOA(IP) as entschluesselteIP from ..."
bekommt man die IP wieder zurück.

ASCII TO Numeric
Numeric TO ASCII)

War doch einfacher als ich dachte (erspart etliche umständliche Funktioen).