【问题标题】:Better performance in MySQL subqueries for timeline graph时间线图的 MySQL 子查询性能更好
【发布时间】:2016-01-28 12:15:09
【问题描述】:

我有一个包含参与者、潜在客户和客户的时间线小部件的子查​​询查询。 例如,表中有 15k 行,但在此日期范围(1 月 1 日至 1 月 28 日)中只有 2k 行,这大约需要 40 秒!

SELECT created_at as date, 
(
    SELECT COUNT(id)
    FROM participant
    WHERE created_at <= date
) as participants,
(
    SELECT COUNT(DISTINCT id)
    FROM participant
    WHERE participant_type = "lead"
    AND created_at <= date
) as leads,
(
    SELECT COUNT(DISTINCT id)
    FROM participant
    WHERE participant_type = "customer"
    AND created_at <= date
) as customer
FROM participant
WHERE created_at >= '2016-01-01 00:00:00'
AND created_at <= '2016-01-28 23:59:59'
GROUP BY date(date)

如何提高性能?

表字段声明如下:

id => primary_key, INT 10, auto increment
participant_type => ENUM "lead,customer", NULLABLE, ut8_unicode_ci
created_at => TIMESTAMP, default '0000-00-00 00:00:00'

【问题讨论】:

  • id提供索引
  • id已经被索引为primary_key

标签: mysql subquery timeline


【解决方案1】:

可能尝试使用计数(或总和)中的条件来获得您想要的值,并交叉连接:-

SELECT a.created_at as date, 
        SUM(IF(b.created_at <= a.created_at, 1, 0)) AS participants,
        COUNT(DISTINCT IF(b.participant_type = "lead" AND b.created_at <= a.created_at, b.id, NULL)) AS leads,
        COUNT(DISTINCT IF(b.participant_type = "customer" AND b.created_at <= a.created_at, b.id, NULL)) AS customer
FROM participant a
CROSS JOIN participant b
WHERE a.created_at >= '2016-01-01 00:00:00'
AND a.created_at <= '2016-01-28 23:59:59'
GROUP BY date(date)

或者可能将日期检查移到联接中

SELECT a.created_at as date, 
        COUNT(b.id) AS participants,
        COUNT(DISTINCT IF(b.participant_type = "lead", b.id, NULL)) AS leads,
        COUNT(DISTINCT IF(b.participant_type = "customer", b.id, NULL)) AS customer
FROM participant a
LEFT OUTER JOIN participant b
ON b.created_at <= a.created_at
WHERE a.created_at >= '2016-01-01 00:00:00'
AND a.created_at <= '2016-01-28 23:59:59'
GROUP BY date(date)

【讨论】:

  • 谢谢。这看起来不错,但是使用这些查询时间要长得多。
  • 能否将表格声明添加到您的原始帖子中?
  • 为三个所需字段完成此原始操作
  • 表上的索引是什么?
  • 索引位于主键 id 上。这就是 id 被自动索引的原因。
【解决方案2】:

我不清楚你想用这个查询做什么。但是我可以提供优化的方法吗?

试试这个:

SELECT
    participants.day as day,
    participants.total_count,
    leads.lead_count,
    customer.customer_count
FROM
    (
        SELECT created_at as day, COUNT(id) as total_count
        FROM participant
        WHERE created_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-28 23:59:59'
        GROUP BY day
    ) as participants
LEFT JOIN
    (
        SELECT  created_at as day, COUNT(DISTINCT id) as lead_count
        FROM participant
        WHERE participant_type = "lead"
        AND created_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-28 23:59:59'
        GROUP BY day
    ) as leads ON (participants.day = leads.day)
LEFT JOIN
    (
        SELECT created_at as day, COUNT(DISTINCT id) as customer_count
        FROM participant
        WHERE participant_type = "customer"
        AND WHERE created_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-28 23:59:59'
        GROUP BY day
    ) as customer ON (participants.day = customer.day)

【讨论】:

  • 谢谢。但我想要一个基于日期的图表,并计算每天的参与者、潜在客户、客户。这就是为什么每种类型的参与者都会出现“WHERE p.created_at
  • 对不起,我在子选择中忘记了日期功能。 SELECT created_at as day 应该看起来像 SELECT date(created_at) as day,
【解决方案3】:

为查询添加索引。您可以对此查询执行解释。

EXPLAIN 的帮助下,您可以看到应该在哪里为表添加索引,以便通过使用索引查找行来更快地执行语句。

【讨论】:

    猜你喜欢
    • 2014-11-30
    • 2017-03-07
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 2011-12-02
    • 1970-01-01
    相关资源
    最近更新 更多