【问题标题】:Slow MariaDB when Query Joining Million of RecordsMariaDB 查询加入百万条记录时速度慢
【发布时间】:2020-05-31 19:25:22
【问题描述】:

我安装了一个插件,并在后端进行了优化(SSD,在 GROUP BY & WHERE 中调用的列的单列索引) 但是在运行这个查询时

SELECT  u.user_id, u.profile_page_id, u.server_id AS user_server_id, u.user_name, u.full_name, u.gender, u.user_image, u.is_invisible, u.user_group_id, u.language_id, u.birthday, u.country_iso, m.*
FROM(
(SELECT m.*
FROM phpfox_channel_video AS m
INNER JOIN phpfox_channel_category AS mc
    ON(mc.category_id = mc.category_id)
INNER JOIN phpfox_channel_category_data AS mcd
    ON(mcd.video_id = m.video_id)

WHERE m.in_process = 0 AND m.view_id = 0 AND m.module_id = 'videochannel' AND m.item_id = 0 AND m.privacy IN(0) AND mcd.category_id = 17
GROUP BY m.video_id
ORDER BY m.time_stamp DESC
)) AS m
JOIN phpfox_user AS u
    ON(u.user_id = m.user_id)

ORDER BY m.time_stamp DESC
LIMIT 24;

这需要 20 秒,而改成这个

SELECT  u.user_id, u.profile_page_id, u.server_id AS user_server_id, u.user_name, u.full_name, u.gender, u.user_image, u.is_invisible, u.user_group_id, u.language_id, u.birthday, u.country_iso, m.*
FROM(
(SELECT  m.*
FROM phpfox_channel_video AS m
INNER JOIN phpfox_channel_category_data AS mcd
    ON(mcd.video_id = m.video_id AND mcd.category_id = 17)
WHERE m.in_process = 0 AND m.view_id = 0 AND m.module_id = 'videochannel' AND m.item_id = 0 AND m.privacy IN(0) 
GROUP BY m.video_id
ORDER BY m.time_stamp DESC
)) AS m
JOIN phpfox_user AS u
    ON(u.user_id = m.user_id)

ORDER BY m.time_stamp DESC
LIMIT 24;

这运行大约 5-6 秒

phpfox_channel_video 包含 200 万行(并将继续快速添加,它是一个社交媒体网站,用户也可以上传文件)所以缓存不是很有用(但已激活)。

关于如何优化它的任何提示?我对 MariaDB/MySQL 的经验很少,因为我已经习惯了 MS SQL 来处理大数据,并创建了自己的结构。任何推荐的方法都不需要对表格进行太多改动(添加表格就可以了)。

或者我是否需要重组 PHP & 表以优化查询以低于 1 秒/查询。 谢谢!

我找到了这些链接 http://mysql.rjweb.org/doc.php/memory & http://mysql.rjweb.org/doc.php/ricksrots#indexing

它们仍然相关吗?

附上解释结果 而对于索引,当前的配置设置为索引,每一列都被声明为一个索引键,上面查询中涉及的所有表。

打印出我当前的服务器配置会有帮助吗?谢谢!

【问题讨论】:

  • 添加解释您的查询以及您拥有的索引或为所有涉及的表创建表-
  • 嗨@nbk 我已经更新了帖子。有什么反馈吗?
  • 您提供的前两个链接来自@RickJames
  • @tcadidot9 谢谢,我会发消息给他
  • 是的,这两个链接仍然有效。我确实“根据需要”更新它们。 (相关性是另一个问题。)

标签: mysql mariadb


【解决方案1】:

我设法清理查询,检查表后,结果是

WHERE m.in_process = 0
  AND m.view_id = 0
  AND m.module_id = 'videochannel'
  AND m.item_id = 0
  AND m.privacy IN(0) 

不需要运行,因为所有的表都符合那个条件..(对于本网站的当前情况)..所以我只是优化那些长查询。并设法击中

【讨论】:

    【解决方案2】:
    INNER JOIN  phpfox_channel_category AS mc ON(mc.category_id = mc.category_id)
    

    几乎没用了。

    • 您不得将mc 的任何列用于其他目的。
    • 执行此JOIN
    • 这个JOIN验证了mc中有对应的行。
    • 如果有 多个 对应的行,这个 JOIN 将使临时表膨胀。
    • 膨胀导致GROUP BY 中的工作浪费。

    同样,您的第二个查询不使用mcd

    请为派生表使用不同的别名。 m. 的多种用途很难理解。

    这完全没用:

    ORDER BY  m.time_stamp DESC
    

    MySQL/MariaDB 可以随意忽略派生表中的ORDER BY。一个表被定义为一组 无序 行。只能在最后下单。

    建议索引

    m: INDEX(item_id, module_id, view_id, in_process, -- any order; tested with '='
             privacy,   -- sometimes has a list?
             video_id)  -- last
    mcd:  INDEX(category_id, video_id)  -- in either order
    

    有一种更合乎逻辑的方法可以做到这一点,而且可能更快:

        INNER JOIN  phpfox_channel_category_data AS mcd
              ON  mcd.video_id = m.video_id
             AND  mcd.category_id = 17
    

    删除它,并删除GROUP BY m.id,然后将其添加到WHERE

    AND EXISTS( SELECT 1 FROM phpfox_channel_category_data AS mcd
                   WHERE  mcd.video_id = m.video_id
                     AND  mcd.category_id = 17 )
    

    (上面提到的索引仍然适用。)

    并不是说我可能已经消除了两个“文件排序”——GROUP BYORDER BY。另一个注意事项:EXPLAIN 并不总是显示真正有多少文件排序。 (但EXPLAIN FORMAT=JSON SELECT ... 可以。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-31
      • 2018-02-08
      • 1970-01-01
      • 2016-04-12
      • 2011-07-06
      • 1970-01-01
      • 2019-01-06
      • 2013-09-25
      相关资源
      最近更新 更多