将MySQL去重操作优化到极致之三弹连发:巧用索引与变量

Posted wzy0623

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将MySQL去重操作优化到极致之三弹连发:巧用索引与变量相关的知识,希望对你有一定的参考价值。

        元旦假期收到阿里吴老师来电,被告知已将mysql查重SQL优化到极致:100万原始数据,其中50万重复,把去重后的50万数据写入目标表只需要9秒钟。这是一个惊人的数字,要知道仅是insert 50万条记录也需要些时间的。于是来了兴趣,自己实验、思考、总结做了一遍。

一、问题提出
        源表t_source结构如下:
item_id int,
created_time datetime,
modified_time datetime,
item_name varchar(20),
other varchar(20)

1. 源表中有100万条数据,其中有50万created_time和item_name重复。
2. 要把去重后的50万数据写入到目标表。
3. 重复created_time和item_name的多条数据,可以保留任意一条,不做规则限制。

二、实验环境
        Linux虚机:CentOS release 6.4;8G内存;100G机械硬盘;双物理CPU双核,共四个处理器;MySQL 5.6.14。

三、建立测试表和数据
1. 建立源表
create table t_source  
(  
item_id int,  
created_time datetime,  
modified_time datetime,  
item_name varchar(20),  
other varchar(20)  
);  

2. 建立目标表

create table t_target like t_source; 

3. 生成100万测试数据,其中有50万created_time和item_name重复

delimiter //      
create procedure sp_generate_data()    
begin     
    set @i := 1;   
    
    while @i<=500000 do  
        set @created_time := date_add('2017-01-01',interval @i second);  
        set @modified_time := @created_time;  
        set @item_name := concat('a',@i);  
        insert into t_source  
        values (@i,@created_time,@modified_time,@item_name,'other');  
        set @i:=@i+1;    
    end while;  
    commit;    
    
    set @last_insert_id := 500000;  
    insert into t_source  
    select item_id + @last_insert_id,  
           created_time,  
           date_add(modified_time,interval @last_insert_id second),  
           item_name,  
           'other'   
      from t_source;  
    commit;
end     
//      
delimiter ;     
    
call sp_generate_data();  

        源表没有主键或唯一性约束,有可能存在两条完全一样的数据,所以再插入一条记录模拟这种情况。

insert into t_source  
select * from t_source where item_id=1;  
commit;  

        查询总记录数和去重后的记录数图一所示。

select count(*),count(distinct created_time,item_name) from t_source;