postgresql如何找到表中重复数据的行并删除


Posted in MySQL onMay 08, 2023

postgresql找到表中重复数据的行并删除

创建测试表并插入数据

create table aaa(id bigserial,col1 varchar(255));
insert into aaa values(1,'b'),(2,'a'),(3,'b'),(4,'c');
select * from aaa;

找到重复行并删除

方法1:ctid表示数据行在它所处的表内的物理位置,ctid由两个数字组成,第一个数字表示物理块号,第二个数字表示在物理块中的行号。

select * from aaa where ctid not in(select max(ctid) from aaa group by col1);

删除重复行

delete from aaa where ctid not in(select max(ctid) from aaa group by col1);

方法2:利用exists

找到重复行

select * from aaa t1 where  exists (select 1 from aaa t2 where t1.col1=t2.col1 and t1.id<t2.id )----exists后的意思是同一列相等,但是自增id不相等且id小的那一个

删除重复行

delete from aaa t1 where  exists (select 1 from aaa t2 where t1.col1=t2.col1 and t1.id<t2.id )

postgresql常用的删除重复数据方法

最高效方法

测试环境验证,6600万行大表,删除2200万重复数据仅需3分钟

delete from deltest a where a.ctid = any(array (select ctid from (select row_number() over (partition by id), ctid from deltest) t where t.row_number > 1));

PG中三种删除重复数据方法

首先创建一张基础表,并插入一定量的重复数据。

create table deltest(id int, name varchar(255));
create table deltest_bk (like deltest);
insert into deltest select generate_series(1, 10000), 'ZhangSan';
insert into deltest select generate_series(1, 10000), 'ZhangSan';
insert into deltest_bk select * from deltest;

1. 常规删除方法

最容易想到的方法就是判断数据是否重复,对于重复的数据只保留ctid最小(或最大)的数据,删除其他的。

explain analyse delete from deltest a where a.ctid <> (select min(t.ctid) from deltest t where a.id=t.id);
-------------------------------------------------------------------------------------------
    Delete on deltest a  (cost=0.00..195616.30 rows=1518 width=6) (actual time=67758.866..67758.866 rows=0 loops=1)
       ->  Seq Scan on deltest a  (cost=0.00..195616.30 rows=1518 width=6) (actual time=32896.517..67663.228 rows=10000 loops=1)
         Filter: (ctid <> (SubPlan 1))
         Rows Removed by Filter: 10000
         SubPlan 1
           ->  Aggregate  (cost=128.10..128.10 rows=1 width=6) (actual time=3.374..3.374 rows=1 loops=20000)
                 ->  Seq Scan on deltest t  (cost=0.00..128.07 rows=8 width=6) (actual time=0.831..3.344 rows=2 loops=20000)
                       Filter: (a.id = id)
                       Rows Removed by Filter: 19998
Total runtime: 67758.931 ms
select count(*) from deltest;
count
-------
10000

可以看到,id相同的数据,保留ctid最小的,其他的删除。相当于把deltest表中的数据删掉一半,耗时达到67s多。相当慢。

2. group by删除方法

group by方法通过分组找到ctid最小的数据,然后删除其他数据。

explain analyse delete from deltest a where a.ctid not in (select min(ctid) from deltest group by id);
-------------------------------------------------------------------------------------------
    Delete on deltest a  (cost=131.89..2930.46 rows=763 width=6) (actual time=30942.496..30942.496 rows=0 loops=1)
       ->  Seq Scan on deltest a  (cost=131.89..2930.46 rows=763 width=6) (actual time=10186.296..30814.366 rows=10000 loops=1)
         Filter: (NOT (SubPlan 1))
         Rows Removed by Filter: 10000
         SubPlan 1
           ->  Materialize  (cost=131.89..134.89 rows=200 width=10) (actual time=0.001..0.471 rows=7500 loops=20000)
                 ->  HashAggregate  (cost=131.89..133.89 rows=200 width=10) (actual time=10.568..13.584 rows=10000 loops=1)
                       ->  Seq Scan on deltest  (cost=0.00..124.26 rows=1526 width=10) (actual time=0.006..3.829 rows=20000 loops=1)
     Total runtime: 30942.819 ms
select count(*) from deltest;
count
-------
10000

可以看到同样是删除一半的数据,使用group by的方式,时间节省了一半。但仍含需要30s,下面试一下第三种删除操作。

3. 高效删除方法

