2016-06-29 25 views
4

So hatte ich einen Test mit einer großen Datenbanktabelle von Benutzern, die knapp über 1 Million Datenzeilen hat, versucht, mit einer Art "Benutzerrang" zu kommen, aber es scheint sehr langsam im Vergleich zu jeder anderen Art und Weise nutze diese Daten, also habe ich mich gefragt, ob ich es falsch mache oder nicht. Ich ziehe jede Reihe von Daten mit den zwei Spalten id und points, Gruppierung nach Punkten, so dass Menschen mit den gleichen Punkten werden die gleichen Rang und dann in absteigender Reihenfolge Reihenfolge.Was ist der schnellste Weg, um eine Datenzeile zu erfassen?

Hier ist ein schneller Wurf zusammen habe ich es zu testen:

<?php 
session_start(); 
$rank = 0; 
$query = $conn->prepare("SELECT id, points FROM users GROUP BY points ORDER BY points DESC"); 
$query->execute(); 
foreach($query as $result){ 
    $rank += 1; 
    if($result['id'] == $_SESSION['myid']){ 
     echo '' . $_SESSION['myuser'] . ' is rank ' . number_format($rank) . ' globally.'; 
    } 
} 

points und id indiziert sind

Dies schien ganz langsam zu laden, nicht ‚wirklich‘ langsam, aber langsamer als würde ich wie so entschied ich mich, mit ihm einige Tests zu tun, und überprüfen, wie lange das Skript mit dem folgenden Verfahren auszuführen fand:

<?php 
$starttime = microtime(true); 
session_start(); 
$rank = 0; 
$query = $conn->prepare("SELECT id, points FROM users GROUP BY points ORDER BY points DESC"); 
$query->execute(); 
foreach($query as $result){ 
    $rank += 1; 
    if($result['id'] == $_SESSION['myid']){ 
     echo '' . $_SESSION['myuser'] . ' is rank ' . number_format($rank) . ' globally.'; 
    } 
} 
$endtime = microtime(true); 
$duration = $endtime - $starttime; 
echo '<br /><br />This page took ' . $duration . ' seconds to load.'; 

Dieser Mittelwert lag bei 1,9468239237 Sekunden zum Laden basierend auf 1000 Lasten.

Ich fügte dann eine break; in die Schleife, wenn es Ihren Rang findet denken vielleicht würde es die Bearbeitungszeit verkürzen, aber ohne Erfolg.

Also meine Frage ist, gibt es einen besseren Weg, berechnen Sie so etwas?

+1

Haben Sie eine auf Ihre Anfrage getan ERKLÄREN, um zu sehen, ob der Index tatsächlich verwendet wird? –

+3

sollten Sie 'GROUP BY Punkte' nicht machen, wenn Sie alle' id' später vergleichen wollen 'if ($ result [' id '] == $ _SESSION [' myid ']) {'Ihre Abfrage liefert eine zufällige Antwort 'id' http://sqlfiddle.com/#!9/56bc9d/1 – Alex

+0

@ chris85 Aber das würde nur eine Zeile bekommen ... Es muss Ihre Zahl basierend auf JEDEM Punkte berechnen, sonst würde es immer zurück, dass Sie sind Platz # 1. – SmurfTheSmurf

Antwort

3

http://sqlfiddle.com/#!9/05189/3

SELECT t.* 
FROM users u 
INNER JOIN (
    SELECT id, points, IF(@rank IS NULL,@rank:=1,@rank:[email protected]+1) rank 
    FROM users 
    ORDER BY points DESC) t 
ON u.id = t.id 
WHERE u.id = 3; # <- 3 is id you are looking for 
+0

Dies ist wie immer Rang 1, egal was die ID ist. – SmurfTheSmurf

+0

was? Hast du meine Geige überprüft? – Alex

+0

Dies scheint die Benutzer nicht zu gruppieren. –

1

könnten Sie versuchen, Ihre Anfrage zu dieser Änderung:

SELECT id, Name, 1+(SELECT count(*) from users u1 WHERE u1.Points > u1.Points) as Rank, Points 
FROM users u WHERE u.id = your_id; 
1

Ich möchte so etwas wie dieses

SELECT users.id, ranks.rank 
FROM users 
INNER JOIN (
    SELECT points, ROW_NUMBER() AS rank 
    FROM users 
    GROUP BY points 
    ORDER BY points DESC 
) ranks ON users.points = ranks.points 
WHERE users.id = ? 

Wo Sie bereiten die Abfrage mit Ihrem Benutzer-ID versuchen.

Bearbeiten: Es scheint, dass MySQL keine ROW_NUMBER() -Funktion hat. Dies sollte stattdessen arbeiten:

SELECT users.id, ranks.rank 
FROM users 
INNER JOIN (
    SELECT t1.points, @rank := @rank + 1 AS rank 
    FROM (
     SELECT points 
     FROM users 
     GROUP BY points 
     ORDER BY points DESC 
    ) t1, (SELECT @rank := 0) t2 
) ranks ON users.points = ranks.points 
WHERE users.id = ? 
Verwandte Themen