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 Shell的介绍以及安装
Apr 24 MySQL
MySQL不使用order by实现排名的三种思路总结
Jun 02 MySQL
MySQL一些常用高级SQL语句
Jul 03 MySQL
使用ORM新增数据在Mysql中的操作步骤
Jul 26 MySQL
MySql子查询IN的执行和优化的实现
Aug 02 MySQL
MySQL中几种插入和批量语句实例详解
Sep 14 MySQL
MySQL分库分表详情
Sep 25 MySQL
Mysql数据库手动及定时备份步骤
Nov 07 MySQL
SQL优化老出错,那是你没弄明白MySQL解释计划用法
Nov 27 MySQL
一次SQL如何查重及去重的实战记录
Mar 13 MySQL
mysql中DCL常用的用户和权限控制
Mar 31 MySQL
Mysql索引失效 数据库表中有索引还是查询很慢
May 15 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
mysql中存储过程、函数的一些问题
2007/02/14 PHP
php 将excel导入mysql
2009/11/09 PHP
CentOS安装php v8js教程
2015/02/26 PHP
php array_walk 对数组中的每个元素应用用户自定义函数详解
2016/11/18 PHP
javascript multibox 全选
2009/03/22 Javascript
jQuery对val和atrr(&quot;value&quot;)赋值的区别介绍
2014/09/26 Javascript
JavaScript 表单处理实现代码
2015/04/13 Javascript
在Node.js中使用Javascript Generators详解
2016/05/05 Javascript
Bootstrap警告(Alerts)的实现方法
2017/03/22 Javascript
webpack-dev-server自动更新页面方法
2018/02/22 Javascript
JavaScript中的E-mail 地址格式验证
2018/03/28 Javascript
在angular 6中使用 less 的实例代码
2018/05/13 Javascript
JavaScript Canvas实现验证码
2020/08/02 Javascript
用POSTMAN发送JSON格式的POST请求示例
2018/09/04 Javascript
JavaScript检测浏览器是否支持CSS变量代码实例
2020/04/03 Javascript
JavaScript组合模式---引入案例分析
2020/05/23 Javascript
[03:48]大碗DOTA
2019/07/25 DOTA
python验证码识别的实例详解
2016/09/09 Python
python 随机生成10位数密码的实现代码
2019/06/27 Python
详解python调用cmd命令三种方法
2019/07/08 Python
详细介绍pandas的DataFrame的append方法使用
2019/07/31 Python
python读写csv文件的方法
2019/08/13 Python
使用Python进行中文繁简转换的实现代码
2019/10/18 Python
Python reques接口测试框架实现代码
2020/07/28 Python
Pycharm自动添加文件头注释和函数注释参数的方法
2020/10/23 Python
全网最细 Python 格式化输出用法讲解(推荐)
2021/01/18 Python
HTML5中meta属性的使用方法
2016/02/29 HTML / CSS
html2canvas生成的图片偏移不完整的解决方法
2020/05/19 HTML / CSS
屈臣氏俄罗斯在线商店:Watsons俄罗斯
2020/08/03 全球购物
土建专业大学生自荐信范文
2014/04/09 职场文书
团队合作精神学习心得体会
2016/01/19 职场文书
2016天猫双十一广告语
2016/01/28 职场文书
2017元旦晚会开幕词
2016/03/03 职场文书
Oracle数据库中通用的函数实例详解
2022/03/25 Oracle
《艾尔登法环》1.03.3补丁上线 碎星伤害调整
2022/04/07 其他游戏
使用CSS实现音波加载效果
2023/05/07 HTML / CSS