MySQL- RAND() Perfomance
Gerd H.
- datenbank
0 Andreas Görtz0 Erik
Hallo Forum,
ich hatte bei meinem Script ein wenig Performanceproblem, da ich mittlerweile immer mehr Besuicher auf meiner Site habe. Dabei geht es speziell um eine Abfrage, bei der 2 zufällige Zeilen aus der DB geleesen werden sollten.
Mit RAND() gibt es bei vielen DB-Einträgen Performanceprobleme.
So war die Lösung bisher:
$sql = '
SELECT id, zelle
FROM tabelle
WHERE id NOT IN(ADMIN-ID, ADMIN2-ID, eigeneID) AND zelle IS NOT NULL AND bedingung1=1 AND bedingung2=3
ORDER BY RAND()
LIMIT 2';
$result = mysql_query($sql);
$max = mysql_num_rows($result);
for($i=0;$i<$max;$i++) {
$row = mysql_fetch_object($result);
switch($i) {
case 0:
$userid1 = $row->id;
$zelle1 = $row->zelle;
break;
case 1:
$userid2 = $row->id;
$zelle2 = $row->zelle;
break;
}
}
Meine neue Lösung:
//Maximale Zahl aus der Tabelle1
$res_max = mysql_query("SELECT MAX(id) AS max_zahl FROM tabelle");
$row = mysql_fetch_object($res_max);
$max_zahl = $row->max_zahl;
//User1
do {
$user_id1 = rand(1,$max_zahl);
$result = mysql_query("SELECT zelle FROM tabelle WHERE id=" . $user_id1 . " AND bedingung1='1' AND bedingung2=3 LIMIT 1");
$row = mysql_fetch_object($result);
$zelle1 = $row->zelle;
} while($zelle1=='');
//User2
do {
$user_id2 = rand(1,$max_zahl);
$result = mysql_query("SELECT zelle FROM tabelle WHERE id=" . $user_id2 . " AND bedingung1='1' AND bedingung2=3 LIMIT 1");
$row = mysql_fetch_object($result);
$zelle2 = $row->zelle;
} while($zelle2=='');
Meint ihr das wird was bringen auf Dauer? Das Problem ist halt, dass IDs in der Datenbank fehlen, da sich Mitglieder auch bereits gelöscht haben und Lücken entstehen. Habt ihr andere Vorschläge? Indizes eventuell auch?
Sollte ich vielleicht beides in eine do...while Schleife packen und dann innerhalb dieser prüfen ob zelle bei beiden gesetzt ist. (Zelle ist übrigens ein Link aufs Foto des Profils)
Hi Gerd,
[...]da ich mittlerweile immer mehr Besuicher auf meiner Site habe.
was verstehst du unter "mehr Besucher"?
Mit RAND() gibt es bei vielen DB-Einträgen Performanceprobleme.
was verstehst du unter "vielen DB-Einträgen"?
Meint ihr das wird was bringen auf Dauer? Das Problem ist halt, dass IDs in der Datenbank fehlen,
ich halte da nicht sehr viel von, weil einfach sehr viele unnötige (in diesem Zusammenhang denke ich, dass jede Anzahl an, die über 1 hinaus geht, überflüssig ist) Anfragen an die DB gestellt werden können. Wenn sogar noch bedingung1 und bedingung2 zu einer zufällig ausgewählten ID passen müssen...
Habt ihr andere Vorschläge? Indizes eventuell auch?
du könntest die Ergebnisse per Cronjob in einem ereignislosen Zeitraum (z.B. irgendwann nachts um 3 Uhr oder so) vorbereiten, in einer eigenen Tabelle, im Dateisystem, whatever. Dann müsstest du die aufwendigen Queries (also mit ORDER BY RAND()) nur noch ausführen, wenn die vorbereiteten Ergebnisse mal ausgehen...
Gruß,
Andreas.
Hallo,
Indices sollten auf jeden Fall helfen können.
Allerdings sollen Indices mit Spalten, in denen NULL vorkommen darf, unter Umständen nicht viel bringen.
Schreib mal "explain" [0] vor "select" (also "explain select ..."), am besten in einem SQL-Tool (z.B. phpmyadmin) deiner Wahl. Das dürfte dir helfen.
Schau dir mal die Performance mit einem Benchmark-Skript an. Ich bezweifle, dass es schneller ist, drei Abfragen zu starten, als einmal RAND() zu benutzen. Bei PEAR [1] gibts einen Benchmark [2], oder du kannst auch einfach die php-Funktion microtime [3] ansehen.
Übrigens würde ich deinen Code etwas anders schreiben.
Nimm mysql_num_rows raus, das schont Resourcen. Wenn du ohnehin weißt, dass du nur 2 Antworten hast, ist es schneller, wenn du einen Zähler in php mitlaufen lässt.
Eine andere Möglichkeit ist, statt "mysql_fetch_object" "mysql_fetch_row" zu verwenden. Das sollte auch schneller sein.
Grüße
Erik
[0] http://dev.mysql.com/doc/refman/5.1/de/explain.html
[1] pear.php.net
[2] http://pear.php.net/package/Benchmark
[3] http://de2.php.net/microtime