【问题标题】:Optimizing query for calculating Median using GROUP BY & ORDER BY使用 GROUP BY 和 ORDER BY 优化计算中位数的查询
【发布时间】:2018-06-26 15:14:57
【问题描述】:

请参阅下面的 MySQL 表的示例部分:

表名:eb_tickets

+-------------------+----------------------+
|  ticket_type      |  time_first_response |
|  Standard Traffic |  0:18:14             |
|  Standard Traffic |  0:48:06             |
|  Miscellaneous    |  44:12:23            |
|  Feed             |  4:48:22             | 
|  Miscellaneous    |  15:33:20            |
|  Banners          |  21:00:02            |
|  Integration      |  36:00:02            |
+-------------------+----------------------+

我想像这样输出响应,用不同的值 ASC 计算中值:

+-------------------+----------------------+
|  median_group     |  median              | 
|  Banners          |  21:00:02            |
|  Feed             |  4:48:22             | 
|  Integration      |  36:00:02            |
|  Miscellaneous    |  32:36:13            |
|  Standard Traffic |  0:33:10             |
+-------------------+----------------------+

目前,我通过以下查询来实现这一点:

SET @row_number:=0; 
SET @median_group:='';

SELECT 
    median_group, AVG(time_first_response) AS median
FROM
(SELECT 
    @row_number:=CASE
        WHEN @median_group = ticket_type THEN @row_number + 1
        ELSE 1
    END AS count_of_group,
    @median_group:=ticket_type AS median_group,
    ticket_type,
    time_first_response,
    (SELECT 
            COUNT(*)
        FROM
            eb_tickets
        WHERE
            a.ticket_type = ticket_type) AS total_of_group 
FROM
    (SELECT 
        ticket_type, time_first_response
    FROM
        eb_tickets           
    ORDER BY ticket_type, time_first_response) AS a) AS b
    WHERE
    count_of_group BETWEEN total_of_group / 2.0 AND total_of_group / 2.0 +1
    GROUP BY median_group

不幸的是,这个查询每条记录大约需要 1 秒,我正在查询数千条记录,ticket_type 列可能有 20 个不同的值。

是否可以优化我当前的查询以使查询执行得更快?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    你可以这样试试吗?

    SELECT counter.ticket_type,AVG(time_first_response) AS median FROM
      (
        SELECT 
          IF(@type = type, @ctr := @ctr + 1, @ctr := 1) AS rownum, 
          @type := ticket_type AS ticket_type,
          time_first_response
        FROM eb_tickets
        ORDER BY ticket_type,time_first_response
      ) AS counter,
      (
        SELECT ticket_type, COUNT(*) AS rows
        FROM eb_tickets
        GROUP BY ticket_type
      ) AS types
      WHERE types.ticket_type = counter.ticket_type AND
        CASE rows % 2 
          WHEN 1 THEN rownum IN (ROUND(rows / 2),ROUND(rows / 2))
          ELSE rownum IN (ROUND(rows / 2),ROUND(rows / 2) + 1)
        END
      GROUP BY counter.ticket_type
    

    最初,当我在试验 SQL 时,我使用较短的列名称 - type 而不是 ticket_type,子查询 counter 留下了错误的列名称 type 而不是 ticket_type

    【讨论】:

    • 我使用 counter.type 而不是 counter.ticket_type 因为我收到了关于 counter.ticket_type 不存在的错误,它只返回部分结果(尽管结果是正确的)。因此,它返回了票证类型和正确的中位数,但是它并未在结果中包含所有票证类型。将 counter.ticket_type 更改为 counter.type 是否正确?
    • 我还将GROUP BY ticket_type 编辑为GROUP BY ticket_type,time_first_response,现在我得到了与原始查询非常接近的完整结果集。现在我不确定哪个查询是准确的:/ 但是这在查询中节省了大量时间。 10 条记录 118 秒 VS 10 条记录 1 秒。
    • 做一些测试看看哪个更准确:)
    • 你的更准确、更快(通过上述调整)。谢谢楼主!
    猜你喜欢
    • 2012-12-31
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 2011-05-13
    相关资源
    最近更新 更多