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查询的控制语句图文详解
Apr 11 MySQL
详解GaussDB for MySQL性能优化
May 18 MySQL
Mysql文件存储图文详解
Jun 01 MySQL
MySQL 发生同步延迟时Seconds_Behind_Master还为0的原因
Jun 21 MySQL
mysql事务对效率的影响分析总结
Oct 24 MySQL
Mysql中一千万条数据怎么快速查询
Dec 06 MySQL
Mysql忘记密码解决方法
Feb 12 MySQL
MySQL派生表联表查询实战过程
Mar 20 MySQL
CentOS MySql8 远程连接实战
Apr 19 MySQL
MySql如何将查询的出来的字段进行转换
Jun 14 MySQL
MySQL实现字段分割一行转多行的示例代码
Jul 07 MySQL
Mysql中mvcc各场景理解应用
Aug 05 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
php合并js请求的例子
2013/11/01 PHP
30个php操作redis常用方法代码例子
2014/07/05 PHP
Laravel学习教程之路由模块
2017/08/18 PHP
PHP模糊查询技术实例分析【附源码下载】
2019/03/07 PHP
动态刷新 dorado树的js代码
2009/06/12 Javascript
js中更短的 Array 类型转换
2011/10/30 Javascript
javascript学习(一)构建自己的JS库
2013/01/02 Javascript
在百度知道团队中快速审批新成员的js脚本
2014/02/02 Javascript
react性能优化达到最大化的方法 immutable.js使用的必要性
2017/03/09 Javascript
ionic实现底部分享功能
2017/05/11 Javascript
JS点击缩略图整屏居中放大图片效果
2017/07/04 Javascript
vue 双向数据绑定的实现学习之监听器的实现方法
2018/11/30 Javascript
JavaScript学习笔记之DOM基础操作实例小结
2019/01/09 Javascript
JavaScript 闭包的使用场景
2020/09/17 Javascript
用Python制作检测Linux运行信息的工具的教程
2015/04/01 Python
用yum安装MySQLdb模块的步骤方法
2016/12/15 Python
python使用生成器实现可迭代对象
2018/03/20 Python
详解python pandas 分组统计的方法
2019/07/30 Python
PyCharm使用Docker镜像搭建Python开发环境
2019/12/26 Python
tensorflow之自定义神经网络层实例
2020/02/07 Python
Python unittest生成测试报告过程解析
2020/09/08 Python
Python如何实现机器人聊天
2020/09/10 Python
HTML5自定义mp3播放器源码
2020/01/06 HTML / CSS
柒牌官方商城:中国男装优秀品牌
2017/06/30 全球购物
Internal修饰符有什么含义
2013/07/10 面试题
javascript实现用户必须勾选协议实例讲解
2021/03/24 Javascript
如何填写个人简历自我评价
2013/12/10 职场文书
九年级物理教学反思
2014/01/29 职场文书
项目投资意向书
2014/04/01 职场文书
父亲去世追悼词
2015/06/23 职场文书
医护人员继续教育学习心得体会
2016/01/19 职场文书
Python爬虫之爬取哔哩哔哩热门视频排行榜
2021/04/28 Python
python面向对象版学生信息管理系统
2021/06/24 Python
Lakehouse数据湖并发控制陷阱分析
2022/03/31 Oracle
Windows Server 2019 域控制器安装图文教程
2022/04/28 Servers
win10识别不了U盘怎么办 win10系统读取U盘失败的解决办法
2022/08/05 数码科技