explain analyze delete from deltest a where a.ctid = any(array (select ctid from (select row_number() over (partition by id), ctid from deltest) t where t.row_number > 1));
-----------------------------------------------------------------------------------------
    Delete on deltest a  (cost=250.74..270.84 rows=10 width=6) (actual time=98.363..98.363 rows=0 loops=1)
    InitPlan 1 (returns 0)−>SubqueryScanont(cost=204.95..250.73rows=509width=6)(actualtime=29.446..47.867rows=10000loops=1)Filter:(t.rownumber>1)RowsRemovedbyFilter:10000−>WindowAgg(cost=204.95..231.66rows=1526width=10)(actualtime=29.436..44.790rows=20000loops=1)−>Sort(cost=204.95..208.77rows=1526width=10)(actualtime=12.466..13.754rows=20000loops=1)SortKey:deltest.idSortMethod:quicksortMemory:1294kB−>SeqScanondeltest(cost=0.00..124.26rows=1526width=10)(actualtime=0.021..5.110rows=20000loops=1)−>TidScanondeltesta(cost=0.01..20.11rows=10width=6)(actualtime=82.983..88.751rows=10000loops=1)TIDCond:(ctid=ANY(0)−>SubqueryScanont(cost=204.95..250.73rows=509width=6)(actualtime=29.446..47.867rows=10000loops=1)Filter:(t.rownumber>1)RowsRemovedbyFilter:10000−>WindowAgg(cost=204.95..231.66rows=1526width=10)(actualtime=29.436..44.790rows=20000loops=1)−>Sort(cost=204.95..208.77rows=1526width=10)(actualtime=12.466..13.754rows=20000loops=1)SortKey:deltest.idSortMethod:quicksortMemory:1294kB−>SeqScanondeltest(cost=0.00..124.26rows=1526width=10)(actualtime=0.021..5.110rows=20000loops=1)−>TidScanondeltesta(cost=0.01..20.11rows=10width=6)(actualtime=82.983..88.751rows=10000loops=1)TIDCond:(ctid=ANY(0))
    Total runtime: 98.912 ms
select count(*) from deltest;
count
-------
10000

可以看到,居然只要98ms

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

MySQL 相关文章推荐
mysql的MVCC多版本并发控制的实现
Apr 14 MySQL
MySQL8.0.24版本Release Note的一些改进点
Apr 22 MySQL
MySQL EXPLAIN输出列的详细解释
May 12 MySQL
MySQL系列之十三 MySQL的复制
Jul 02 MySQL
MySQL深度分页(千万级数据量如何快速分页)
Jul 25 MySQL
mysql 索引合并的使用
Aug 30 MySQL
mysql配置SSL证书登录的实现
Sep 04 MySQL
MySQL into_Mysql中replace与replace into用法案例详解
Sep 14 MySQL
MySQL修炼之联结与集合浅析
Oct 05 MySQL
分析MySQL优化 index merge 后引起的死锁
Apr 19 MySQL
Mysql表数据比较大情况下修改添加字段的方法实例
Jun 28 MySQL
SQL Server数据库的三种创建方法汇总
May 08 #MySQL
SQL中去除重复数据的几种方法汇总(窗口函数对数据去重)
May 08 #MySQL
MySQL中TIMESTAMP类型返回日期时间数据中带有T的解决
Dec 24 #MySQL
MySQL实现用逗号进行拼接、以逗号进行分割
Dec 24 #MySQL
MySQL数据管理操作示例讲解
Dec 24 #MySQL
MySQL深分页问题解决思路
Dec 24 #MySQL
DQL数据查询语句使用示例
Dec 24 #MySQL
You might like
日本收入最高的漫画家:海贼王作者版税年收入高达8.45亿元
2020/03/04 日漫
php中引用符号(&amp;)的使用详解
2013/11/13 PHP
php实现memcache缓存示例讲解
2013/12/04 PHP
PHP判断一个字符串是否是回文字符串的方法
2015/03/23 PHP
PHP传值到不同页面的三种常见方式及php和html之间传值问题
2015/11/19 PHP
基于jquery实现日历签到功能
2020/09/11 Javascript
使用JavaScript判断手机浏览器是横屏还是竖屏问题
2016/08/02 Javascript
浅谈jQuery中事情的动态绑定
2017/02/12 Javascript
关于Javascript中document.cookie的使用
2017/03/08 Javascript
ES6教程之for循环和Map,Set用法分析
2017/04/10 Javascript
jQuery使用ajax_动力节点Java学院整理
2017/07/05 jQuery
VueJs单页应用实现微信网页授权及微信分享功能示例
2017/07/26 Javascript
BootStrap Fileinput上传插件使用实例代码
2017/07/28 Javascript
node(koa2) web应用模块介绍详解
2019/03/29 Javascript
如何使用Node.js爬取任意网页资源并输出PDF文件到本地
2019/06/17 Javascript
ES6 Object属性新的写法实例小结
2019/06/25 Javascript
简单了解微信小程序的目录结构
2019/07/01 Javascript
ES6学习笔记之字符串、数组、对象、函数新增知识点实例分析
2020/01/22 Javascript
[49:13]DOTA2上海特级锦标赛C组资格赛#1 OG VS LGD第一局
2016/02/27 DOTA
python切换hosts文件代码示例
2013/12/31 Python
python简单获取本机计算机名和IP地址的方法
2015/06/03 Python
Python3连接SQLServer、Oracle、MySql的方法
2018/06/28 Python
python 判断文件还是文件夹的简单实例
2019/06/10 Python
Django 源码WSGI剖析过程详解
2019/08/05 Python
基于pytorch 预训练的词向量用法详解
2020/01/06 Python
python global和nonlocal用法解析
2020/02/03 Python
Idea安装python显示无SDK问题解决方案
2020/08/12 Python
美国狗旅行和户外用品领先供应商:kurgo
2020/08/18 全球购物
护理自荐信范文
2013/10/05 职场文书
求职信结尾怎么写
2014/05/26 职场文书
收款委托书范本
2014/09/11 职场文书
民主生活会对照检查材料(统计局)
2014/09/21 职场文书
2014年初级职称工作总结
2014/12/08 职场文书
罚站检讨书
2015/01/29 职场文书
Python爬虫实战之爬取携程评论
2021/06/02 Python
SQL Server携程核心系统无感迁移到MySQL实战
2022/06/01 SQL Server