如何提高SQL的抓取速度?

时间:2017-07-09 15:26:10

标签: mysql aggregate-functions query-performance

我不是MySQL索引的专家,但我看到了很多教程,使用PHP仍然需要7秒才能加载。

我在MySQL表中有大约50k行和30列。

如何提高MySQL获取数据的速度?我可以在下面的查询中改进一下吗?

SELECT tmdb_movies.movie_title,tmdb_movies.budget,tmdb_movies.original_language,tmdb_movies.original_title

,translations.translations_english_name

,videos.videos_name,videos.videos_key



FROM tmdb_movies 


LEFT JOIN
(
  SELECT 
    translations_tmdb_id
,GROUP_CONCAT(DISTINCT translations.translations_english_name SEPARATOR ', ') AS translations_english_name

  FROM translations
  GROUP BY translations_tmdb_id
) translations ON translations.translations_tmdb_id = tmdb_movies.tmdb_id


LEFT JOIN
(
  SELECT 
    videos_tmdb_id
,GROUP_CONCAT(DISTINCT videos.videos_name) as videos_name
,GROUP_CONCAT(DISTINCT videos.videos_key) as videos_key
  FROM videos
  GROUP BY videos_tmdb_id
) videos ON videos.videos_tmdb_id = tmdb_movies.tmdb_id

Where tmdb_movies.tmdb_id= '$tmdb_id'

在这里,我使用tmdb_id连接所有表。 tmdb_idtranslations_tmdb_idvideos_tmdb_id已在MySQL中编入索引。

以下是我的MySQL表结构示例:

tmdb_movies表格:

tmdb_id      movie_title
1            Logan
2            Iron Man
3            Superman

translations表格

translations_tmdb_id      translations_english_name 
1                         English
1                         Hindi
1                         French 
2                         English
2                         Spanish
2                         Hindi

videos表格

videos_tmdb_id          videos_name
1                       Official Trailer
1                       Trailer 2 
2                       Trailer 1
2                       Trailer 2 HD
3                       Superman Trailer 1
3                       Superman Trailer 2

2 个答案:

答案 0 :(得分:2)

您的主SELECT声明可能没问题;你正在过滤自动增量主键。

这是两个子查询,其机会可能在于提高绩效。

第一个:

  SELECT 
    translations_tmdb_id, 
    GROUP_CONCAT( DISTINCT translations.translations_english_name 
                  SEPARATOR ', ') AS translations_english_name    
  FROM translations
  GROUP BY translations_tmdb_id

translations_tmdb_id, translations_english_name上的compound index (sometimes called a composite index or multi-column index)有可能帮助这个子查询。为什么?它可以帮助查询的GROUP BYDISTINCT部分。

第二个:

  SELECT 
    videos_tmdb_id
,GROUP_CONCAT(DISTINCT videos.videos_name) as videos_name
,GROUP_CONCAT(DISTINCT videos.videos_key) as videos_key
  FROM videos
  GROUP BY videos_tmdb_id

同样的原则适用,但两个不同的DISTINCT条款会使事情变慢一些。在videos_tmdb_id, videos_name, videos_key上尝试复合索引。它应该有所帮助。

答案 1 :(得分:2)

  1. 为什么GROUP_CONCAT(DISTINCT ...)?没有重复。
  2. 您只为一部电影选择数据。但是您的派生表会读取并汇总所有电影。一个伟大的优化器将查看这个并且只对该一部电影的聚合记录。如果这是Oracle,我会期待这一点。但是对于MySQL?我不会依赖这个。因此,在子查询中添加where子句。
  3. 如果没有order by子句,则不应选择视频名称和密钥。订购它们以便两者具有相同的顺序,即第一个名称与第一个键匹配等。
  4. 这是您的查询重写:

    SELECT 
      m.movie_title,
      m.budget,
      m.original_language,
      m.original_title,
      t.translations_english_names,
      v.videos_names,
      v.videos_keys
    FROM tmdb_movies m
    CROSS JOIN
    (
      SELECT 
        GROUP_CONCAT(translations_english_name SEPARATOR ', ') AS translations_english_names
      FROM translations
      WHERE translations_tmdb_id = @tmdb_id
    ) t
    CROSS JOIN
    (
      SELECT 
        GROUP_CONCAT(videos_name ORDER BY videos_name) as videos_names,
        GROUP_CONCAT(videos_key ORDER BY videos_name) as videos_keys
      FROM videos
      WHERE videos_tmdb_id = @tmdb_id
    ) v
    WHERE m.tmdb_id = @tmdb_id;
    

    这些是您应该使用的索引:

    create index idxm on tmdb_movies(tmdb_id); -- if tmdb_id is PK, you have this already
    create index idxt on translations(translations_tmdb_id, translations_english_name);
    create index idxv on videos(videos_tmdb_id, videos_name, videos_key);