【问题标题】:MySQL Query is slow (Joins/counts)MySQL 查询很慢(加入/计数)
【发布时间】:2015-05-29 16:21:29
【问题描述】:

我有这个问题:

 SELECT `assemblies`.`id`,
   `assemblies`.`type`,
   `assemblies`.`champion`,
   `assemblies`.`name`,
   `assemblies`.`author`,
   `assemblies`.`githublastmod`,
   ( assemblies.forum IS NOT NULL ) AS forumExists,
   Count(votes.id)                  AS votesCount,
   Count(install_clicks.id)         AS installCount,
   Count(github_clicks.id)          AS githubCount,
   Count(forum_clicks.id)           AS forumCount
FROM   `assemblies`
   INNER JOIN `votes`
           ON `votes`.`assembly` = `assemblies`.`id`
   INNER JOIN `install_clicks`
           ON `install_clicks`.`assembly` = `assemblies`.`id`
   INNER JOIN `github_clicks`
           ON `github_clicks`.`assembly` = `assemblies`.`id`
   INNER JOIN `forum_clicks`
           ON `forum_clicks`.`assembly` = `assemblies`.`id`
WHERE  `assemblies`.`type` = 'utility'
   AND Unix_timestamp(Date(assemblies.githublastmod)) > '1419536536'
GROUP  BY `assemblies`.`id`
ORDER  BY `votescount` DESC,
      `githublastmod` DESC  

由于某种原因,这个查询非常慢,我正在使用数据库引擎 MyISAM。我希望有人可以在这里帮助我:)

解释命令:

【问题讨论】:

  • 将解释命令添加为图像(复制/粘贴对我来说失败:(),链接到完整图像:i.stack.imgur.com/y8k8H.png
  • 您的表中有哪些索引?连接表所涉及的所有字段是否都已编入索引?
  • 我只将 id 设置为索引。我也应该为其他列添加索引吗?
  • 你应该在votes.assemblyinstall_clicks.`assembly等上添加索引
  • SHOW CREATE TABLE,而不是SHOW INDEXES

标签: mysql performance myisam


【解决方案1】:

我相信在这种情况下,为计数创建子查询会使其运行得更快(并且值将是正确的)。

原始查询的问题是中间行数的爆炸式增长:对于每个“程序集”,有 n1 票、n2 次安装等。这导致 n1*n2*... 行 per 大会。

SELECT  `assemblies`.`id`, `assemblies`.`type`, `assemblies`.`champion`,
        `assemblies`.`name`, `assemblies`.`author`, `assemblies`.`githublastmod`,
        ( assemblies.forum IS NOT NULL ) AS forumExists, 
      ( SELECT  Count(*)
            FROM  votes
            WHERE  `assembly` = `assemblies`.`id` 
      ) AS votesCount, 
      ( SELECT  Count(*)
            FROM  install_clicks
            WHERE  `assembly` = `assemblies`.`id` 
      ) AS installCount, 
      ( SELECT  Count(*)
            FROM  github_clicks
            WHERE  `assembly` = `assemblies`.`id` 
      ) AS githubCount, 
      ( SELECT  Count(*)
            FROM  forum_clicks.id
            WHERE  `assembly` = `assemblies`.`id` 
      ) AS forumCount
    FROM  `assemblies`
    WHERE  `assemblies`.`type` = 'utility'
      AND  Unix_timestamp(Date(assemblies.githublastmod)) > '1419536536'
    ORDER BY  `votescount` DESC, `githublastmod` DESC 

每个辅助表都需要一个以assembly 开头的索引

【讨论】:

  • 你确定这样更快吗?能否请您给我们一个EXPLAIN 两个选项的结果?
  • 我不确定它是否更快。一方面,我假设 assemblies 是一个短表格,而其他表格很长,每个assemblies.id 有很多行。我假设assembly 已编入索引。希望看到EXPLAINs。
  • 用这个方法解释(我相信这是正确的):gyazo.com/e9fe505cab210fb1b54fe5d6cbbffaf1 ---用我自己的查询解释:gyazo.com/8bfebc979c57953a4ced5b5b7a3b1985
【解决方案2】:

您的问题应该使用正确的索引来解决:

CREATE INDEX index_name_1 ON `votes`(`assembly`);
CREATE INDEX index_name_2 ON `install_clicks`(`assembly`);
CREATE INDEX index_name_3 ON `github_clicks`(`assembly`);
CREATE INDEX index_name_4 ON `forum_clicks`(`assembly`);

创建这些索引后再次尝试查询,它应该会更快。

【讨论】:

  • 据我所知,这已经工作得更好了。但它并没有在 forum_clicks 上选择一个键。 gyazo.com/8728fbac4c836192e386adb85170a6ae
  • 请注意,每个辅助表的 Rows 列要小得多。请注意,优化器选择从 forum_clicks 而不是程序集开始。
  • (旁注:稍微添加解释)---问题几乎解决了,forum_clicks 仍然包含所有行,有没有办法解决这个问题?
  • 根据显示的EXPLAIN,服务器知道assembly 上有索引,但不想使用它。正如@RickJames 所说,这可能是因为扫描所有表比使用索引更快(例如,取决于列值分布)。也就是说,您可以尝试将forum_clicks.assembly 添加到Group By 子句中。
  • 服务器用起来还是很笨哈哈哈。我正在使用 Rick 的答案,因为它工作得很好,但没有你就无法做到。很抱歉,我只能将一个帖子标记为 anwer :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 2016-02-10
相关资源
最近更新 更多