Php RESTAPI的Laravel DB查询速度非常慢
我正在和拉威尔一起做我的第一步,试着写一个音乐播放列表。该数据库有3个实体/模型:Php RESTAPI的Laravel DB查询速度非常慢,php,mysql,laravel,eloquent,mariadb,Php,Mysql,Laravel,Eloquent,Mariadb,我正在和拉威尔一起做我的第一步,试着写一个音乐播放列表。该数据库有3个实体/模型: Play <-n-1-> Song <-n-1-> Artist 该数据库拥有约856000部戏剧,33000首歌曲和15000名艺术家 起初,我试着直接使用模型,急切地加载剧本->歌曲->艺术家 return playsource::collection(Play::whereDate('date',$date)->get()); 通过Laravel在RESTAPI上使用此查询需要2
Play <-n-1-> Song <-n-1-> Artist
该数据库拥有约856000部戏剧,33000首歌曲和15000名艺术家
起初,我试着直接使用模型,急切地加载剧本->歌曲->艺术家
return playsource::collection(Play::whereDate('date',$date)->get());
通过Laravel在RESTAPI上使用此查询需要2.6秒。
我想这很慢
如果我正确理解了Laravel,它会对许多DB查询产生影响:
- 对剧本的一个查询
- 另一首歌
- 但对于每一个剧本/歌曲,都需要对其艺术家进行单独的询问(?)
returndb::table('plays')
->leftJoin('songs'、'plays.song_id'、'='、'songs.id')
->leftJoin('artists'、'songs.artist_id'、'='、'artists.id')
->选择('plays.*'、'songs.*'、'Artisters.*')
->whereDate('plays.date',$date)
->orderByDesc('plays.date')
->get();
这个查询稍微快一点,但仍然很慢:2.2s
直接在数据库上调用等效的SQL查询要快得多:
选择*
从剧本p
在p.song_id=s.id上左连接歌曲s
在s.artist_id=a.id上左键加入艺术家a
其中日期(p.DATE)=“2020-12-30”
按p.date DESC订购;
->0.4s
我是否做错了什么,或者使用Laravel时这是典型的开销
EDIT1:
好的,我找到了DB::getQueryLog()
(但这不是我要找的)。现在我知道了:使用三个表和链式急切加载只会导致3db查询。我的第一个是最慢的,将近400毫秒。这两个查询每个只需要1-2毫秒
我还发现流明应该比Laravel快。所以我试过了。我的第一个使用模型的查询现在需要1.4s。为输出映射添加JsonResources会添加0.3s->1.7s。在我看来,所有这一切仍在放缓
但我认为这是我在使用现代框架时必须付出的代价。(我2006年的旧播放列表不使用任何框架)
EDIT2:
第一个查询可以通过以下方式显著增强:
date
列上添加索引DATE(`DATE`)
或->whereDate('DATE',…)
)进行查询,而是使用->wherebeen('DATE',[$DATE,'23:59:59'])
现在第一个查询只需要5毫秒(以前是400毫秒)。对于整个流明查询,我是1.3SQL查询只执行您可以通过向app/providers/AppServiceProvider.php文件中添加以下函数来检查Laravel正在向数据库启动的查询:
public function boot(){
if(env('APP_DEBUG')) {
DB::listen(function($query) {
File::append(
storage_path('/logs/query.log'),
$query->sql . ' [' . implode(', ', $query->bindings) . ']' . PHP_EOL
);
});
}
}
您将在将创建的/storage/logs/query.log文件中找到每个查询的sql代码。
这有助于我理解和优化查询生成器语句,有时我也会遇到类似的问题。尝试在不转换为特殊集合的情况下进行度量。只需
Play::whereDate('date',$date)->with(['artist','song'])->get()
让我们看看生成的SQL,以便发现问题。我在查询后添加了一个强制异常以获取Laravels调试屏幕。在“调试”选项卡下,我可以看到之前的查询及其运行时间。使用JOIN查询,生成的查询看起来与我编写的SQL查询几乎相同,只需0.4s。因此,开销来自拉威尔。不是来自生成的查询。