Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Menghitung perbedaan nilai antara dua record di Eloquent

Maka saya punya kejutan untuk Anda - Ini adalah tes kinerja kecil:

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 adalah tabel dengan hanya satu kolom int dan 1 juta baris.

Dan Hasilnya adalah:

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

Jadi "dampak kinerja kecil dari fasih" adalah:

  • Hampir 20 kali lebih lambat daripada menggunakan PDO biasa dan stdClass saat mengambil data dari database.
  • Setidaknya 100 kali lebih lambat dari stdClass saat membaca properti/atribut dalam satu lingkaran.

Jadi, jika Anda ingin meningkatkan kinerja, beralihlah ke PDO biasa saat menangani data dalam jumlah besar atau setidaknya gunakan Builder default.

Sekarang Anda masih dapat mencoba melakukan pekerjaan di MySQL, tetapi persyaratan untuk menggunakan Eloquent tidak masuk akal.

Namun Anda dapat mencoba versi campuran - Gunakan Eloquent untuk membuat kueri, tetapi ubah menjadi Database\Query\Builder dengan getQuery() .

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

Tetapi saya akan selalu menghindari penggunaan variabel sesi dengan cara ini dalam kode aplikasi, karena saya telah melihat banyak solusi seperti itu mengembalikan hasil yang salah/tidak terduga setelah peningkatan versi.

Masih belum yakin? Berikut adalah beberapa tes lainnya:

Menggunakan variabel sesi dalam kueri Eloquent yang dikonversi ke 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

Solusi PHP menggunakan kueri Eloquent yang dikonversi:

$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

Solusi PHP dengan PDO biasa dan 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

Solusi PHP dengan PDO biasa dan array asosiatif:

$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

Solusi pilihan Anda adalah yang paling lambat dan paling tidak dapat diandalkan. Jadi jawaban atas pertanyaan Anda adalah solusi yang buruk untuk masalah Anda.




  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 LOAD DATA LOCAL INFILE contoh di python?

  2. pencarian kedekatan kode pos php/mysql

  3. MySQL secara kondisional UPDATE nilai kolom boolean baris berdasarkan daftar putih id

  4. sesuatu tentang ansi_nulls

  5. Cara menghitung rata-rata bergerak berganda di MySQL