› MySQL 5.5 Community Server
› MySQL 5.6 Community Server
› Percona Configuration Wizard
› XtraBackup 搭建主从复制
Great Sites on MySQL
› Percona
› MySQL Performance Blog
› Severalnines
推荐管理工具
› Sequel Pro
› phpMyAdmin
推荐书目
› MySQL Cookbook
MySQL 相关项目
› MariaDB
› Drizzle
参考文档
› http://mysql-python.sourceforge.net/MySQLdb.html
Nick2VIPUser
V2EX  ›  MySQL

[mysql 去重问题] 如何高效的删除数据表中的重复数据?

  •  
  •   Nick2VIPUser ·
    nickliqian · Feb 26, 2018 · 12301 views
    This topic created in 3139 days ago, the information mentioned may be changed or developed.

    有一个数据表,共三个字段:id,data,datetime。

    其中 data 是不能重复的,但是由于粗心在最开始的时候忘记给data字段设置了unique约束。 在插入数据的过程中造成了大量重复。

    目前: 数据总量(count(* ))是 50W,不重复数据量 (distinct(data) ) 35W。

    现在的需求是把重复的数据删除掉且只保留其中一条。

    使用如下语句进行去重(网络上找的):

    delete from bj where data_info in
     (select data_info from
     ( select data_info from bj group by data_info having count(data_info)>1) a) 
    and id not in 
    ( select min(id) from 
    (select min(id) as id from bj group by data_info having count(data_info)>1 ) b)
    

    先测试了总量为 1000 的数据,功能是 OK 的。

    然后在单核 2G 的云主机上对 50W 总量的数据跑这个 sql,跑了超过 1 个小时还没有出结果。

    求问有什么高效的方法可以替代这个方法呢?

    在此感谢各位老哥。

    Supplement 1  ·  Feb 26, 2018

    感谢各位的答案! 综合 3L @l00t 和 8L @Immortal 的答案,解决了问题。

    1. 先建立一个同样字段的新表newtable,给指定data字段设置好unique约束
    2. 使用如下sql语句将旧表的数据全部INSERT转移到新表,由于使用了IGNORE选项这样遇到重复数据会忽略,直到将所有数据插入完成
    INSERT IGNORE INTO newtable SELECT * FROM oldtable;
    

    再次感谢各位的答案!

    Supplement 2  ·  Feb 26, 2018

    补充:以上方法使用innodb引擎3分钟30秒完成数据插入和去重,暂没有测试MyISAM引擎。

    26 replies  •  2020-01-10 18:00:34 +08:00
    blueorange
        1
    blueorange  
       Feb 26, 2018   ❤️ 1
    执行 sql 之前 加索引呢? 尝试了没有?
    Nick2VIPUser
        2
    Nick2VIPUser  
    OP
       Feb 26, 2018
    @blueorange 有加索引的
    l00t
        3
    l00t  
       Feb 26, 2018   ❤️ 1
    建个新表插一遍不重的数据,然后把老表 drop 掉,再把新表名字改成老表的。
    nosay
        4
    nosay  
       Feb 26, 2018   ❤️ 1
    3L + 1
    st157285231
        5
    st157285231  
       Feb 26, 2018   ❤️ 1
    取出全部数据,然后做去重处理,筛选出重复 ID,然后 delete from xx where id in 1,2,3
    justfindu
        6
    justfindu  
       Feb 26, 2018   ❤️ 1
    delete * from table where table_id not in ( select table_id from table group by data) ?
    哦 我不知道效率如何 哈哈哈, in 效率估计会爆炸, mysql5.7 下会快很多..

    最快 3L
    jsnjfz
        7
    jsnjfz  
       Feb 26, 2018   ❤️ 1
    Immortal
        8
    Immortal  
       Feb 26, 2018   ❤️ 1
    之前看<高性能 mysql>这书的时候貌似看到过一样的情况
    alter ignore table 表名 add unique index(列名);
    Nick2VIPUser
        10
    Nick2VIPUser  
    OP
       Feb 26, 2018
    @l00t
    @nosay
    @st157285231
    @justfindu
    @jsnjfz
    @Immortal
    感谢各位,综合几种答案已经将问题解决!
    SbloodyS
        11
    SbloodyS  
       Feb 26, 2018
    一般慢的话可以对相应字段加索引,子查询中不要嵌套子查询 SQL 效率比较高
    问题的删除 SQL 用这个会效率比较高
    DELETE
    FROM
    bj
    WHERE
    id NOT IN (
    SELECT
    min(id)
    FROM
    bj
    GROUP BY
    data
    );
    lihongjie0209
        12
    lihongjie0209  
       Feb 26, 2018
    @SbloodyS #11 和我之前的做法一样
    SbloodyS
        13
    SbloodyS  
       Feb 26, 2018
    @lihongjie0209 哈哈,我之前就是这么做的
    Nick2VIPUser
        14
    Nick2VIPUser  
    OP
       Feb 27, 2018
    @SbloodyS @lihongjie0209 谢谢!刚刚试了一下,在 5.7.17 版本 mysql 下会报错:
    ```
    mysql> DELETE FROM bj WHERE id NOT IN (SELECT min(id) FROM bj GROUP BY data_info);
    ERROR 1093 (HY000): You can't specify target table 'bj' for update in FROM clause
    ```
    貌似这个版本不支持这么做-_-
    lihongjie0209
        15
    lihongjie0209  
       Feb 27, 2018   ❤️ 2
    @Nick2VIPUser

    DELETE
    FROM
    signin
    WHERE
    signin.id NOT IN (
    SELECT
    *
    FROM
    (
    SELECT
    MAX(id)
    FROM
    signin
    GROUP BY
    signin.student_id,
    signin.question_id
    ) AS t
    )

    按照这个改一下, 这是我之前用的
    annielong
        16
    annielong  
       Feb 27, 2018
    关键是怎么定义重复的数据才麻烦,我目前就遇到四个字段都一样才是重复
    SbloodyS
        17
    SbloodyS  
       Feb 27, 2018   ❤️ 1
    @Nick2VIPUser 噢,忘记了,Mysql 不支持 Delete 中 Select,我这个使用在 PG 里的 0.0......那可以先执行 select 然后把 ID 复制出来手动填入 Delete 的 In 中 23333
    Arthur001
        18
    Arthur001  
       Feb 27, 2018
    5.7 以后就不支持 alter ignore table 表名 add unique index(列名); 这样的语法了

    ![WL#7395: Deprecate (5.6) and remove (5.7) IGNORE for ALTER TABLE]( https://dev.mysql.com/worklog/task/?id=7395)
    Arthur001
        19
    Arthur001  
       Feb 27, 2018
    我能转载一下吗
    zhangyp123
        20
    zhangyp123  
       Feb 27, 2018   ❤️ 1
    刚验证了一下,alter ignore table 表名 add unique index(列名); 5.6 是可行的,5.7 就不支持了
    Nick2VIPUser
        21
    Nick2VIPUser  
    OP
       Feb 28, 2018
    @lihongjie0209 谢谢您帮我找出来,我试一下!
    Nick2VIPUser
        22
    Nick2VIPUser  
    OP
       Feb 28, 2018
    @Arthur001 对,我在 stackoverflow 也看到了这个。可以转载的~
    Nick2VIPUser
        23
    Nick2VIPUser  
    OP
       Feb 28, 2018
    @zhangyp123
    @SbloodyS
    谢谢各位!
    Nick2VIPUser
        24
    Nick2VIPUser  
    OP
       Feb 28, 2018
    @annielong 我遇到的需求是只有一个字段重复-_-,mysql 也许可以把四个字段结合起来整理成一个 hash 值然后通过 hash 值判断?
    xjroot
        25
    xjroot  
       Oct 1, 2018
    已收藏,好帖
    chaodada
        26
    chaodada  
       Jan 10, 2020
    @lihongjie0209 #15 感谢楼主 参考您的语句解决了我的问题
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   828 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 19:20 · PVG 03:20 · LAX 12:20 · JFK 15:20
    ♥ Do have faith in what you're doing.