【问题标题】:MySQL select max record from each group and insert into another tableMySQL从每个组中选择最大记录并插入另一个表
【发布时间】:2017-05-15 13:21:45
【问题描述】:

表A有4列,id、name、create_time和content。

create table A
(
    id int primary key,
    name varchar(20),
    create_time datetime,
    content varchar(4000)
);
create table B like A;

我想在同一个name 中选择最大create_time 记录,并插入另一个表B

如下执行sql,但耗时不可接受。

insert into B
select A.*
from A,
    (select name, max(create_time) create_time from B group by name) tmp
where A.name = tmp.name
  and A.create_time = tmp.create_time;

一张表1000W行10GB,执行sql耗时200s。

有什么方法可以更快地完成这项工作,或者更改 MySQL Server 中的哪些参数以更快地运行。

p: 表 A 可以是任何类型、分区表或其他类型。

【问题讨论】:

  • 你的意思是“select name, max(create_time) create_time from A ...”?
  • 您想要表 B 中的所有记录,还是每个名称只有一个?在第一种情况下,您是否应该将 max() 命名为不同于 create_time 的名称以避免与 A 中已经存在的列发生冲突?还是不想保留原来的create_time?第二种情况(每个名字只有一条记录),内容和id应该是什么?您的问题中的一些示例数据和预期结果会有很大帮助。

标签: mysql database aggregate-functions greatest-n-per-group


【解决方案1】:

首先确保您在 A (name, create_time) 和 B (name, create_time) 上有正确的索引 然后尝试使用显式连接和条件

insert into B 
select A.* 
from A 
inner join ( 
    select name, max(create_time) create_time 
    from B 
    group by name) tmp on  ( A.name = tmp.name and A.create_time = tmp.create_time)

【讨论】:

    【解决方案2】:

    您需要的查询是:

    INSERT INTO B
    SELECT m.*
    FROM A m                                      # m from "max"
    LEFT JOIN A l                                 # l from "later"
        ON m.name = l.name                        # the same name
            AND m.create_time < l.create_time     # "l" was created later than "m"
    WHERE l.name IS NULL                          # there is no "later"
    

    工作原理:

    它将A 别名为m(来自“max”)与别名为l 的自身连接起来(来自“后来”而不是”最大”)。 LEFT JOIN 确保在没有WHERE 子句的情况下,来自m 的所有行都出现在结果集中。 m 中的每一行与 l 中具有相同 name (m.name = l.name) 并在 m (m.create_time &lt; l.create_time) 中的行之后创建的所有行组合在一起。 WHERE 条件仅将来自m 且在l 中没有任何匹配的行保留到结果集中(没有同名且创建时间更长的记录)。

    讨论

    如果A 中有多个行具有相同的namecreation_time,则查询将返回所有行。为了只保留其中一个,需要附加条件。

    添加:

    OR (m.create_time = l.create_time AND m.id < l.id)
    

    ON 子句(就在WHERE 之前)。调整/替换条件的m.id &lt; l.id 部分以满足您的需要(此版本支持表格中较早插入的行)。

    确保表 A 具有查询使用的列(namecreate_time)的索引。 否则与原始查询相比性能提升并不显着。

    【讨论】:

    • 表 A 有 name 和 create_time 索引,你的解决方案执行计划对我来说似乎差别不大。我该如何优化这个 sql。
    • 你跑了吗?需要多少时间才能完成?
    猜你喜欢
    • 2012-01-23
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多