Datum in MySQL
am 12.04.2006 13:52:17 von Marian Ritter
Holla Newsgroup.
Ich habe eine kleine Frage. Ich möchte gerne (via PHP...) in eine
Tabelle "zeiten"(s.u.) IPs eintragen und/oder prüfen, ob die IP
innerhalb der letzten 24h abgerufen wurde/schonmal da war.
Dazu möchte ich zunächst überprüfen, ob die IP überhaupt schon
eingetragen ist:
SELECT ip FROM zeiten WHERE ip =3D '$ip' LIMIT 1
über PHPs mysql_num_rows kann ich dann ja schauen, ob was
zurückgeliefert wird.
(Gibt's da ne 0 wird mit
INSERT INTO zeiten SET ip =3D '$ip', time=3DNOW()
ein Eintrag erzeugt)
Wenn es einen Eintrag gibt, dann möchte ich prüfen, ob die
zugehörige IP innerhalb der letzten 24h abgerufen wurde.
Dazu bastel ich mir in PHP einen MySQL-Timestamp (12 Zeichen, auf die
Minute reicht) und ziehe den entsprechenden Betrag (10000) ab:
$gestern =3D date("Ymdhi") - 10000;
(dieses Date müsste YYYYMMDDHHMM ausgeben, 10000 verkleinert das ganze
um 24h)
und frage dann ab
SELECT ip FROM zeiten WHERE ip =3D '$ip' AND time < '$gestern' LIMIT 1
Wenn dann was positives zurückkommt (also ein Eintrag), war diese IP
seit im Verlaufe des gestrigen Tages nicht zu besuch.
Und dann muss die Sperre natürlich erneuert werden. Ich schätze, das
geht dann mit
UPDATE zeiten SET time=3DCURDATE() WHERE ip =3D '$ip' LIMIT 1;
Soweit so klar. Ich frage mich nur - für diesen einen Aufruf brauche
ich ja drei SQL-Abfragen. Das ist ziemlich viel finde ich und ich
möchte ich die Last für den Server ja möglichst gering halten.
Hat irgendwer ne Idee wie das noch besser geht - besonders bei den
ersten beiden Abfragen?
Funktionieren die Abfragen so überhaupt?
Außerdem wird die Tabelle mit mehr Besuchern ja auch immer größer.
Hat jemand ne Idee, wie man das "platzsparend" lösen kann?
Gibt es für die Spalte ip (s.u.) einen sinnigeren Datentyp als bigint
mit 12 Zeichen?
Ich danke euch im Voraus
Marian
Tabelle "zeiten":
ip bigint(12) NOT NULL auto_increment
time timestamp(12) NULL (Standard "Null")
Re: Datum in MySQL
am 12.04.2006 14:21:18 von Andreas Kretschmer
Andreas
--
Andreas Kretschmer
Linux - weil ich es mir wert bin!
GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net
Deutsche PostgreSQL User Group: http://pgug.de
Re: Datum in MySQL
am 12.04.2006 14:35:15 von Thomas Rachel
Marian Ritter wrote:
> Ich habe eine kleine Frage. Ich möchte gerne (via PHP...) in eine
> Tabelle "zeiten"(s.u.) IPs eintragen und/oder prüfen, ob die IP
> innerhalb der letzten 24h abgerufen wurde/schonmal da war.
Ich glaube, da muÃt Du einen kurzen Schritt zurückgehen und überlegen, was
Du genau willst.
So wie ich Dich verstehe, soll das Endergebis sein: Die gegebene IP soll mit
dem jetzigen Timestamp da stehen. Zusätzlich willst Du in der Applikation
wissen, ob die IP *vorher* einen Timestamp innerhalb der letzten 24 h
hatte:
SET @gestern=DATE_SUB(NOW(), INTERVAL 1 DAY)
SELECT ip FROM zeiten WHERE ip = '$ip' AND time < @gestern LIMIT 1
Das LIMIT 1 ist hier natürlich Unfug, wenn ip unique/primary ist (siehe ganz
unten), wovon ich jetzt mal ausgehe.
Unter diesen Umständen müÃte unter hinreichend neuen Versionen folgendes im
Anschluà gehen:
INSERT INTO zeiten SET ip='$ip', time=NOW()
ON DUPLICATE KEY UPDATE zeiten
SET time=NOW()
WHERE ip='$ip' AND time < @gestern
Dann sind die beiden Queries zumindest mal entkoppelt von der Anwendung.
> Soweit so klar. Ich frage mich nur - für diesen einen Aufruf
Es sind ja zwei Vorgänge - einmal lesen (ich nehme an, Du willst mit dem
Wert noch weiterarbeiten) und einmal schreiben.
Wenn diese Annahme falsch war, reicht sogar der letzte Aufruf...
> Das ist ziemlich viel finde ich und ich
> möchte ich die Last für den Server ja möglichst gering halten.
Die Last ist da, denke ich, weniger das Problem - oder wieviele Anfragen
sind da zu erwarten?
Aber so ist es wesentlich eleganter.
> Gibt es für die Spalte ip (s.u.) einen sinnigeren Datentyp als bigint
> mit 12 Zeichen?
Die Anzahl der Zeichen ist zunächst mal nicht relevant, sofern Du die IP als
32bit-Wert verarbeitest. Dann brauchst Du lediglich einen int unsigned, der
ja von 0..2^32 geht, also genau den Wertebereich einer IP(4) abdeckt.
> Tabelle "zeiten":
> ip bigint(12) NOT NULL auto_increment
Das auto_increment ist hier glaub ich recht überflüssig, aber unique (oder
gar primary) sollte es schon sein (s.o.)
HTH,
Thomas
Re: Datum in MySQL
am 12.04.2006 14:37:12 von Helmut Chang
Marian Ritter schrieb:
> Dazu möchte ich zunächst überprüfen, ob die IP überhaupt schon
> eingetragen ist:
> SELECT ip FROM zeiten WHERE ip = '$ip' LIMIT 1
SELECT COUNT(*) FROM zeiten WHERE ip = $ip
Wozu Quotes, wenns ein BIGINT ist?
> Dazu bastel ich mir in PHP einen MySQL-Timestamp (12 Zeichen, auf die
> Minute reicht) und ziehe den entsprechenden Betrag (10000) ab:
> $gestern = date("Ymdhi") - 10000;
> (dieses Date müsste YYYYMMDDHHMM ausgeben, 10000 verkleinert das ganze
> um 24h)
> und frage dann ab
> SELECT ip FROM zeiten WHERE ip = '$ip' AND time < '$gestern' LIMIT 1
Tjo. DATEADD() oder DATESUB() (oder wie immers jetzt exakt heißt) würde
das evtl. in der Datenbank selbst effizienter tun.
Hätte auch den Vorteil, dass du in einer hinreichend neuen MySQL-Version
die ganze Transaktion in einer Stored Procedure unterbringen könntest.
> Und dann muss die Sperre natürlich erneuert werden. Ich schätze, das
> geht dann mit
> UPDATE zeiten SET time=CURDATE() WHERE ip = '$ip' LIMIT 1;
Das LIMIT kann man, korrigierte Tabelle vorausgesetzt, weglassen.
Ich stelle mal dein Posting um:
> Tabelle "zeiten":
> ip bigint(12) NOT NULL auto_increment
^^^^^^^^^^^^^^
Das glaube ich nicht, Tim! Ich denke eher, dass du PRIMARY KEY meinst.
> time timestamp(12) NULL (Standard "Null")
^^^^^^^^^^^^^^^^^^^^^^
Das glaube ich nach deinen Ausführungen auch nicht. AFAIR geht bei
neueren MySQL-Versionen auch CURDATE() als DEFAULT.
> Außerdem wird die Tabelle mit mehr Besuchern ja auch immer größer.
Teufel auch ;-)! Das hat eine Datenbank im Normalfall so an sich.
> Gibt es für die Spalte ip (s.u.) einen sinnigeren Datentyp als bigint
> mit 12 Zeichen?
Es gibt RDBMS, die haben den Datentyp IP. Obs MySQL jetzt hat, weiß ich
nicht, aber man kann ja im Manual nachschauen. Ansonsten tät ich evtl.
VARCHAR(15) nehmen.
gruss, heli
Re: Datum in MySQL
am 12.04.2006 14:39:16 von mail
Marian Ritter schrieb:
> Holla Newsgroup.
>
> Ich habe eine kleine Frage. Ich möchte gerne (via PHP...) in eine
> Tabelle "zeiten"(s.u.) IPs eintragen und/oder prüfen, ob die IP
> innerhalb der letzten 24h abgerufen wurde/schonmal da war.
>
Also wenn ich es recht verstehe willst Du prüfen ob die gerade
auflaufende IP in den Letzten 24 Stunden schon mal da war und dann
entsprechend reagieren?
Die IP (xxx.xxx.xxx.xxx) würde ich als varchar(15) definieren.
Timestamp ist ok.
dann brauchst Du doch nur noch abfragen, wie oft die gerade aufgelaufene
IP ($ip) schon in den letzten 24 Stunden eingetragen ist.
SELECT COUNT(*) FROM zeiten
WHERE ip = '$ip' AND time > (NOW() - INTERVAL '1' DAY)
Dann die Anzahl der Einträge auswerten
wenn 0 bzw. nicht definiert dann Neueintrag
INSERT INTO zeiten VALUES ('$ip',NOW())
wenn > 0 bzw. definiert dann irgendwas oder eben keine Aktion
Falls ich Dein Problem falsch verstanden habe, müsstest Du es eventuell
noch mal erläutern.
Gruß Jürgen
Re: Datum in MySQL
am 12.04.2006 14:44:30 von Thomas Rachel
Andreas Kretschmer wrote:
>> Und dann muss die Sperre natürlich erneuert werden. Ich schätze, das
>> geht dann mit
>> UPDATE zeiten SET time=CURDATE() WHERE ip = '$ip' LIMIT 1;
>
> Ich weià nicht, was Du rauchst, aber ein LIMIT begrenzt die
> Ergebnismenge, nicht die Menge beim Update.
Auch UPDATE kennt einen LIMIT-Parameter. Der hier allerdings von eher
bescheidenem Sinn ist, wenn man von einem UNIQUE-Key ausgeht, den ich jetzt
angesichts des auto_increment mal voraussetze, da es ohne UNIQUE kein
auto_increment gibt.
Thomas
Re: Datum in MySQL
am 12.04.2006 14:45:57 von Carsten Wiedmann
Marian Ritter schrieb:
> Gibt es für die Spalte ip (s.u.) einen sinnigeren Datentyp als bigint
> mit 12 Zeichen?
"INT UNSIGNED" und PHP kennt ip2long()/long2ip().
Gruß
Carsten
Re: Datum in MySQL
am 12.04.2006 14:46:41 von Frank Schenk
Andreas Kretschmer wrote:
> begin Marian Ritter schrieb:
....
>>Und dann muss die Sperre natürlich erneuert werden. Ich schätze, das
>>geht dann mit
>> UPDATE zeiten SET time=CURDATE() WHERE ip = '$ip' LIMIT 1;
>
>
> Ich weiß nicht, was Du rauchst, aber ein LIMIT begrenzt die
> Ergebnismenge, nicht die Menge beim Update.
http://dev.mysql.com/doc/refman/5.0/en/update.html kennst du?
Gruß, Frank
Re: Datum in MySQL
am 12.04.2006 15:03:04 von Andreas Kretschmer
Andreas
--
Andreas Kretschmer
Linux - weil ich es mir wert bin!
GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net
Deutsche PostgreSQL User Group: http://pgug.de
Re: Datum in MySQL
am 12.04.2006 15:04:45 von Christian Kirsch
Frank Schenk schrieb:
> Andreas Kretschmer wrote:
>> begin Marian Ritter schrieb:
> ...
>>> Und dann muss die Sperre natürlich erneuert werden. Ich schätze, das
>>> geht dann mit
>>> UPDATE zeiten SET time=CURDATE() WHERE ip = '$ip' LIMIT 1;
>>
>> Ich weiß nicht, was Du rauchst, aber ein LIMIT begrenzt die
>> Ergebnismenge, nicht die Menge beim Update.
>
> http://dev.mysql.com/doc/refman/5.0/en/update.html kennst du?
>
Ja, ich liebe RTFM auch. Aber noch mehr mag ich ja Brain 1.0.
In dem von Dir Verlinkten steht:
The LIMIT clause places a limit on the number of rows that can be updated.
MaW: Der OP begrenzt in seinem oben zitierten Statement die Menge der
zu aktualisierenden Zeilen auf 1 (uno, one, une etc.). Allem anderen
zufolge gibt es jedoch ohne nur genau EINE (uno, one, une, 1, etc.)
Zeile, auf die WHERE ip='$ip' zutrifft (ich frage jetzt mal nicht,
warum der OP ein Integer quoten möchte). Was also SOLL eine
Beschränkung des UPDATE per LIMIT auf eine Zeile, wenn schon das WHERE
genau eine Zeile aussortiert?
Und was sollte ein LIMIT überhaupt, wenn man kein ORDER BY dazu
schreibt, der Server also quasi zufällig eine Zeile aus der
Ergebnismenge auswählt, um sie zu ändern?
Re: Datum in MySQL
am 12.04.2006 15:51:46 von Frank Schenk
Christian Kirsch wrote:
>
> Ja, ich liebe RTFM auch. Aber noch mehr mag ich ja Brain 1.0.
>
> In dem von Dir Verlinkten steht:
>
> The LIMIT clause places a limit on the number of rows that can be updated.
>
> MaW: Der OP begrenzt in seinem oben zitierten Statement die Menge der
> zu aktualisierenden Zeilen auf 1 (uno, one, une etc.). Allem anderen
> zufolge gibt es jedoch ohne nur genau EINE (uno, one, une, 1, etc.)
> Zeile, auf die WHERE ip='$ip' zutrifft (ich frage jetzt mal nicht,
> warum der OP ein Integer quoten möchte). Was also SOLL eine
> Beschränkung des UPDATE per LIMIT auf eine Zeile, wenn schon das WHERE
> genau eine Zeile aussortiert?
>
> Und was sollte ein LIMIT überhaupt, wenn man kein ORDER BY dazu
> schreibt, der Server also quasi zufällig eine Zeile aus der
> Ergebnismenge auswählt, um sie zu ändern?
Mein Post ging nicht an den OP. Ich wollte nur zeigen, daß LIMIT
durchaus die Menge der geänderten Datensätze begrenzen kann. Ob und wie
es sinnvoll ist stand grad nicht zur Diskussion.
gruß, Frank
Re: Datum in MySQL
am 13.04.2006 17:04:20 von Marian Ritter
Ich danke euch allen für eure Antworten.
Habe jetzt einige Möglichkeiten davon übernommen. Die vielen
komischen Sachen vom Anfang kamen davon, dass ich mich erstmal wild
durch das MySQL-Handbuch gewühlt habe bevor ich hier was schrieb -
fand das besser als ne Frage "Wie kann man prüfen wie alt ein Eintrag
ist" oder sowas (und ihr sicher auch), ne Komplettübersicht daraus
natürlich nicht bekommen, sonst hätte ich hier wohl auch nicht
nachgefragt.
Ich komme jetzt ganz ohne ein SELECT-Statement aus, das hätte ich eh
nicht gebraucht, und LIMITs sind tatsächlich grober Dummfug wenn man
die Spalte ip Unique hat (oder heißt es "wenn die Spalte IP Unique
ist", "wenn die Spalte die Eigenschaft hat, Unique zu sein"?).
Ich habe seit gestern viel gelernt also dankeschön an
Andreas, Helmut, Jürgen und Carsten und besonders an Thomas :)
Winkewinke und frohe Ostern.
Marian
Re: Datum in MySQL
am 13.04.2006 21:01:19 von Dominik Echterbruch
Hallo,
ich habe mir nicht den gesamten Thread durchgelesen, aber noch zwei
Anmerkungen hierzu. Deshalb bitte ich um Nachsicht, falls das schon
gesagt wurde.
>>Tabelle "zeiten":
>>ip bigint(12) NOT NULL auto_increment
>>
>>Gibt es für die Spalte ip (s.u.) einen sinnigeren Datentyp als bigint
>>mit 12 Zeichen?
Die 12 wird ausschließlich bei der Darstellung der Werte berücksichtigt.
Bei einem zusätzlichen ZEROFILL in der Spaltendefinition würde die Zahl
nach vorne auf genau 12 Stellen aufgefüllt. Das ist für deutsche
Postleitzahlen ganz nett, aber sonst habe ich das noch nicht wirklich
oft gebraucht.
Die 12 beeinflusst also weder die interne Speicherung (bigint(12) belegt
also genauso viel Platz, wie ein bigint(1) oder ein bigint ohne alles),
noch wird der Wert beim Schreiben (oder Lesen) aufd 12 Zeichen begrenzt.
> Die Anzahl der Zeichen ist zunächst mal nicht relevant, sofern Du die IP als
> 32bit-Wert verarbeitest. Dann brauchst Du lediglich einen int unsigned, der
> ja von 0..2^32 geht, also genau den Wertebereich einer IP(4) abdeckt.
Es gibt hierfür in MySQL auch zwei sehr praktische Funktionen:
- INET_ATON() baut eine IP wie 127.0.0.1 in einen numerischen Wert um,
der wie oben beschrieben wunderbar in ein in unsigned reinpasst.
- INET_NTOA() nimmt einen numerischen Wert entgegen und baut daraus eine
IP-Adresse in gewohnter Schreibweise.
Einer der ganz großen Vorteile von INET_ATON() ist, daß immer eindeutige
numerische Werte entstehen. Es ist völlig wurscht, ob du 127.000.000.001
übergibst (was ja durchaus eine korrekte Schreibweise ist) oder
127.0.0.1. Das heißt, daß die Werte in deinem int unsigned garantiert
immer auf alle IP-Schreibweisen matchen.
Umgekehrt liefert dir INET_NTOA() immer die Variante ohne führende
Nullen (also 127.0.0.1).
Grüße,
Dominik
Re: Datum in MySQL
am 13.04.2006 21:18:13 von Dominik Echterbruch
Carsten Wiedmann wrote:
>
>> Gibt es für die Spalte ip (s.u.) einen sinnigeren Datentyp als bigint
>> mit 12 Zeichen?
>
> "INT UNSIGNED" und PHP kennt ip2long()/long2ip().
Wozu PHP damit behelligen und sich auch noch mit den Problemen des
Datentyps dort rumschlagen? MySQL erledigt das on-the-fly mit.
INET_ATON() und INET NTOA() sei Dank.
Gruß,
Dominik
Re: Datum in MySQL
am 13.04.2006 21:32:32 von Thomas Rachel
Dominik Echterbruch wrote:
> Es gibt hierfür in MySQL auch zwei sehr praktische Funktionen:
> - INET_ATON() baut eine IP wie 127.0.0.1 in einen numerischen Wert um,
> der wie oben beschrieben wunderbar in ein in unsigned reinpasst.
> - INET_NTOA() nimmt einen numerischen Wert entgegen und baut daraus
> eine IP-Adresse in gewohnter Schreibweise.
Oh, danke! Die kannte ich ja noch gar nicht :-)
Thomas
--
> Es gibt Perl-Entwickler, die behaupten auch in Perl könne man echtes
> OOP praktizieren.
Und mit einem Kalligraphiepinsel kann man Wände streichen.
(Jan Sauerwein und Hauke Ingmar in de.comp.lang.java)
Re: Datum in MySQL
am 14.04.2006 17:45:13 von Marian Ritter
Danke für INET_ATON() und INET_NTOA() aber die helfen mir in dem Falle
nicht.
Und das mit bigint wusste ich bisher auch noch nicht. Ich dachte
bisher, wenn man die Länge irgendwie beschränkt, auch der Platz, der
verwendet wird, kleiner ist...
Ist das allgemein falsch oder nur bei bigint?
Re: Datum in MySQL
am 15.04.2006 22:26:10 von Dominik Echterbruch
Marian Ritter wrote:
> Danke für INET_ATON() und INET_NTOA() aber die helfen mir in dem Falle
> nicht.
Warum? Du möchtest IPs speichern und wissen, ob eine IP bereits
eingetragen ist. Dann ist es doch geradezu ideal, wenn man ganz exakt
weiß, daß die IP da ist. Mit einem 12-stelligen BIGINT stelle ich mir
das schwierig vor. Jedenfalls, wenn man sonstige Programmlogik außen vor
läßt.
> Und das mit bigint wusste ich bisher auch noch nicht. Ich dachte
> bisher, wenn man die Länge irgendwie beschränkt, auch der Platz, der
> verwendet wird, kleiner ist...
> Ist das allgemein falsch oder nur bei bigint?
Das gilt allgemein für alle numerischen Datentypen. In gewissem Umfang
sogar für die Alphanumerischen Typen mit variabler Länge (z.B. VARCHAR).
Aber dazu befragst du am Besten das Handbuch.
Grüße,
Dominik
--
MonstersGame - Die Schlacht zwischen Vampiren und Werwölfen
http://spielwelt6.monstersgame.net/?ac=vid&vid=3018786
Re: Datum in MySQL
am 17.04.2006 12:49:26 von Marian Ritter
INET_ATON() hat bei mir irgendwie keine ordentlichen IPs gespeichert -
außerdem is das ja gar kein Problem - ich kann die IPs ja auch schon
ohne Punkte an SQL senden - in ein INT Unsigned - kA was für vorteile
das hat aber es klingt wenigstens nicht nach BIG :)
Österliche Grüße
Marian
Re: Datum in MySQL
am 17.04.2006 13:36:01 von Kai Ruhnau
Marian Ritter wrote:
> INET_ATON() hat bei mir irgendwie keine ordentlichen IPs gespeichert -
Was bedeutet "keine ordentlichen IPs"? Bei mir wandelt MySQL ganz sauber
ankommende IP-Adresse-Strings in ihre 32-Bit Darstellung um, die ich
ebenso sauber in einem INT UNSIGNED unterbringen kann. Ebenso sauber
funktioniert eine anschließende Ausgabe mittels INET_NTOA, die mir die
32-Bit Ganzzahldarstellung der IP-Adresse wieder die
String-Repräsentation umwandelt.
Vielleicht hast du auch einfach nur ein grundlegendes
Verständnisproblem, was eine IP-Adresse eigentlich ist?
> außerdem is das ja gar kein Problem - ich kann die IPs ja auch schon
> ohne Punkte an SQL senden - in ein INT Unsigned - kA was für vorteile
> das hat aber es klingt wenigstens nicht nach BIG :)
Du entledigst die Stringrepräsentation einer IP-Adresse ihrer Punkte und
speicherst das Ergebnis umgewandelt als 32-Bit Integer? Das ist mehr als
unglücklich, denn
a) reichen 32 Bit dafür nicht aus:
253.142.189.212 ist größer als 4.294.967.295(=2^32-1).
b) bekommst du aus einer Zahl nicht mehr die IP-Adresse
War es jetzt 192.168.10.11 oder 192.168.101.1?
Benutze INET_ATON und INET_NTOA, die sind dafür da, genau das zu tun,
was du brauchts.
Grüße
Kai
--
This signature is left as an exercise for the reader.
Re: Datum in MySQL
am 17.04.2006 15:00:22 von Marian Ritter
> Benutze INET_ATON und INET_NTOA, die sind dafür da, genau das zu
> tun, was du brauchts.
Okay, nach dieser Darstellung hab ich das jetzt auch verstanden.
Ich danke dir und schreibe das entsprechend um
Marian