sql >> Database >  >> RDS >> Mysql

Waardeverschillen tussen twee records berekenen in Eloquent

Dan heb ik een verrassing voor je - Hier is een kleine prestatietest:

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 is een tabel met slechts één int-kolom en 1 miljoen rijen.

En het resultaat is:

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

Dus de "kleine prestatie-impact van welsprekend" is:

  • Bijna 20 keer langzamer dan het gebruik van gewone PDO en stdClass bij het ophalen van gegevens uit de database.
  • Minstens 100 keer langzamer dan stdClass bij het lezen van eigenschappen/attributen in een lus.

Dus als je de prestaties wilt verbeteren, schakel dan over naar gewone PDO als je met grote hoeveelheden gegevens te maken hebt of gebruik in ieder geval de standaard Builder.

Nu kun je nog steeds proberen om het werk in MySQL te doen, maar de vereiste om Eloquent te gebruiken zou niet logisch zijn.

U kunt echter een gemengde versie proberen - Gebruik Eloquent om de query te bouwen, maar converteer deze naar Database\Query\Builder met getQuery() .

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

Maar ik zou altijd vermijden om sessievariabelen op deze manier in applicatiecode te gebruiken, omdat ik heb gezien dat veel van dergelijke oplossingen verkeerde/onverwachte resultaten opleveren na een versie-upgrade.

Nog steeds niet overtuigd? Hier zijn enkele andere tests:

Sessievariabelen gebruiken in een welsprekende query die is geconverteerd naar 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-oplossing met geconverteerde welsprekende zoekopdracht:

$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-oplossing met duidelijke PDO en 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-oplossing met duidelijke PDO en associatieve 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

Uw voorkeursoplossing is de langzaamste en de minst betrouwbare. Het antwoord op uw vraag is dus een slechte oplossing voor uw probleem.




  1. Opgeslagen procedure in Oracle-voorbeeld met IN OUT-parameter

  2. Beestje? #1146 - Tabel 'xxx.xxxxx' bestaat niet

  3. Wat is het standaard MySQL JOIN-gedrag, INNER of OUTER?

  4. SQL - Vind ontbrekende int-waarden in meestal geordende opeenvolgende reeksen