Mysql
 sql >> база данни >  >> RDS >> Mysql

Изчисляване на стойностни разлики между два записа в Eloquent

Тогава имам изненада за вас - Ето малък тест за производителност:

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 е таблица само с една колона int и 1M реда.

И резултатът е:

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

Така че „малкото въздействие върху производителността от eloquent“ е:

  • Почти 20 пъти по-бавно от използването на обикновен PDO и stdClass при извличане на данни от база данни.
  • Поне 100 пъти по-бавно от stdClass при четене на свойства/атрибути в цикъл.

Така че, ако искате да подобрите производителността, преминете към обикновен PDO, когато работите с големи количества данни или поне използвайте Builder по подразбиране.

Сега все още можете да опитате да свършите работата в MySQL, но изискването за използване на Eloquent няма да има смисъл.

Можете обаче да опитате смесена версия - Използвайте Eloquent за изграждане на заявката, но я преобразувайте в Database\Query\Builder с getQuery() .

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

Но винаги бих избягвал да използвам променливи на сесията по този начин в кода на приложението, защото съм виждал много от подобни решения да връщат грешни/неочаквани резултати след надстройка на версията.

Все още не сте убедени? Ето някои други тестове:

Използване на променливи на сесията в заявка Eloquent, преобразувана в 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 решение, използващо преобразувана заявка 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

PHP решение с обикновен PDO и 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 решение с обикновен PDO и асоциативни масиви:

$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

Предпочитаното от вас решение е най-бавното и най-малко надеждното. Така че отговорът на вашия въпрос е лошо решение на проблема ви.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Свържете се с MySQL, като използвате SSH тунелиране в node-mysql

  2. SQL - Запитване за намиране дали низ съдържа част от стойността в колона

  3. Динамично създаване на колони от данни за редове с помощта на Select in Bigquery

  4. Възможно ли е да се вмъкнат данни в две различни таблици в mysql чрез една заявка за вмъкване php?

  5. Как да съхранявате данни, които съдържат кавички в MySQL