【问题标题】:JOIN query taking long time and creating issue "converting HEAP to MyISAMJOIN 查询需要很长时间并创建问题“将 HEAP 转换为 MyISAM
【发布时间】:2019-12-03 06:39:55
【问题描述】:

我的查询如下。这里我使用连接查询来获取数据。你能建议我如何解决“将 HEAP 转换为 MyISAM”的问题。

我可以在这里使用子查询来更新它吗?请建议我该怎么做。

这里我加入了 users 表来检查用户是否存在。我可以在不加入的情况下对其进行改进,以便“将 HEAP 转换为 MyISAM”可以解决。

哦,有时我不会检查特定的 user_id。像这里我添加了 user_id = 16082

SELECT `user_point_logs`.`id`, 
   `user_point_logs`.`user_id`, 
   `user_point_logs`.`point_get_id`, 
   `user_point_logs`.`point`, 
   `user_point_logs`.`expire_date`, 
   `user_point_logs`.`point`  AS `sum_point`, 

   IF(sum(`user_point_used_logs`.`point`) IS NULL, 0, sum(`user_point_used_logs`.`point`)) AS `minus` 

   FROM   `user_point_logs` 

     JOIN `users` ON ( `users`.`id` = `user_point_logs`.`user_id` ) 

     LEFT JOIN (SELECT * 
              FROM   user_point_used_logs 
              WHERE  user_point_log_id NOT IN (
                                                     SELECT DISTINCT return_id 
                                               FROM   user_point_logs 
                                               WHERE  return_id IS NOT NULL 
                                                      AND user_id = 16082
                                                              )
                  ) 
    AS user_point_used_logs
      ON ( `user_point_logs`.`id` = `user_point_used_logs`.`user_point_log_used_id` ) 

    WHERE  expire_date >= 1563980400 

   AND `user_point_logs`.`point` >= 0 

   AND `users`.`id` IS NOT NULL 

   AND ( `user_point_logs`.`return_id` = 0 
          OR `user_point_logs`.`return_id` IS NULL ) 

   AND `user_point_logs`.`user_id` = '16082' 

   GROUP  BY `user_point_logs`.`id` 
   ORDER  BY `user_point_logs`.`expire_date` ASC 

DB FIDDLE HERE WITH STRUCTURE

【问题讨论】:

  • 分享你的explain执行计划
  • @James 我不确定如何解决这个问题。我可以删除“用户”表连接查询。但其他人加入查询如何优化我不知道该怎么做。
  • 在查询的开头添加 EXPLAIN SELCT ..... 然后分享结果
  • 您可以添加您的表创建语句,因为存在不必要的 where 子句。更好地了解您的索引和其他列数据类型
  • 感谢您提供详细信息。似乎缺少用户表?

标签: mysql join subquery myisam


【解决方案1】:

请尝试一下,如果可行...将通过添加复合索引进一步优化。

SELECT 
    upl.id,
    upl.user_id,
    upl.point_get_id,
    upl.point,
    upl.expire_date,
    upl.point AS sum_point,
    coalesce(SUM(upl.point),0) AS minus -- changed from complex to readable
FROM user_point_logs upl
JOIN users u ON upl.user_id = u.id
LEFT JOIN (select supul.user_point_log_used_id from user_point_used_logs supul
left join user_point_logs supl on supul.user_point_log_id=supl.return_id and supl.return_id is null and supl.user_id = 16082) AS upul 
ON upl.id=upul.user_point_log_used_id

WHERE
upl.user_id = 16082 and coalesce(upl.return_id,0)= 0 
and upl.expire_date >= 1563980400 -- tip: if its unix timestamp change the datatype and if possible use range between dates
        #AND upl.point >= 0 -- since its NN by default removing this condition
        #AND u.id IS NOT NULL -- removed since the inner join matches not null
GROUP BY upl.id
ORDER BY upl.expire_date ASC;

编辑:

尝试在表user_point_logsreturn_id 列中添加索引。 由于此列用于派生查询的联接。 或者使用user_id and return_id的复合索引

【讨论】:

  • 感谢您的帮助。它看起来有所改善。有什么办法可以改善更多。会很好的。 i.imgur.com/bhdeS0b.jpg
  • 好的,结果是你需要的吗?
  • 是的,看起来改进了。正如你所说,你可以优化更多,所以你可以尝试。这将更加明显
  • 已编辑如果可行,我们可以在 where 子句中进一步优化
【解决方案2】:

索引:

user_point_logs:  (user_id, expire_date)
user_point_logs:  (user_id, return_id)

OR 很难优化。决定只用一种方式来表达这里所说的一切,然后摆脱OR

   AND (     `user_point_logs`.`return_id` = 0 
          OR `user_point_logs`.`return_id` IS NULL ) 

DISTINCT 是多余的:

NOT IN ( SELECT DISTINCT ... )

改变

IF(sum(`user_point_used_logs`.`point`) IS NULL, 0,
   sum(`user_point_used_logs`.`point`)) AS `minus`

COALESCE( ( SELECT SUM(point) FROM   user_point_used_logs ... ), 0)  AS minus

然后折腾LEFT JOIN (SELECT * FROM user_point_used_logs ... )

由于PRIMARY KEY 是一个键,第二个是多余的,可以是DROPped

ADD PRIMARY KEY (`id`),
ADD KEY `id` (`id`) USING BTREE;

毕竟,我们可能需要另一遍来进一步简化和优化它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-02
    相关资源
    最近更新 更多