Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Obliczanie różnic wartości między dwoma rekordami w Eloquent

W takim razie mam dla Ciebie niespodziankę - oto mały test wydajności:

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 to tabela z tylko jedną kolumną int i 1 mln wierszy.

Wynik:

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

Tak więc „mały wpływ na wydajność z elokwentnego” to:

  • Prawie 20 razy wolniej niż przy użyciu zwykłego PDO i stdClass podczas pobierania danych z bazy danych.
  • Co najmniej 100 razy wolniej niż stdClass podczas czytania właściwości/atrybutów w pętli.

Więc jeśli chcesz poprawić wydajność, przełącz się na zwykły PDO, gdy masz do czynienia z dużymi ilościami danych lub przynajmniej użyj domyślnego kreatora.

Teraz nadal możesz spróbować wykonać tę pracę w MySQL, ale wymóg używania Eloquent nie miałby sensu.

Możesz jednak wypróbować wersję mieszaną — użyj Eloquent, aby zbudować zapytanie, ale przekonwertuj je na Database\Query\Builder z getQuery() .

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

Ale zawsze unikałbym używania zmiennych sesji w ten sposób w kodzie aplikacji, ponieważ widziałem, jak wiele takich rozwiązań zwraca złe/nieoczekiwane wyniki po aktualizacji wersji.

Nadal nie jesteś przekonany? Oto kilka innych testów:

Używanie zmiennych sesji w elokwentnym zapytaniu przekonwertowanym na 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

Rozwiązanie PHP wykorzystujące przekonwertowane zapytanie Eloquent:

$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

Rozwiązanie PHP ze zwykłym PDO i 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

Rozwiązanie PHP ze zwykłym PDO i tablicami asocjacyjnymi:

$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

Twoje preferowane rozwiązanie jest najwolniejsze i najmniej niezawodne. Tak więc odpowiedź na twoje pytanie jest złym rozwiązaniem twojego problemu.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Importowanie bazy danych MS ACCESS do mySql?

  2. Jak kpić z MySQL (bez ORM) w Node.js?

  3. Jak połączyć wyniki dwóch zapytań z porządkowaniem?

  4. Jaka jest różnica między MySQL i MySQL2 biorąc pod uwagę NodeJS?

  5. Zapobiegaj wprowadzaniu zduplikowanych danych do bazy danych mysql