【问题标题】:How to speed up the return of most recent records in group by query如何通过查询加快返回分组中最近的记录
【发布时间】:2018-03-14 13:19:24
【问题描述】:

我正在尝试从GROUP BY mysql 查询中返回最新记录。

我的数据如下所示:

id  | user_id | rate_gbp    | active | created_at
===============================================================
1   | 5       | 10.000000   | 1      | 2016-05-19 18:42:55
2   | 6       | 10.000000   | 0      | 2016-05-19 18:42:58
3   | 7       | 10.000000   | 0      | 2016-05-19 18:42:59
4   | 8       | 10.000000   | 0      | 2016-05-19 18:43:01
5   | 9       | 10.000000   | 1      | 2016-05-19 18:43:03
6   | 10      | 10.000000   | 0      | 2016-05-19 18:43:05
7   | 11      | 10.000000   | 0      | 2016-05-19 18:43:07
8   | 12      | 10.000000   | 0      | 2016-05-19 18:43:09

有些记录在一天内被修改了多次,我只想为每个费率提取每天最近的记录。

我已尝试实施类似此处的解决方案:SQL Show most recent record in GROUP BY?,如下所示:

SELECT
  *
FROM (SELECT
  user_id,
  date_format(rates.created_at, '%Y-%m-%d') AS sday,
  MAX(rates.created_at) AS latest_record
FROM rates
GROUP BY id,
         sday) r1
LEFT JOIN (SELECT
  *
FROM rates) r2
  ON r2.created_at = rates.latest_record
  AND r2.user_id = rates.user_id
GROUP BY r1.user_id,
         r2.sday

这工作正常,但比我想要的慢。

我也使用了SUBSTRING_INDEX(GROUP_CONCAT...,但是这会发出警告,表示行正在被剪切,不幸的是我没有权限更改group_concat_max_len 的值(当前为 1024)。

有没有更有效的方法来做到这一点?

【问题讨论】:

  • 能否提供表索引?
  • 运行 SHOW INDEX FROM 汇率;显示 id、user_id 和 active 作为索引,id 为主键。

标签: mysql


【解决方案1】:

从添加这个索引开始:

ALTER TABLE `rates` ADD INDEX `rates_idx_id_id_at` (`id`, `user_id`, `created_at`);

此外,将 FROM 子句中的子查询提取到临时表,对它们进行索引然后加入应该比加入子查询快得多,在许多情况下是不可索引的。

以下内容应该可以帮助您创建临时表、索引它们,然后运行连接它们的查询:

-- Transformed subquery to a temp table to improve performance
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS SELECT
        rates.user_id,
        date_format(rates.created_at,
        '%Y-%m-%d') AS sday,
        MAX(rates.created_at) AS latest_record 
    FROM
        rates 
    GROUP BY
        rates.id,
        sday 
    ORDER BY
        NULL;

-- Transformed subquery to a temp table to improve performance
CREATE TEMPORARY TABLE IF NOT EXISTS temp2 AS SELECT
        * 
    FROM
        rates;

-- This index is required for optimal temp tables performance
ALTER TABLE
  `temp1`
ADD
  INDEX `temp1_idx_id` (`user_id`);

-- This index is required for optimal temp tables performance
ALTER TABLE
  `temp2`
ADD
  INDEX `temp2_idx_at_id_sday` (`created_at`, `user_id`, `sday`);

SELECT
        * 
    FROM
        temp1 r1 
    LEFT JOIN
        temp2 r2 
            ON r2.created_at = rates.latest_record 
            AND r2.user_id = rates.user_id 
    GROUP BY
        r1.user_id,
        r2.sday 
    ORDER BY
        NULL

【讨论】:

    【解决方案2】:
      select * from table group by created_at,rate_gbp order by created_at desc
    

    【讨论】:

    • 这不起作用 - 如果我将 max(created_at) 作为字段包含在内,则结果不匹配 - 即返回记录的 max(created_at) != created_at。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 2019-08-02
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多