【问题标题】:Need some help optimising an SQL query需要一些帮助来优化 SQL 查询
【发布时间】:2021-09-06 00:29:53
【问题描述】:

我的客户获得了以下代码,他每天都使用它来计算在他的网站上发送给企业的消息。我查看了 MYSQL.SLOW.LOG,它有以下查询的统计数据,这表明它需要优化。

计数:183 时间=44.12s (8073s) 锁定=0.00s (0s) Rows_sent=17337923391683297280.0 (-1), Rows_examined=382885.7 (70068089), Rows_affected=0.0 (0), thewedd1[thewedd1]@localhost

查询是:

SELECT
  businesses.name AS BusinessName,
  messages.created AS DateSent,
  messages.guest_sender AS EnquirersEmail,
  strip_tags(messages.message) AS Message,
  users.name AS BusinessName
FROM
  messages
  JOIN users ON messages.from_to = users.id
  JOIN businesses ON users.business_id = businesses.id

我的 SQL 不是很好,但是 LEFT JOIN 而不是 JOIN 是否有助于减少返回的行数或行数?我已经运行了一个 EXPLAIN 查询,它似乎在 LEFT JOIN 和 JOIN 之间没有区别..

基本上我认为减少返回的行数会很好,因为它太大了..

【问题讨论】:

  • 检查你的执行计划和索引。根据您提供的信息,查询是完全正常的,没有什么可以改进的(除了@AKX指出的)
  • LEFT JOINs 只能增加加入的行数。
  • 您确定您的查询一开始就正确吗?它有两列别名为 BusinessName...
  • my client was given the following code and he uses it daily to count the messages sent ... 如果这纯粹是为了计数,为什么不适当地聚合结果,而不是返回所有匹配的行并让客户端/应用程序计数?这就是减少返回行的方式。然而,这个问题并没有解释整个/明确的要求。
  • strip_tags 不是 MySQL 内置函数。提供它的代码......也许它是问题的根源?

标签: mysql sql optimization


【解决方案1】:

简短回答:除了重复的 BusinessName 别名之外,您的查询没有任何“错误”。

长答案:您可以向外键/主键添加索引以加快搜索速度,这不仅仅是更改查询。

如果您使用的是 SSMS(SQL 管理工作室),您可以右键单击表的索引并使用向导。

只是不要试图索引所有列,因为这可能会减慢您将来执行的任何插入操作,除非您知道自己在做什么,否则请坚持使用 ids 和 _ids。

【讨论】:

  • 感谢您的帮助。是的,我没有发现重复的 AS BusinessName。出于好奇,Rows_sent 数字非常大(超过 17 quintillion),这是正确的还是可能的?
  • @jodaki 可能没问题,我认为只是每次您进行联接时,它都会在每条记录中复制一行。如果 id 1 在表 2 中有 3 行,那么将有 1x3,如果它在表 3 中 4 次,那么它的 3 x 4 等等
【解决方案2】:

他每天都用它来统计发送给企业的消息

如果每天都这样做,为什么不将其限制为最近几天发送的消息?

例如:要统计最近几天(例如:3 或 4 天)每天每个企业发送的消息,请尝试以下操作:

SELECT businesses.name       AS BusinessName
     , messages.created      AS DateSent
     , COUNT(*) AS n
  FROM messages
  JOIN users      ON messages.from_to  = users.id
  JOIN businesses ON users.business_id = businesses.id
 WHERE messages.created BETWEEN current_date - INTERVAL '3' DAY AND current_date
 GROUP BY businesses.id
        , DateSent
 ORDER BY DateSent DESC
        , n DESC
        , businesses.id
;

注意:businesses.name 在功能上依赖于businesses.id(在GROUP BY 术语中),这是businesses 的主键。

示例结果:

+--------------+------------+---+
| BusinessName | DateSent   | n |
+--------------+------------+---+
| business1    | 2021-09-05 | 3 |
| business2    | 2021-09-05 | 1 |
| business2    | 2021-09-04 | 1 |
| business2    | 2021-09-03 | 1 |
| business3    | 2021-09-02 | 5 |
| business1    | 2021-09-02 | 1 |
| business2    | 2021-09-02 | 1 |
+--------------+------------+---+
7 rows in set

这假设您的基本 join 逻辑是正确的,这可能不正确。

如有必要,其他数据可以作为汇总结果返回,而且现在这仅限于最近的数据,因此检查的行数应该更加合理。

【讨论】:

    猜你喜欢
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 2014-08-03
    相关资源
    最近更新 更多