Non sono un ottimo programmatore di php (vengo da C++). Sto usando php solo per l'inserimento nel database.PhP, MySql - Codice ottimizzazione
Ho un database con il seguente:
UserId (an unique int)
AsyncPointsAverage (float)
AsyncPointsAverageRank (a position based on the value immediately above)
AsyncPointsRecentAverage (float an average for the last 5 tests only)
AsyncPointsRecentAverageRank (a position based on the value immediately above)
Ci sono circa 1000-1500 voci in quella tabella. Ogni mattina e pomeriggio 5 persone effettuano un test che influisce sulla media generale e sulla media recente. (Questo è aggiornato altrove, ma non mostrato qui.) Dopo che viene calcolato per quelle 5 persone, verranno effettuate le classifiche di tutti i 1000-1500, quindi ho scritto il codice qui sotto. È ottimale?
La cosa a cui sono più interessato è che sto facendo un UPDATE MySql circa 1000 volte. È fantastico? Dovrei farlo in un altro modo? (Inoltre, sentitevi liberi di ottimizzare qualsiasi altro codice nella funzione. Come ho detto, io sono da un background C++, quindi non so davvero le sfumature del php.)
// Sorts by array entry 1
function ReRankCompareAverage($a, $b)
{
if($a[1] == $b[1]) return 0;
else return ($a[1] > $b[1] ? 1 : -1);
}
// Sorts by array entry 2
function ReRankCompareAverageRecent($a, $b)
{
if($a[2] == $b[2]) return 0;
else return ($a[2] > $b[2] ? 1 : -1);
}
function ReRank($db)
{
$i = 0, $j = 0;
$usersARR = null;
$stmt = $db->prepare("SELECT UserId, AsyncPointsAverage, AsyncPointsRecentAverage FROM studenttable");
$stmt->execute();
if($stmt && isset($stmt) && $stmt->rowCount() > 0)
{
$i = 0;
while(($row = $stmt->fetch(PDO::FETCH_ASSOC)))
{
$usersARR[$i][0] = intval($row['UserId']);
$usersARR[$i][1] = floatval($row['AsyncPointsAverage']);
$usersARR[$i][2] = floatval($row['AsyncPointsRecentAverage']);
$i++;
}
}
$stmt->closeCursor(); // mysql_free_result equivalent
// The first pass of $j == 3 does the ranking by Average, filling position $usersARR[][3] with that rank
// The second pass of $j == 4 does the ranking by AverageRecent, filling position $usersARR[][4] with that rank
for($j = 3, $j <= 4; $j++)
{
$iCompare = $j == 3 ? 1 : 2;
usort($usersARR, $j == 3 ? "ReRankCompareAverage" : "ReRankCompareAverageLast");
$count = count($usersARR);
if($count > 0)
{
// Start it off, with the person with the highest average is rank 1
$usersARR[$count - 1][$j] = 1; // Position $j is filled with the rank
// Now loop starting from the second one down
for($i = $count - 2, $rank = 1; $i >= 0; $i--)
{
// Only change the rank if the next one down is strictly lower than the one above, otherwise will share the same rank
if($usersARR[$i][$iCompare] < $usersARR[$i+1][$iCompare]) $rank = $count - $i; // Otherwise keep the same rank, because they are equal
$usersARR[$count - 1][$j] = $rank;
}
}
}
// Now $usersARR is filled with the correct rankings, and they are asscoiated with $UserId
// Now we must put all of these rankings into the database
$count = count($usersARR);
for($i = 0; $i < $count; $i++)
{
$stmt = $db->prepare("UPDATE studenttable SET AsyncPointsAverageRank=:AsyncPointsAverageRank, AsyncPointsRecentAverageRank=:AsyncPointsRecentAverageRank "
. "WHERE UserId=:UserId");
$stmt->execute(array(':AsyncPointsAverageRank' => $usersARR[$i][3],
':AsyncPointsRecentAverageRank' => $usersARR[$i][4],
':UserId' => $usersARR[$i][0]));
}
}
È possibile utilizzare la transazione e fare tutti gli aggiornamenti. Non sono sicuro che MyISAM supporti la transazione ma InnoDb lo fa. – frz3993
Il tuo codice è sicuro per l'iniezione e l'esecuzione di migliaia di piccole query di aggiornamento non è un problema per nessun server di database moderno. Direi che stai bene. Se desideri ulteriore ottimizzazione, sei sul sito StackExchange sbagliato. :) –
Non ha esaminato i dettagli del tuo problema poiché il modo in cui lo stai facendo sembra soddisfacente ma, solo per "scopo di discussione", se vuoi evitare un migliaio di aggiornamenti nel tuo db, dovresti forse considerare un altro "ranking" "sistema, come una colonna nella tabella che si riferisce al" precedente "o al" prossimo elemento ". In questo modo, l'aggiornamento del tuo ranking avrà effetto solo sugli oggetti "riclassificati" e sui vicini ... – Julo0sS