Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Tính toán chênh lệch giá trị giữa hai bản ghi trong Eloquent

Sau đó, tôi có một bất ngờ dành cho bạn - Đây là một bài kiểm tra hiệu suất nhỏ:

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 là một bảng chỉ có một cột int và 1 triệu hàng.

Và kết quả là:

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

Vì vậy, "tác động nhỏ đến hiệu suất từ ​​tài hùng biện" là:

  • Chậm hơn gần 20 lần so với sử dụng PDO đơn giản và stdClass khi tìm nạp dữ liệu từ cơ sở dữ liệu.
  • Chậm hơn ít nhất 100 lần so với stdClass khi đọc thuộc tính / thuộc tính trong một vòng lặp.

Vì vậy, nếu bạn muốn cải thiện hiệu suất, hãy chuyển sang PDO thuần túy khi xử lý lượng lớn dữ liệu hoặc ít nhất là sử dụng Trình tạo mặc định.

Bây giờ bạn vẫn có thể cố gắng thực hiện công việc trong MySQL, nhưng yêu cầu sử dụng Eloquent sẽ không thực hiện được.

Tuy nhiên, bạn có thể thử một phiên bản hỗn hợp - Sử dụng Eloquent để tạo truy vấn, nhưng chuyển đổi nó thành Database\Query\Builder với getQuery() .

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

Nhưng tôi sẽ luôn tránh sử dụng các biến phiên theo cách này trong mã ứng dụng, vì tôi đã thấy nhiều giải pháp như vậy trả lại kết quả sai / không mong muốn sau khi nâng cấp phiên bản.

Vẫn không thuyết phục? Dưới đây là một số thử nghiệm khác:

Sử dụng các biến phiên trong một truy vấn Eloquent được chuyển đổi thành 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

Giải pháp PHP sử dụng truy vấn Eloquent được chuyển đổi:

$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

Giải pháp PHP với PDO đơn giản và 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

Giải pháp PHP với PDO thuần túy và mảng phân bổ:

$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

Giải pháp ưa thích của bạn là giải pháp chậm nhất và kém tin cậy nhất. Vì vậy, câu trả lời cho câu hỏi của bạn là một giải pháp tồi cho vấn đề của bạn.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mã hóa mật khẩu trong Java hoặc MySQL?

  2. Tìm tổng số kết quả trong truy vấn mySQL với offset + giới hạn

  3. Bảng Pivot PHP / MySQL

  4. MySQL - Thiết kế Supertype / Subtype

  5. Cập nhật cột dựa trên các giá trị khớp trong bảng khác trong mysql