【问题标题】:MySQL clean up HAVING with WHERE or JOINMySQL 使用 WHERE 或 JOIN 清理 HAVING
【发布时间】:2015-04-19 00:07:22
【问题描述】:

我有一个查询,当它的尝试状态为 2 或 3 并且超过 7 天时,它会获取所有文档:

SELECT D.*,
GROUP_CONCAT(A.status) as statuses, 
MAX(A.datetime) as maxDate FROM documents D

LEFT JOIN attempts A on A.documentId = D.id

GROUP BY D.id

HAVING statuses NOT LIKE '%2%' 
AND statuses NOT LIKE '%3%'
AND DATE(maxDate) < DATE_SUB(CURDATE(), INTERVAL 7 DAY)

我将 A.status 分组为状态并检查 2 和 3,然后检查 MAX 日期以查看它是否为 7 天。

但是,我听说使用 HAVING 并不是最好的方法,而且我的 LIKE 是一个非常糟糕的主意。有谁知道这是真的还是有更好的方法来优化这段代码?我已经在这几天了,这似乎是最快的方法(尝试过子查询和其他一些方法)。

编辑:为了更好地解释结构,一个文档可以包含无限数量的尝试。尝试使用 documentId 连接到文档的 id。

【问题讨论】:

  • 我认为可以通过修改加入表格的方式来解决问题。你能提供一些关于尝试表结构的信息吗?
  • 澄清一下:没有状态 2,3 并且超过 7 天 = 状态 2,3 当文档只有 6 天时允许?
  • 必须满足所有三个条件:永远不能有 2 或 3,并且日期必须始终早于 7 天。

标签: mysql join optimization having


【解决方案1】:

下面的查询比原来的查询效率更高。 LIKE 是一个非常低效的操作,因为它循环遍历每个字符以查找 2 或 3;查找完全匹配会更有效,即使这确实需要子查询。

HAVING 子句中编写剩余条件的另一种方法是使用子查询,但这比在这种情况下仅使用HAVING 效率低,因为子查询是必须执行的单独查询对于主查询中的每一行。 HAVING 子句只是一个检查我们分组依据的每个值的条件。

这将要求您拥有表attempts 的主键;我叫它attempt_id

SELECT D.*, 
MAX(A.datetime) as maxDate
FROM documents D
LEFT JOIN attempts A on A.documentId = D.id
WHERE NOT EXISTS (SELECT status
                    FROM attempts A2
                   WHERE A2.attempt_id = A.attempt_id
                     AND A2.status = 2
                      OR A2.status = 3)
GROUP BY D.id
HAVING DATE(maxDate) < DATE_SUB(CURDATE(), INTERVAL 7 DAY)

【讨论】:

    猜你喜欢
    • 2010-11-21
    • 2013-04-15
    • 2016-05-27
    • 1970-01-01
    • 2021-03-14
    • 2013-01-03
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多