如何优化 MySQL 中的多个左连接?

Posted

技术标签:

【中文标题】如何优化 MySQL 中的多个左连接?【英文标题】:How can I do optimize multiple left joins in MySQL? 【发布时间】:2012-12-10 12:09:39 【问题描述】:

你能帮我完成这个查询吗?

我有一个日志查询,它按天(表:calendar,包括没有行的日子。

以下查询需要 10 分钟才能运行!我怎样才能在几秒钟而不是几分钟内运行它?

SELECT
    c.day, COUNT(u.id) AS count
FROM calendar c
LEFT JOIN log l
    ON c.day = DATE_FORMAT(l.db_timestamp , '%Y-%m-%d')
LEFT JOIN user u
    ON l.user_id = u.id
    AND u.user_status_type_id = 1
WHERE
    c.day > '2012-12-01'
    AND c.day < '2013-01-01'
GROUP BY
    c.day

表结构:

calendar (~3,000 rows)
day
===============================
2012-01-01
2012-01-02
2012-01-03
...
2020-01-01


log (~30,000 rows)
id  user_id  db_timestamp
================================
1   1        2012-01-01 01:01:01
1   2        2012-01-01 01:01:01
1   1        2012-01-01 01:01:01

user (~3,000,000 rows)
id  user_status_type_id
================================
1   1
1   0

结果应如下所示:

Sample Expected Results
day         count
=================
2012-12-01  1
2012-12-02  0
2012-12-03  4
...
2012-12-31  0

不幸的是,它需要很长时间才能运行。接下来我该怎么做?

【问题讨论】:

您显示了预期的结果 - 很好。但你实际上得到了什么? 或者您遇到错误? 您发布的查询有什么问题?有什么错误吗?不是预期的结果?或者如果日志表中缺少未填写的天数,您是否要生成天数列表?请详细说明,以便我们为您提供帮助。 这个day在你的表中在哪里?你说选择c.day,我在你的日历表中找不到day 事实证明它确实有效,只是花了很长时间,所以我认为我做错了什么。显然我仍然是,因为我没有搜索大型数据集。我该如何优化呢?问题已更新。 【参考方案1】:

对于您选择的列,您不需要任何连接。使用下面的sql

SELECT DATE_FORMAT(l.db_timestamp , '%Y-%m-%d') AS days, COUNT(l.id) AS COUNT 
FROM LOG l 
WHERE 
DATE_FORMAT(l.db_timestamp , '%Y-%m-%d') > '2012-12-01' 
AND DATE_FORMAT(l.db_timestamp , '%Y-%m-%d') < '2013-01-01'
GROUP BY days

对于用户明智的计数

使用

GROUP BY days, l.user_id

【讨论】:

@ryan 然后查询无法在当前结构中优化,因为连接列的格式不同。如果您可以在日志表中创建仅存储日期(Y-m-d)的另一列,那么您可以在两个连接列上进行连接并创建索引 我同意。我最终使用 php 生成数组中的零行,并基于更简单的没有连接的查询与 mysql 结果合并。再次感谢您的帮助,但我无法在任何可接受的时间内使其工作。【参考方案2】:

试试这个:: 加入时使用DATE()

 SELECT
        c.day, COUNT(u.id) AS count
    FROM calendar c
    LEFT JOIN log l
        ON c.day = DATE(l.db_timestamp)
    LEFT JOIN user u
        ON l.user_id = u.id
        AND u.user_status_type_id = 1
    WHERE
        c.day between '2013-01-01'
 AND '2012-12-01'
        GROUP BY
        c.day

【讨论】:

以上是关于如何优化 MySQL 中的多个左连接?的主要内容,如果未能解决你的问题,请参考以下文章

MySql:查询优化(多个左连接)

如何使用 MySQL 展平左连接的结果?

mysql优化5表左连接

MySQL:优化格式化日期的左连接

MySQL 多个左连接

MySQL 索引优化与子查询与左连接