如何优化此 MYSQL JOIN 查询?

How do I optimize this MYSQL JOIN Query?

我很难处理查询优化,我相信目前使用的查询优化可以有很大改进。

我有 4 张桌子;

Artist (14,930 rows)
artist_id artist_name artist_slug artist_country
1 Elle elle 5
Country (85 rows)
country_id country_name country_slug
1 USA usa
Song (61,119 rows)
song_id song_title song_artist_id song_plays
1 Kitty kat 1 38291
2 Donkey 1 8291
Lyrics (61,119 rows)
lyrics_id lyrics_song_id lyrics_body
1 1 Kitty Kat lyrics
2 2 Donkey lyrics

我正在使用此查询加入表格,获取单个艺术家的数据加上国家/地区、歌曲总数、艺术家所有歌曲的播放总和以及歌词总数。

SELECT /*+ MAX_EXECUTION_TIME(2000) */ 
artist.*,
country.*,
COUNT(song.song_id) AS TotalSongs,
COUNT(lyrics.lyrics_id) AS TotalLyrics,
SUM(song.song_plays) AS TotalPlays
FROM artist
LEFT JOIN country ON artist.artist_country_id = country.country_id
LEFT JOIN song ON artist.artist_id = song.song_artist_id
LEFT JOIN lyrics ON song.song_id = lyrics.lyrics_song_id 
WHERE artist_status = 'enabled' AND artist.artist_slug = '$slug'
GROUP BY artist.artist_id LIMIT 0, 1

如何改进它以更快地执行并使用更少的资源?

提前致谢。

我会简单地在 select 子句中使用子查询进行聚合:

SELECT artist.*, country.*, (
    SELECT COUNT(*)
    FROM song
    WHERE song.song_artist_id = artist.artist_id
) AS total_songs, (
    SELECT SUM(song_plays)
    FROM song
    WHERE song.song_artist_id = artist.artist_id
) AS total_plays, (
    SELECT COUNT(*)
    FROM song
    JOIN lyrics ON song.song_id = lyrics.lyrics_song_id
    WHERE song.song_artist_id = artist.artist_id
) AS total_lyrics
FROM artist
LEFT JOIN country ON artist.artist_country_id = country.country_id
WHERE artist_status = 'enabled'
AND artist.artist_slug = :slug

在 MySQL 8 或更高版本中,您可以使用横向连接:

SELECT artist.*, country.*, lj.*
FROM (artist LEFT JOIN country ON artist.artist_country_id = country.country_id), LATERAL (
    SELECT COUNT(song.song_id) total_songs, SUM(song_plays) total_plays, COUNT(lyrics.lyrics_id) total_lyrics
    FROM song
    LEFT JOIN lyrics ON song.song_id = lyrics.lyrics_song_id
    WHERE song.song_artist_id = artist.artist_id
) AS lj
WHERE artist_status = 'enabled'
AND artist.artist_slug = :slug

在 table 上创建所有索引,列为:

CREATE INDEX index_name1 ON artist (artist_country_id ); 
CREATE INDEX index_name2 ON country (country_id); 
CREATE INDEX index_name3 ON artist (artist_id ); 
CREATE INDEX index_name4 ON song (song_artist_id); 
CREATE INDEX index_name5 ON artist (artist_status );

并创建一个视图:

CREATE VIEW customerPayments
AS 
SELECT /*+ MAX_EXECUTION_TIME(2000) */ 
artist.*,
country.*,
COUNT(song.song_id) AS TotalSongs,
COUNT(lyrics.lyrics_id) AS TotalLyrics,
SUM(song.song_plays) AS TotalPlays
FROM artist
LEFT JOIN country ON artist.artist_country_id = country.country_id
LEFT JOIN song ON artist.artist_id = song.song_artist_id
LEFT JOIN lyrics ON song.song_id = lyrics.lyrics_song_id 
WHERE artist_status = 'enabled' AND artist.artist_slug = '$slug'
GROUP BY artist.artist_id LIMIT 0, 1;

视图是存储在数据库目录中的命名查询

视图不实际存储数据。当您对视图发出 SELECT 语句时,MySQL 执行视图的基础查询定义和 returns 结果集。因此,有时 视图被称为虚拟 table。

物化视图 (MV) 是查询的 pre-calculated(物化)结果。 与简单的 VIEW 不同,实体化视图的结果存储在某个地方,通常在 table 中。当需要立即响应并且实体化视图所基于的查询需要很长时间才能产生结果时,使用实体化视图。物化视图必须不时刷新一次。这取决于实体化视图刷新的频率及其内容的实际程度的要求。基本上,物化视图可以立即刷新或延迟刷新,可以完全刷新或刷新到某个时间点。 MySQL 本身不提供物化视图。但是自己构建物化视图很容易。

由于实体化视图基于缓存获取数据,因此它们比视图更快。 Mysql.But中没有物化视图的概念你可以通过https://fromdual.com/mysql-materialized-views

实现你自己的物化视图