【发布时间】:2020-12-17 22:28:00
【问题描述】:
我有一个包含多个表的数据库,我要优化的查询中涉及的只有 4 个。
albums、songs、genres、genre_song
一首歌可以有很多类型,一个类型可以有很多歌曲。一张专辑可以有很多歌曲。专辑通过歌曲与流派相关。
目标是能够推荐与专辑流派相关的专辑。
所以这导致我有这个问题。
SELECT *
FROM `albums`
WHERE EXISTS
(SELECT *
FROM `songs`
WHERE `albums`.`id` = `songs`.`album_id`
AND EXISTS
(SELECT *
FROM `genres`
INNER JOIN `genre_song` ON `genres`.`id` = `genre_song`.`genre_id`
WHERE `songs`.`id` = `genre_song`.`song_id`
AND `genres`.`id` IN (6)))
AND `id` <> 37635
AND `published` = 1
ORDER BY `release_date` DESC
LIMIT 6
这个查询需要 1.4 到 1.6 秒。 我想尽可能减少它。理想的目标是小于 10 毫秒 ????
我已经在几个表中使用了索引,我已经设法将其他查询的时间从最多 4 秒减少到只有 15-20 毫秒。我愿意使用任何东西将性能降低到最低限度。
我正在使用 Laravel,所以这将是 Eloquent 的查询。
$relatedAlbums = Album::whereHas('songs.genres', function ($query) use ($album) {
$query->whereIn('genres.id', $album->genres->pluck('id'));
})->where('id', '<>', $album->id)
->orderByDesc('release_date')
->take(6)
->get();
注意:之前加载了流派。
如果您想在数据库中重新创建表和一些假数据,here is the structure
【问题讨论】:
-
只想指出几点: 1. 提供的架构不完整,因为任何表上都没有
release_date字段。 2. 您使用$album->genres->pluck('id')执行查询。 3. 您应该尝试在每个单独的查询上运行 EXPLAIN 以确保它们正在使用索引。 -
1.你是对的,我想让这个问题保持简单,事实上每个表中有很多字段。 2.在问题中我明确表示之前已经加载了流派,我需要这样。因此,
$album->genres不会进行其他查询。 3 从一开始我就一直这样做。只有索引不适用于EXISTS。这就是我在这里寻求帮助的原因。 -
对每个单独的查询运行解释,简单地按没有索引的字段字段排序会使您的查询变慢。
-
为什么不提供一些样本数据和所需数量的结果?
-
不要认为
EXISTS是这里的瓶颈。 Mysql EXISTS 非常高效。我会听从@Pablo 的建议,也许会分享结果让我们看看?我们谈论的数据集有多大?另外,您提到有很多领域。根据字段的类型,您可能会通过仅选择子查询中的必填字段来获得小优势。