sql >> Database teknologi >  >> RDS >> Mysql

Beregning af værdiforskelle mellem to poster i Eloquent

Så har jeg en overraskelse til dig - Her er en lille præstationstest:

class Seq extends Eloquent {
    protected $table = 'helper.seq';
    protected $primaryKey = 'i';
}

Route::get('/loop', function () {
    $limit = 10000;

    $st = microtime(true);
    $data = Seq::orderBy('i')->take($limit)->get();
    var_dump(microtime(true) - $st);

    $st = microtime(true);
    foreach ($data as $row) {
        $row->i;
    }
    var_dump(microtime(true) - $st);

    $pdo = DB::getPdo();
    $st = microtime(true);
    $data2 = $pdo
        ->query("select * from helper.seq order by i limit $limit")
        ->fetchAll(PDO::FETCH_OBJ);
    var_dump(microtime(true) - $st);

    $st = microtime(true);
    foreach ($data2 as $k => $row) {
        if ($k == 0) {
            $row->diff = 0;
        } else {
            $row->diff = $row->i - $data2[$k-1]->i;
        }
    }
    var_dump(microtime(true) - $st);
});

helper.seq er en tabel med kun én int kolonne og 1M rækker.

Og resultatet er:

0.779045s <- Fetch from DB with Eloquent

1.022058s <- Read Eloquent data (Only one column and do nothing with it)

0.020002s <- Fetch from DB with PDO

0.009999s <- Calculate all diffs in a loop

Så den "lille præstationspåvirkning fra veltalende" er:

  • Næsten 20 gange langsommere end at bruge almindelig PDO og stdClass når data hentes fra databasen.
  • Mindst 100 gange langsommere end stdClass ved læsning af egenskaber/attributter i en loop.

Så hvis du vil forbedre ydeevnen, skal du skifte til almindelig PDO, når du har at gøre med store mængder data eller i det mindste bruge standard Builder.

Nu kan du stadig prøve at udføre jobbet i MySQL, men kravet om at bruge Eloquent ville ikke give mening.

Du kan dog prøve en blandet version - Brug Eloquent til at bygge forespørgslen, men konverter den til Database\Query\Builder med getQuery() .

$fooBars = FooBar::where('type', 'FOO')->orderBy('id')
    ->getQuery()
    ->select(['*', DB::raw('coalesce(`value` - @last, 0)'), DB::raw('@last := `value`')])
    ->get();

Men jeg ville altid undgå at bruge sessionsvariabler på denne måde i applikationskode, fordi jeg har set mange af sådanne løsninger returnere forkerte/uventede resultater efter en versionsopgradering.

Stadig ikke overbevist? Her er nogle andre tests:

Brug af sessionsvariabler i en veltalende forespørgsel konverteret til Database\Query\Builder :

$st = microtime(true);
$data = Seq::getQuery()
    ->select(['*', DB::raw('coalesce(i - @last, 0)'), DB::raw('@last := i')])
    ->orderBy('i')->take($limit)->get();
var_dump(microtime(true) - $st);

// runtime: 0.045002s

PHP-løsning ved hjælp af konverteret veltalende forespørgsel:

$st = microtime(true);
$data2 = Seq::getQuery()->orderBy('i')->take($limit)->get();
foreach ($data2 as $k => $row) {
    if ($k == 0) {
        $row->diff = 0;
    } else {
        $row->diff = $row->i - $data2[$k-1]->i;
    }
}
var_dump(microtime(true) - $st);

// runtime: 0.039002

PHP-løsning med almindelig PDO og stdClass

$st = microtime(true);
$data3 = $pdo
    ->query("select * from helper.seq s1 order by i limit $limit")
    ->fetchAll(PDO::FETCH_OBJ);
foreach ($data3 as $k => $row) {
    if ($k == 0) {
        $row->diff = 0;
    } else {
        $row->diff = $row->i - $data3[$k-1]->i;
    }
}
var_dump(microtime(true) - $st);

// runtime: 0.035001s

PHP-løsning med almindelig PDO og assosiative arrays:

$st = microtime(true);
$data4 = $pdo
    ->query("select * from helper.seq s1 order by i limit $limit")
    ->fetchAll(PDO::FETCH_ASSOC);
foreach ($data4 as $k => $row) {
    if ($k == 0) {
        $row['diff'] = 0;
    } else {
        $row['diff'] = $row['i'] - $data4[$k-1]['i'];
    }
}
var_dump(microtime(true) - $st);

// runtime: 0.027001s

Din foretrukne løsning er den langsomste og mindst pålidelige. Så svaret på dit spørgsmål er en dårlig løsning på dit problem.




  1. Indsæt hvis det ikke findes, ellers returner id i postgresql

  2. Hvordan har man komplet offline funktionalitet i en webapp med PostgreSQL-database?

  3. Oracle-understøttede versioner Matrix

  4. GI 19c RPM Package Manager Database