我不介意 eloquent 对性能的小幅影响,但循环往复
计算差异的结果集..我的意思是,如果我有的话,cmon
数千条记录,一条一条循环是粗略的想法
那我给你一个惊喜——这是一个小的性能测试:
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 对性能的影响很小”是:
- 从数据库中获取数据时,比使用普通 PDO 和
stdClass 慢将近 20 倍。
- 在循环中读取属性/属性时,至少比
stdClass 慢 100 倍。
因此,如果您想提高性能,请在处理大量数据时切换到普通 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
使用转换后的 Eloquent 查询的 PHP 解决方案:
$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
带有普通 PDO 和 stdClass 的 PHP 解决方案
$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
带有普通 PDO 和关联数组的 PHP 解决方案:
$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
您首选的解决方案是最慢且最不可靠的。所以你的问题的答案对你的问题来说是一个不好的解决方案。