Il momento di lavorare su un sistema che fornisce statistiche basate su alcuni dati raccolti dal database è arrivato nella mia azienda.
Come si raccolgono in modo efficiente le statistiche da un database in modo tale da non aggiungere troppi sovraccarichi nel caricamento di una pagina o troppa complessità nella gestione della cache?
Attualmente, le statistiche vengono calcolate in fase di esecuzione, nessun dato viene salvato o memorizzato nella cache, il problema è che quando aggiungi nuove statistiche, e anche quelle che vengono calcolate in fase di esecuzione, raggiungerò un punto in cui il sito web sta per essere realisticamente lento, il che non è accettabile.
L'unica idea che mi è venuta in mente per risolvere questo problema è la memorizzazione nella cache dei dati che hanno filtri di data oltre il giorno in cui sono calcolati.
Ad esempio, supponiamo che mi piacerebbe sapere se un utente ha visitato una pagina specifica tra il 2017-01-01 e il 2017-01-08. Da oggi è il 2017-01-12, è implicito che questo risultato non potrebbe mai cambiare in futuro, poiché le date selezionate sono vecchie.
Questo è un esempio di come calcolo le statistiche in Laravel (4.x):
namespace App\Composers\Users;
use Illuminate\Support\Collection;
use User;
class ShowComposer
{
public function compose($view)
{
$viewData = $view->getData();
$view->with([
'sellings' => $this->getSellingStatistics($viewData['user'])
]);
}
public function getSellingStatistics(User $user)
{
$sellings = [];
$getSellingsOf = function (User $user, $months) {
$startOfMonth = \Carbon::now()->subMonths($months)->startOfMonth();
$endOfMonth = \Carbon::now()->subMonths($months)->endOfMonth();
return $user
->mavs()
->whereHas('buyerProposal', function ($proposal) use ($startOfMonth, $endOfMonth) {
$proposal->whereBetween('sold_at', [
$startOfMonth, $endOfMonth
]);
})
->count();
};
$sellings['best'] = value(function () use ($getSellingsOf) {
$months = [];
for ($month = 0; $month < 12; $month++) {
$startOfMonth = \Carbon::now()->subMonths($month)->startOfMonth();
$endOfMonth = \Carbon::now()->subMonths($month)->endOfMonth();
$query = <<<SQL
SELECT
id, (SELECT COUNT(*)
FROM 'mav'
INNER JOIN 'mav_proposals' ON 'mav'.'mav_proposal_id' = 'mav_proposals'.'id'
WHERE sold_at BETWEEN ? AND ?
AND mav.user_id = users.id) AS sellings
FROM users
ORDER BY sellings DESC
LIMIT 1
SQL;
$response = \DB::select($query, [
$startOfMonth->toDateTimeString(),
$endOfMonth->toDateTimeString()
]);
$user = User::find($response[0]->id);
$months[] = $getSellingsOf($user, $month);
}
$months = array_reverse($months);
return $months;
});
$sellings['personal'] = value(function () use ($user, $getSellingsOf) {
$months = [];
for ($month = 0; $month < 12; $month++) {
$months[] = $getSellingsOf($user, $month);
}
$months = array_reverse($months);
return $months;
});
$sellings['global'] = value(function () use ($user) {
$months = [];
for ($month = 0; $month < 12; $month++) {
$startOfMonth = \Carbon::now()->subMonths($month)->startOfMonth();
$endOfMonth = \Carbon::now()->subMonths($month)->endOfMonth();
$companySoldMavs = \App\Models\MAV::whereHas('buyerProposal',
function ($proposal) use ($startOfMonth, $endOfMonth) {
$proposal->whereBetween('sold_at', [
$startOfMonth, $endOfMonth
]);
})->count();
$usersWithSoldMavs = \User::whereHas('mavs', function ($mav) use ($startOfMonth, $endOfMonth) {
$mav->whereHas('buyerProposal', function ($proposal) use ($startOfMonth, $endOfMonth) {
$proposal->whereBetween('sold_at', [
$startOfMonth, $endOfMonth
]);
});
})->count();
$months[] = ($usersWithSoldMavs > 0)
? round($companySoldMavs / $usersWithSoldMavs)
: 0;
}
$months = array_reverse($months);
return $months;
});
return $sellings;
}
}
Ora, ecco le uniche due opzioni a cui ho pensato:
- Calcola le statistiche ogni 24 ore e salvale in un database.
- Memorizza i dati sulla cache in base ai parametri utilizzati per raccogliere le statistiche.
La prima opzione è piuttosto complicata e richiede molto tempo per essere sviluppata in modo propizio.
La seconda opzione potrebbe essere interessante, tuttavia temo che la cache possa darmi mal di testa prima o poi.
C'è un altro modo per farlo in modo efficiente? In che modo le aziende si muovono verso il data mining? In questi casi le lingue come R vengono sempre utilizzate, oppure PHP può essere corretto se usato correttamente?
Per me è un nuovo mondo, per favore sii gentile.